sign-up-form.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import { useState } from 'react'
  2. import { z } from 'zod'
  3. import { useForm } from 'react-hook-form'
  4. import { zodResolver } from '@hookform/resolvers/zod'
  5. import { IconFacebook, IconGithub } from '@/assets/brand-icons'
  6. import { cn } from '@/lib/utils'
  7. import { Button } from '@/components/ui/button'
  8. import {
  9. Form,
  10. FormControl,
  11. FormField,
  12. FormItem,
  13. FormLabel,
  14. FormMessage,
  15. } from '@/components/ui/form'
  16. import { Input } from '@/components/ui/input'
  17. import { PasswordInput } from '@/components/password-input'
  18. const formSchema = z
  19. .object({
  20. email: z.email({
  21. error: (iss) =>
  22. iss.input === '' ? 'Please enter your email' : undefined,
  23. }),
  24. password: z
  25. .string()
  26. .min(1, 'Please enter your password')
  27. .min(7, 'Password must be at least 7 characters long'),
  28. confirmPassword: z.string().min(1, 'Please confirm your password'),
  29. })
  30. .refine((data) => data.password === data.confirmPassword, {
  31. message: "Passwords don't match.",
  32. path: ['confirmPassword'],
  33. })
  34. export function SignUpForm({
  35. className,
  36. ...props
  37. }: React.HTMLAttributes<HTMLFormElement>) {
  38. const [isLoading, setIsLoading] = useState(false)
  39. const form = useForm<z.infer<typeof formSchema>>({
  40. resolver: zodResolver(formSchema),
  41. defaultValues: {
  42. email: '',
  43. password: '',
  44. confirmPassword: '',
  45. },
  46. })
  47. function onSubmit(data: z.infer<typeof formSchema>) {
  48. setIsLoading(true)
  49. // eslint-disable-next-line no-console
  50. console.log(data)
  51. setTimeout(() => {
  52. setIsLoading(false)
  53. }, 3000)
  54. }
  55. return (
  56. <Form {...form}>
  57. <form
  58. onSubmit={form.handleSubmit(onSubmit)}
  59. className={cn('grid gap-3', className)}
  60. {...props}
  61. >
  62. <FormField
  63. control={form.control}
  64. name='email'
  65. render={({ field }) => (
  66. <FormItem>
  67. <FormLabel>Email</FormLabel>
  68. <FormControl>
  69. <Input placeholder='name@example.com' {...field} />
  70. </FormControl>
  71. <FormMessage />
  72. </FormItem>
  73. )}
  74. />
  75. <FormField
  76. control={form.control}
  77. name='password'
  78. render={({ field }) => (
  79. <FormItem>
  80. <FormLabel>Password</FormLabel>
  81. <FormControl>
  82. <PasswordInput placeholder='********' {...field} />
  83. </FormControl>
  84. <FormMessage />
  85. </FormItem>
  86. )}
  87. />
  88. <FormField
  89. control={form.control}
  90. name='confirmPassword'
  91. render={({ field }) => (
  92. <FormItem>
  93. <FormLabel>Confirm Password</FormLabel>
  94. <FormControl>
  95. <PasswordInput placeholder='********' {...field} />
  96. </FormControl>
  97. <FormMessage />
  98. </FormItem>
  99. )}
  100. />
  101. <Button className='mt-2' disabled={isLoading}>
  102. Create Account
  103. </Button>
  104. <div className='relative my-2'>
  105. <div className='absolute inset-0 flex items-center'>
  106. <span className='w-full border-t' />
  107. </div>
  108. <div className='relative flex justify-center text-xs uppercase'>
  109. <span className='bg-background text-muted-foreground px-2'>
  110. Or continue with
  111. </span>
  112. </div>
  113. </div>
  114. <div className='grid grid-cols-2 gap-2'>
  115. <Button
  116. variant='outline'
  117. className='w-full'
  118. type='button'
  119. disabled={isLoading}
  120. >
  121. <IconGithub className='h-4 w-4' /> GitHub
  122. </Button>
  123. <Button
  124. variant='outline'
  125. className='w-full'
  126. type='button'
  127. disabled={isLoading}
  128. >
  129. <IconFacebook className='h-4 w-4' /> Facebook
  130. </Button>
  131. </div>
  132. </form>
  133. </Form>
  134. )
  135. }