234 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			234 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { useCallback, useState } from 'react'
 | |
| import { Link } from 'react-router-dom'
 | |
| import {
 | |
|   Button,
 | |
|   FormControl,
 | |
|   FormErrorMessage,
 | |
|   Input,
 | |
|   Link as ChakraLink,
 | |
|   Heading,
 | |
| } from '@chakra-ui/react'
 | |
| import {
 | |
|   Field,
 | |
|   FieldAttributes,
 | |
|   FieldProps,
 | |
|   Form,
 | |
|   Formik,
 | |
|   FormikHelpers,
 | |
| } from 'formik'
 | |
| import * as Yup from 'yup'
 | |
| import cx from 'classnames'
 | |
| import { Helmet } from 'react-helmet-async'
 | |
| import AccountAPI from '@/client/idp/account'
 | |
| import Logo from '@/components/common/logo'
 | |
| import LayoutFull from '@/components/layout/layout-full'
 | |
| 
 | |
| type FormValues = {
 | |
|   fullName: string
 | |
|   email: string
 | |
|   password: string
 | |
|   passwordConfirmation: string
 | |
| }
 | |
| 
 | |
| const SignUpPage = () => {
 | |
|   const [isConfirmationVisible, setIsConfirmationVisible] = useState(false)
 | |
|   const formSchema = Yup.object().shape({
 | |
|     fullName: Yup.string().required('Name is required'),
 | |
|     email: Yup.string()
 | |
|       .email('Email is not valid')
 | |
|       .required('Email is required'),
 | |
|     password: Yup.string().required('Password is required'),
 | |
|     passwordConfirmation: Yup.string()
 | |
|       .oneOf([Yup.ref('password'), undefined], 'Passwords must match')
 | |
|       .required('Confirm your password'),
 | |
|   })
 | |
| 
 | |
|   const handleSubmit = useCallback(
 | |
|     async (
 | |
|       { fullName, email, password }: FormValues,
 | |
|       { setSubmitting }: FormikHelpers<FormValues>,
 | |
|     ) => {
 | |
|       try {
 | |
|         await AccountAPI.create({
 | |
|           fullName,
 | |
|           email,
 | |
|           password,
 | |
|         })
 | |
|         setIsConfirmationVisible(true)
 | |
|       } finally {
 | |
|         setSubmitting(false)
 | |
|       }
 | |
|     },
 | |
|     [],
 | |
|   )
 | |
| 
 | |
|   return (
 | |
|     <LayoutFull>
 | |
|       <>
 | |
|         <Helmet>
 | |
|           <title>Sign Up to Voltaserve</title>
 | |
|         </Helmet>
 | |
|         {isConfirmationVisible && (
 | |
|           <div
 | |
|             className={cx(
 | |
|               'flex',
 | |
|               'flex-col',
 | |
|               'items-center',
 | |
|               'gap-2.5',
 | |
|               'w-full',
 | |
|             )}
 | |
|           >
 | |
|             <div className={cx('flex', 'flex-col', 'items-center', 'gap-1.5')}>
 | |
|               <div className={cx('w-[64px]')}>
 | |
|                 <Logo isGlossy={true} />
 | |
|               </div>
 | |
|               <Heading className={cx('text-heading')}>
 | |
|                 Thanks! We just sent you a confirmation email
 | |
|               </Heading>
 | |
|               <span className={cx('text-center')}>
 | |
|                 Just open your inbox, find the email, and click on the
 | |
|                 confirmation link.
 | |
|               </span>
 | |
|             </div>
 | |
|           </div>
 | |
|         )}
 | |
|         {!isConfirmationVisible && (
 | |
|           <div
 | |
|             className={cx(
 | |
|               'flex',
 | |
|               'flex-col',
 | |
|               'items-center',
 | |
|               'gap-2.5',
 | |
|               'w-full',
 | |
|             )}
 | |
|           >
 | |
|             <div className={cx('w-[64px]')}>
 | |
|               <Logo isGlossy={true} />
 | |
|             </div>
 | |
|             <Heading className={cx('text-heading')}>
 | |
|               Sign Up to Voltaserve
 | |
|             </Heading>
 | |
|             <Formik
 | |
|               initialValues={{
 | |
|                 fullName: '',
 | |
|                 email: '',
 | |
|                 password: '',
 | |
|                 passwordConfirmation: '',
 | |
|               }}
 | |
|               validationSchema={formSchema}
 | |
|               validateOnBlur={false}
 | |
|               onSubmit={handleSubmit}
 | |
|             >
 | |
|               {({ errors, touched, isSubmitting }) => (
 | |
|                 <Form className={cx('w-full')}>
 | |
|                   <div
 | |
|                     className={cx(
 | |
|                       'flex',
 | |
|                       'flex-col',
 | |
|                       'items-center',
 | |
|                       'gap-1.5',
 | |
|                     )}
 | |
|                   >
 | |
|                     <Field name="fullName">
 | |
|                       {({ field }: FieldAttributes<FieldProps>) => (
 | |
|                         <FormControl
 | |
|                           isInvalid={
 | |
|                             errors.fullName && touched.fullName ? true : false
 | |
|                           }
 | |
|                         >
 | |
|                           <Input
 | |
|                             {...field}
 | |
|                             id="fullName"
 | |
|                             placeholder="Full name"
 | |
|                             disabled={isSubmitting}
 | |
|                           />
 | |
|                           <FormErrorMessage>{errors.fullName}</FormErrorMessage>
 | |
|                         </FormControl>
 | |
|                       )}
 | |
|                     </Field>
 | |
|                     <Field name="email">
 | |
|                       {({ field }: FieldAttributes<FieldProps>) => (
 | |
|                         <FormControl
 | |
|                           isInvalid={
 | |
|                             errors.email && touched.email ? true : false
 | |
|                           }
 | |
|                         >
 | |
|                           <Input
 | |
|                             {...field}
 | |
|                             id="email"
 | |
|                             placeholder="Email"
 | |
|                             disabled={isSubmitting}
 | |
|                           />
 | |
|                           <FormErrorMessage>{errors.email}</FormErrorMessage>
 | |
|                         </FormControl>
 | |
|                       )}
 | |
|                     </Field>
 | |
|                     <Field name="password">
 | |
|                       {({ field }: FieldAttributes<FieldProps>) => (
 | |
|                         <FormControl
 | |
|                           isInvalid={
 | |
|                             errors.password && touched.password ? true : false
 | |
|                           }
 | |
|                         >
 | |
|                           <Input
 | |
|                             {...field}
 | |
|                             id="password"
 | |
|                             placeholder="Password"
 | |
|                             type="password"
 | |
|                             disabled={isSubmitting}
 | |
|                           />
 | |
|                           <FormErrorMessage>{errors.password}</FormErrorMessage>
 | |
|                         </FormControl>
 | |
|                       )}
 | |
|                     </Field>
 | |
|                     <Field name="passwordConfirmation">
 | |
|                       {({ field }: FieldAttributes<FieldProps>) => (
 | |
|                         <FormControl
 | |
|                           isInvalid={
 | |
|                             errors.passwordConfirmation &&
 | |
|                             touched.passwordConfirmation
 | |
|                               ? true
 | |
|                               : false
 | |
|                           }
 | |
|                         >
 | |
|                           <Input
 | |
|                             {...field}
 | |
|                             id="passwordConfirmation"
 | |
|                             placeholder="Confirm password"
 | |
|                             type="password"
 | |
|                             disabled={isSubmitting}
 | |
|                           />
 | |
|                           <FormErrorMessage>
 | |
|                             {errors.passwordConfirmation}
 | |
|                           </FormErrorMessage>
 | |
|                         </FormControl>
 | |
|                       )}
 | |
|                     </Field>
 | |
|                     <Button
 | |
|                       className={cx('w-full')}
 | |
|                       variant="solid"
 | |
|                       colorScheme="blue"
 | |
|                       type="submit"
 | |
|                       isLoading={isSubmitting}
 | |
|                     >
 | |
|                       Sign Up
 | |
|                     </Button>
 | |
|                   </div>
 | |
|                 </Form>
 | |
|               )}
 | |
|             </Formik>
 | |
|             <div className={cx('flex', 'flex-row', 'items-center', 'gap-0.5')}>
 | |
|               <span>Already a member?</span>
 | |
|               <ChakraLink as={Link} to="/sign-in">
 | |
|                 Sign In
 | |
|               </ChakraLink>
 | |
|             </div>
 | |
|           </div>
 | |
|         )}
 | |
|       </>
 | |
|     </LayoutFull>
 | |
|   )
 | |
| }
 | |
| 
 | |
| export default SignUpPage
 |