| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- import { useState } from 'react'
- import { z } from 'zod'
- import { useForm } from 'react-hook-form'
- import { zodResolver } from '@hookform/resolvers/zod'
- import { Loader2, UserPlus } from 'lucide-react'
- import { toast } from 'sonner'
- import { IconFacebook, IconGithub } from '@/assets/brand-icons'
- import { sleep, cn } from '@/lib/utils'
- import { Button } from '@/components/ui/button'
- import {
- Form,
- FormControl,
- FormField,
- FormItem,
- FormLabel,
- FormMessage,
- } from '@/components/ui/form'
- import { Input } from '@/components/ui/input'
- import { PasswordInput } from '@/components/password-input'
- const formSchema = z
- .object({
- email: z.email({
- error: (iss) =>
- iss.input === '' ? 'Please enter your email.' : undefined,
- }),
- password: z
- .string()
- .min(1, 'Please enter your password.')
- .min(7, 'Password must be at least 7 characters long.'),
- confirmPassword: z.string().min(1, 'Please confirm your password.'),
- })
- .refine((data) => data.password === data.confirmPassword, {
- message: "Passwords don't match.",
- path: ['confirmPassword'],
- })
- export function SignUpForm({
- className,
- ...props
- }: React.HTMLAttributes<HTMLFormElement>) {
- const [isLoading, setIsLoading] = useState(false)
- const form = useForm<z.infer<typeof formSchema>>({
- resolver: zodResolver(formSchema),
- defaultValues: {
- email: '',
- password: '',
- confirmPassword: '',
- },
- })
- function onSubmit(data: z.infer<typeof formSchema>) {
- setIsLoading(true)
- toast.promise(sleep(2000), {
- loading: 'Creating account...',
- success: () => {
- setIsLoading(false)
- return `Account created for ${data.email}.`
- },
- error: 'Error',
- })
- }
- return (
- <Form {...form}>
- <form
- onSubmit={form.handleSubmit(onSubmit)}
- className={cn('grid gap-3', className)}
- {...props}
- >
- <FormField
- control={form.control}
- name='email'
- render={({ field }) => (
- <FormItem>
- <FormLabel>Email</FormLabel>
- <FormControl>
- <Input placeholder='name@example.com' {...field} />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
- <FormField
- control={form.control}
- name='password'
- render={({ field }) => (
- <FormItem>
- <FormLabel>Password</FormLabel>
- <FormControl>
- <PasswordInput placeholder='********' {...field} />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
- <FormField
- control={form.control}
- name='confirmPassword'
- render={({ field }) => (
- <FormItem>
- <FormLabel>Confirm Password</FormLabel>
- <FormControl>
- <PasswordInput placeholder='********' {...field} />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
- <Button className='mt-2' disabled={isLoading}>
- {isLoading ? <Loader2 className='animate-spin' /> : <UserPlus />}
- Create Account
- </Button>
- <div className='relative my-2'>
- <div className='absolute inset-0 flex items-center'>
- <span className='w-full border-t' />
- </div>
- <div className='relative flex justify-center text-xs uppercase'>
- <span className='bg-background px-2 text-muted-foreground'>
- Or continue with
- </span>
- </div>
- </div>
- <div className='grid grid-cols-2 gap-2'>
- <Button
- variant='outline'
- className='w-full'
- type='button'
- disabled={isLoading}
- >
- <IconGithub className='h-4 w-4' /> GitHub
- </Button>
- <Button
- variant='outline'
- className='w-full'
- type='button'
- disabled={isLoading}
- >
- <IconFacebook className='h-4 w-4' /> Facebook
- </Button>
- </div>
- </form>
- </Form>
- )
- }
|