sign-up-form.tsx 4.4 KB

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