import { useCallback, useState } from 'react'; import { Controller, SubmitHandler, useForm } from 'react-hook-form'; import { useNavigate, useParams } from 'react-router-dom'; import styled from '@emotion/styled'; import { yupResolver } from '@hookform/resolvers/yup'; import { useRecoilState } from 'recoil'; import * as Yup from 'yup'; import { Logo } from '@/auth/components/ui/Logo'; import { SubTitle } from '@/auth/components/ui/SubTitle'; import { Title } from '@/auth/components/ui/Title'; import { useAuth } from '@/auth/hooks/useAuth'; import { authFlowUserEmailState } from '@/auth/states/authFlowUserEmailState'; import { PASSWORD_REGEX } from '@/auth/utils/passwordRegex'; import { isDemoModeState } from '@/client-config/states/isDemoModeState'; import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys'; import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope'; import { MainButton } from '@/ui/components/buttons/MainButton'; import { TextInput } from '@/ui/components/inputs/TextInput'; import { SubSectionTitle } from '@/ui/components/section-titles/SubSectionTitle'; import { useCheckUserExistsQuery } from '~/generated/graphql'; const StyledContentContainer = styled.div` width: 100%; > * + * { margin-top: ${({ theme }) => theme.spacing(6)}; } `; const StyledForm = styled.form` align-items: center; display: flex; flex-direction: column; width: 100%; > * + * { margin-top: ${({ theme }) => theme.spacing(8)}; } `; const StyledSectionContainer = styled.div` > * + * { margin-top: ${({ theme }) => theme.spacing(4)}; } `; const StyledButtonContainer = styled.div` width: 200px; `; const StyledErrorContainer = styled.div` color: ${({ theme }) => theme.color.red}; `; const validationSchema = Yup.object() .shape({ exist: Yup.boolean().required(), email: Yup.string().email('Email must be a valid email').required(), password: Yup.string() .matches( PASSWORD_REGEX, 'Password must contain at least 8 characters, one uppercase and one number', ) .required(), }) .required(); type Form = Yup.InferType; export function PasswordLogin() { const navigate = useNavigate(); const [isDemoMode] = useRecoilState(isDemoModeState); const [authFlowUserEmail] = useRecoilState(authFlowUserEmailState); const [showErrors, setShowErrors] = useState(false); const workspaceInviteHash = useParams().workspaceInviteHash; const { data: checkUserExistsData } = useCheckUserExistsQuery({ variables: { email: authFlowUserEmail, }, }); const { login, signUp } = useAuth(); // Form const { control, handleSubmit, formState: { isSubmitting }, setError, watch, getValues, } = useForm
({ mode: 'onChange', defaultValues: { exist: false, email: authFlowUserEmail, password: isDemoMode ? 'Applecar2025' : '', }, resolver: yupResolver(validationSchema), }); const onSubmit: SubmitHandler = useCallback( async (data) => { try { if (!data.email || !data.password) { throw new Error('Email and password are required'); } if (checkUserExistsData?.checkUserExists.exists) { await login(data.email, data.password); } else { await signUp(data.email, data.password, workspaceInviteHash); } navigate('/auth/create/workspace'); } catch (err: any) { setError('root', { message: err?.message }); } }, [ login, navigate, setError, signUp, workspaceInviteHash, checkUserExistsData, ], ); useScopedHotkeys( 'enter', () => { onSubmit(getValues()); }, InternalHotkeysScope.PasswordLogin, [onSubmit], ); return ( <> Welcome to Twenty Enter your credentials to sign{' '} {checkUserExistsData?.checkUserExists.exists ? 'in' : 'up'} { setShowErrors(true); return handleSubmit(onSubmit)(event); }} > ( )} /> ( )} /> {/* Will be replaced by error snack bar */} ( {errors?.root?.message} )} /> ); }