| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- import { z } from 'zod'
- import { format } from 'date-fns'
- import { useForm } from 'react-hook-form'
- import { CalendarIcon, CaretSortIcon, CheckIcon } from '@radix-ui/react-icons'
- import { zodResolver } from '@hookform/resolvers/zod'
- import { cn } from '@/lib/utils'
- import { toast } from '@/hooks/use-toast'
- import { Calendar } from '@/components/ui/calendar'
- import {
- Command,
- CommandEmpty,
- CommandGroup,
- CommandInput,
- CommandItem,
- CommandList,
- } from '@/components/ui/command'
- import {
- Form,
- FormControl,
- FormDescription,
- FormField,
- FormItem,
- FormLabel,
- FormMessage,
- } from '@/components/ui/form'
- import { Input } from '@/components/ui/input'
- import {
- Popover,
- PopoverContent,
- PopoverTrigger,
- } from '@/components/ui/popover'
- import { Button } from '@/components/button'
- const languages = [
- { label: 'English', value: 'en' },
- { label: 'French', value: 'fr' },
- { label: 'German', value: 'de' },
- { label: 'Spanish', value: 'es' },
- { label: 'Portuguese', value: 'pt' },
- { label: 'Russian', value: 'ru' },
- { label: 'Japanese', value: 'ja' },
- { label: 'Korean', value: 'ko' },
- { label: 'Chinese', value: 'zh' },
- ] as const
- const accountFormSchema = z.object({
- name: z
- .string()
- .min(2, {
- message: 'Name must be at least 2 characters.',
- })
- .max(30, {
- message: 'Name must not be longer than 30 characters.',
- }),
- dob: z.date({
- required_error: 'A date of birth is required.',
- }),
- language: z.string({
- required_error: 'Please select a language.',
- }),
- })
- type AccountFormValues = z.infer<typeof accountFormSchema>
- // This can come from your database or API.
- const defaultValues: Partial<AccountFormValues> = {
- // name: "Your name",
- // dob: new Date("2023-01-23"),
- }
- export function AccountForm() {
- const form = useForm<AccountFormValues>({
- resolver: zodResolver(accountFormSchema),
- defaultValues,
- })
- function onSubmit(data: AccountFormValues) {
- toast({
- title: 'You submitted the following values:',
- description: (
- <pre className='mt-2 w-[340px] rounded-md bg-slate-950 p-4'>
- <code className='text-white'>{JSON.stringify(data, null, 2)}</code>
- </pre>
- ),
- })
- }
- return (
- <Form {...form}>
- <form onSubmit={form.handleSubmit(onSubmit)} className='space-y-8'>
- <FormField
- control={form.control}
- name='name'
- render={({ field }) => (
- <FormItem>
- <FormLabel>Name</FormLabel>
- <FormControl>
- <Input placeholder='Your name' {...field} />
- </FormControl>
- <FormDescription>
- This is the name that will be displayed on your profile and in
- emails.
- </FormDescription>
- <FormMessage />
- </FormItem>
- )}
- />
- <FormField
- control={form.control}
- name='dob'
- render={({ field }) => (
- <FormItem className='flex flex-col'>
- <FormLabel>Date of birth</FormLabel>
- <Popover>
- <PopoverTrigger asChild>
- <FormControl>
- <Button
- variant={'outline'}
- className={cn(
- 'w-[240px] pl-3 text-left font-normal',
- !field.value && 'text-muted-foreground'
- )}
- >
- {field.value ? (
- format(field.value, 'MMM d, yyyy')
- ) : (
- <span>Pick a date</span>
- )}
- <CalendarIcon className='ml-auto h-4 w-4 opacity-50' />
- </Button>
- </FormControl>
- </PopoverTrigger>
- <PopoverContent className='w-auto p-0' align='start'>
- <Calendar
- mode='single'
- selected={field.value}
- onSelect={field.onChange}
- disabled={(date: Date) =>
- date > new Date() || date < new Date('1900-01-01')
- }
- initialFocus
- />
- </PopoverContent>
- </Popover>
- <FormDescription>
- Your date of birth is used to calculate your age.
- </FormDescription>
- <FormMessage />
- </FormItem>
- )}
- />
- <FormField
- control={form.control}
- name='language'
- render={({ field }) => (
- <FormItem className='flex flex-col'>
- <FormLabel>Language</FormLabel>
- <Popover>
- <PopoverTrigger asChild>
- <FormControl>
- <Button
- variant='outline'
- role='combobox'
- className={cn(
- 'w-[200px] justify-between',
- !field.value && 'text-muted-foreground'
- )}
- >
- {field.value
- ? languages.find(
- (language) => language.value === field.value
- )?.label
- : 'Select language'}
- <CaretSortIcon className='ml-2 h-4 w-4 shrink-0 opacity-50' />
- </Button>
- </FormControl>
- </PopoverTrigger>
- <PopoverContent className='w-[200px] p-0'>
- <Command>
- <CommandInput placeholder='Search language...' />
- <CommandEmpty>No language found.</CommandEmpty>
- <CommandGroup>
- <CommandList>
- {languages.map((language) => (
- <CommandItem
- value={language.label}
- key={language.value}
- onSelect={() => {
- form.setValue('language', language.value)
- }}
- >
- <CheckIcon
- className={cn(
- 'mr-2 h-4 w-4',
- language.value === field.value
- ? 'opacity-100'
- : 'opacity-0'
- )}
- />
- {language.label}
- </CommandItem>
- ))}
- </CommandList>
- </CommandGroup>
- </Command>
- </PopoverContent>
- </Popover>
- <FormDescription>
- This is the language that will be used in the dashboard.
- </FormDescription>
- <FormMessage />
- </FormItem>
- )}
- />
- <Button type='submit'>Update account</Button>
- </form>
- </Form>
- )
- }
|