Skip to content

Commit

Permalink
Merge pull request #103 from NikDoe/feature/housing-stays-page
Browse files Browse the repository at this point in the history
add another fields in create property form
  • Loading branch information
NikDoe authored Sep 22, 2024
2 parents 6def9dd + 2a15e87 commit 785d80a
Show file tree
Hide file tree
Showing 21 changed files with 422 additions and 180 deletions.
6 changes: 3 additions & 3 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import { Poppins } from 'next/font/google';
import './globals.css';

import Navbar from '@/components/navbar/Navbar';
Expand All @@ -9,7 +9,7 @@ import { Separator } from '@/components/ui/separator';
import { ClerkProvider } from '@clerk/nextjs';
import Providers from './providers';

const inter = Inter({ subsets: ['latin'] });
const poppins = Poppins({ subsets: ['latin'], weight: ['300', '400', '500', '600', '700'] });

export const metadata: Metadata = {
title: 'Livo',
Expand All @@ -24,7 +24,7 @@ export default function RootLayout({
return (
<ClerkProvider>
<html lang='en' suppressHydrationWarning>
<body className={`${inter.className} min-h-screen flex flex-col`}>
<body className={`${poppins.className} min-h-screen flex flex-col`}>
<Providers>
<Navbar />
<main className='container py-16 lg:py-20 flex-1'>
Expand Down
37 changes: 10 additions & 27 deletions app/stays/create-stay/page.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,32 @@
import { AccommodationBlock, DetailsBlock, FormHeader } from '@/components/create-stay-form';
import {
CategoriesInput,
FormContainer,
FormInput,
PriceInput,
ImageInput,
SubmitButton,
TextAreaInput
} from '@/components/form';
import { Button } from '@/components/ui/button';

import { createPropertyAction } from '@/utils/actions';

import Link from 'next/link';
import { createPropertyAction } from '@/utils/actions';;

function CreateProperty() {
return (
<section className='flex flex-col lg:flex-row gap-20'>
<div className='w-2/3'>
<div className='flex justify-between'>
<h1 className='text-3xl font-semibold mb-20'>
Объявление о жилье
</h1>
<Button asChild>
<Link href='/experiences/create-experience'>Организовать мероприятие</Link>
</Button>
</div>
<div className='w-full space-y-10 lg:w-2/3'>
<FormHeader />
<div className='space-y-20'>
<FormContainer action={createPropertyAction}>
<div className='grid md:grid-cols-2 gap-10 mb-10'>
<FormInput
name='name'
type='text'
label='Название (макс. 20 символов)'
defaultValue='Глэмпинг в Гомеле: Уютный домик в стиле Тосканы'
/>
<PriceInput />
<CategoriesInput />
</div>
<h3 className='text-base font-bold mb-10'>Загрузите фото</h3>
<ImageInput />
<DetailsBlock />
<TextAreaInput name='description' labelText='Описание (от 10 до 1000 слов)' />
<AccommodationBlock />
<SubmitButton text='Разместить предложение' className='mt-20' />
</FormContainer>
</div>
</div>

<div className='w-1/3'>
<h1 className='text-3xl'>Превью</h1>
<h1 className='text-2xl font-semibold'>Предпросмотр</h1>
</div>
</section>
);
Expand Down
21 changes: 21 additions & 0 deletions components/create-stay-form/AccommodationBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { accommodationList } from '@/utils/accommodation';
import { CounterInput } from '../form';

function AccommodationBlock() {
return (
<>
<h3 className='text-base font-bold mt-20 mb-10'>Информация о проживании</h3>
<div className='grid md:grid-cols-2 gap-10 mt-10'>
{accommodationList.map(({ name, labelText }) => (
<CounterInput
key={name}
name={name}
labelText={labelText}
/>
))}
</div>
</>
);
}

export default AccommodationBlock;
22 changes: 22 additions & 0 deletions components/create-stay-form/DetailsBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { CategoriesInput, CountriesInput, FormInput, PriceInput } from '../form';

function DetailsBlock() {
return (
<>
<h3 className='text-base font-bold mt-20 mb-10'>Детали о жилье</h3>
<div className='grid md:grid-cols-2 gap-10 my-10'>
<FormInput
name='name'
type='text'
label='Название (макс. 20 символов)'
defaultValue='Глэмпинг в Гомеле: Уютный домик в стиле Тосканы'
/>
<PriceInput />
<CategoriesInput />
<CountriesInput placeholder='Выберите страну' />
</div>
</>
);
}

export default DetailsBlock;
17 changes: 17 additions & 0 deletions components/create-stay-form/FormHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Link from 'next/link';
import { Button } from '../ui/button';

function FormHeader() {
return (
<div className='flex flex-col md:flex-row justify-between'>
<h1 className='mb-4 text-3xl font-semibold lg:mb-20'>
Объявление о жилье
</h1>
<Button asChild>
<Link href='/experiences/create-experience'>Организовать мероприятие</Link>
</Button>
</div>
);
}

export default FormHeader;
3 changes: 3 additions & 0 deletions components/create-stay-form/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { default as FormHeader } from './FormHeader';
export { default as DetailsBlock } from './DetailsBlock';
export { default as AccommodationBlock } from './AccommodationBlock';
9 changes: 4 additions & 5 deletions components/form/CategoriesInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,18 @@ import { Prisma } from '@prisma/client';

const name = Prisma.PropertyScalarFieldEnum.category;

function CategoriesInput({ defaultValue }: { defaultValue?: string }) {
function CategoriesInput() {
return (
<div>
<Label htmlFor={name}>
Категории
Категория
</Label>
<Select
defaultValue={defaultValue || categories[0].label}
name={name}
required
>
<SelectTrigger id={name} className='mt-2'>
<SelectValue />
<SelectTrigger id={name}>
<SelectValue placeholder='Выберите категорию' />
</SelectTrigger>
<SelectContent>
{categories.map((item) => {
Expand Down
41 changes: 41 additions & 0 deletions components/form/CounterInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Label } from '../ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select';

const DEFAULT_ARRAY_LENGTH = 4;

type CounterInputProps = {
name: string;
maxValue?: number;
labelText?: string;
placeholder?: string;
}

function CounterInput(props: CounterInputProps) {
const { maxValue, labelText, name, placeholder } = props;
const length = maxValue ? maxValue + 1 : DEFAULT_ARRAY_LENGTH + 1;

return (
<div>
<Label htmlFor={name}>
{labelText}
</Label>
<Select
name={name}
required
>
<SelectTrigger id={name}>
<SelectValue placeholder={placeholder || 0} />
</SelectTrigger>
<SelectContent>
{Array.from({ length }, (_, i) => (
<SelectItem key={i + 1} value={(i).toString()}>
{i}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
);
}

export default CounterInput;
46 changes: 46 additions & 0 deletions components/form/CountriesInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use client';

import { Label } from '@/components/ui/label';
import { formattedCountries, truncateCountryName } from '@/utils/countries';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { Prisma } from '@prisma/client';

const name = Prisma.PropertyScalarFieldEnum.country;

function CountriesInput({ placeholder }: { placeholder?: string }) {
return (
<div>
<Label htmlFor={name}>
Страна
</Label>
<Select
name={name}
required
>
<SelectTrigger id={name}>
<SelectValue placeholder={placeholder} />
</SelectTrigger>
<SelectContent>
{formattedCountries.map((item) => {
return (
<SelectItem
key={item.code}
value={item.code}
>
{truncateCountryName(item.name, 34)}
</SelectItem>
);
})}
</SelectContent>
</Select>
</div>
);
}

export default CountriesInput;
2 changes: 1 addition & 1 deletion components/form/FormInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function FormInput(props: FormInputProps) {

return (
<div>
<Label htmlFor={name} className='capitalize'>
<Label htmlFor={name}>
{label || name}
</Label>
<Input
Expand Down
28 changes: 19 additions & 9 deletions components/form/ImageInput.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
import { Input } from '../ui/input';
import { Label } from '../ui/label';

type ImageInputProps = {
labelText?: string;
}

const name = 'image';

function ImageInput() {
function ImageInput({ labelText }: ImageInputProps) {
return (
<Input
id={name}
name={name}
type='file'
required
accept='image/*'
className='max-w-xs my-2'
/>
<div>
<Label htmlFor={name}>
{labelText}
</Label>
<Input
id={name}
name={name}
type='file'
required
accept='image/*'
className='mt-0'
/>
</div>
);
}

Expand Down
2 changes: 1 addition & 1 deletion components/form/ImageInputContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const userIcon = (
);

const imageInputWithButton = (
<div className='flex items-center space-x-2'>
<div className='flex items-center space-x-2 mt-2'>
<ImageInput />
<SubmitButton size='sm' text='загрузить' />
</div>
Expand Down
35 changes: 35 additions & 0 deletions components/form/SelectCountryItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { CountryItem } from '@/utils/types';
import { SelectItem } from '../ui/select';
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from '../ui/tooltip';
import { truncateCountryName } from '@/utils/countries';

type SelectCountryItemProps = {
item: CountryItem
}

function SelectCountryItem({ item }: SelectCountryItemProps) {
const isLongCountryName = item.name.length > 20;

return (
<Tooltip>
<TooltipTrigger asChild>
<SelectItem value={item.code}>
{truncateCountryName(item.name)}
</SelectItem>
</TooltipTrigger>
{
isLongCountryName && (
<TooltipContent className='truncate'>
{item.name}
</TooltipContent>
)
}
</Tooltip>
);
}

export default SelectCountryItem;
4 changes: 3 additions & 1 deletion components/form/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ export { default as ImageInput } from './ImageInput';
export { default as ImageInputContainer } from './ImageInputContainer';
export { default as PriceInput } from './PriceInput';
export { default as CategoriesInput } from './CategoriesInput';
export { default as TextAreaInput } from './TextAreaInput';
export { default as TextAreaInput } from './TextAreaInput';
export { default as CountriesInput } from './CountriesInput';
export { default as CounterInput } from './CounterInput';
2 changes: 1 addition & 1 deletion components/ui/label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/lib/utils';

const labelVariants = cva(
'text-sm text-muted-foreground font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
'text-sm text-muted-foreground font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 uppercase'
);

const Label = React.forwardRef<
Expand Down
Loading

0 comments on commit 785d80a

Please sign in to comment.