From 6e04a3b19fe41b1fe46f0138e546695725eca4bd Mon Sep 17 00:00:00 2001 From: Antoine Moreaux Date: Tue, 7 Jan 2025 17:09:45 +0100 Subject: [PATCH] refactor(auth): integrate react-hook-form context (#9417) Remove redundant validation logic and streamline form handling by leveraging react-hook-form's context. Simplify component props and enhance consistency across the sign-in/up flow. Fix https://github.com/twentyhq/twenty/issues/9380 --- .../components/SignInUpEmailField.tsx | 14 +---- .../components/SignInUpWithCredentials.tsx | 57 +++++++++---------- .../components/SignInUpWorkspaceScopeForm.tsx | 10 +++- .../auth/sign-in-up/hooks/useSignInUpForm.ts | 2 +- 4 files changed, 37 insertions(+), 46 deletions(-) diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpEmailField.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpEmailField.tsx index a2ca5d1af..7c7dee0cd 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpEmailField.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpEmailField.tsx @@ -2,7 +2,6 @@ import { TextInput } from '@/ui/input/components/TextInput'; import { Controller, useFormContext } from 'react-hook-form'; import styled from '@emotion/styled'; import { motion } from 'framer-motion'; -import { isDefined } from '~/utils/isDefined'; import { Form } from '@/auth/sign-in-up/hooks/useSignInUpForm'; const StyledFullWidthMotionDiv = styled(motion.div)` @@ -13,13 +12,7 @@ const StyledInputContainer = styled.div` margin-bottom: ${({ theme }) => theme.spacing(3)}; `; -export const SignInUpEmailField = ({ - showErrors, - onChange: onChangeFromProps, -}: { - showErrors: boolean; - onChange?: (value: string) => void; -}) => { +export const SignInUpEmailField = ({ showErrors }: { showErrors: boolean }) => { const form = useFormContext
(); return ( @@ -45,10 +38,7 @@ export const SignInUpEmailField = ({ value={value} placeholder="Email" onBlur={onBlur} - onChange={(value: string) => { - onChange(value); - if (isDefined(onChangeFromProps)) onChangeFromProps(value); - }} + onChange={onChange} error={showErrors ? error?.message : undefined} fullWidth /> diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpWithCredentials.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpWithCredentials.tsx index a1176e13c..e385edd8c 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpWithCredentials.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpWithCredentials.tsx @@ -3,17 +3,18 @@ import { signInUpStepState, } from '@/auth/states/signInUpStepState'; import { useSignInUp } from '@/auth/sign-in-up/hooks/useSignInUp'; +import { Form } from '@/auth/sign-in-up/hooks/useSignInUpForm'; + import { Loader, MainButton } from 'twenty-ui'; import { isDefined } from '~/utils/isDefined'; import { SignInUpEmailField } from '@/auth/sign-in-up/components/SignInUpEmailField'; -import { useSignInUpForm } from '@/auth/sign-in-up/hooks/useSignInUpForm'; import { useRecoilValue } from 'recoil'; import styled from '@emotion/styled'; import { SignInUpPasswordField } from '@/auth/sign-in-up/components/SignInUpPasswordField'; import { useState, useMemo } from 'react'; import { captchaProviderState } from '@/client-config/states/captchaProviderState'; import { isRequestingCaptchaTokenState } from '@/captcha/states/isRequestingCaptchaTokenState'; -import { FormProvider } from 'react-hook-form'; +import { useFormContext } from 'react-hook-form'; import { SignInUpMode } from '@/auth/types/signInUpMode'; const StyledForm = styled.form` @@ -24,7 +25,7 @@ const StyledForm = styled.form` `; export const SignInUpWithCredentials = () => { - const { form, validationSchema } = useSignInUpForm(); + const form = useFormContext(); const signInUpStep = useRecoilValue(signInUpStepState); const [showErrors, setShowErrors] = useState(false); @@ -90,8 +91,7 @@ export const SignInUpWithCredentials = () => { const isEmailStepSubmitButtonDisabledCondition = signInUpStep === SignInUpStep.Email && - (!validationSchema.shape.email.safeParse(form.watch('email')).success || - shouldWaitForCaptchaToken); + (isDefined(form.formState.errors['email']) || shouldWaitForCaptchaToken); // TODO: isValid is actually a proxy function. If it is not rendered the first time, react might not trigger re-renders // We make the isValid check synchronous and update a reactState to make sure this does not happen @@ -110,32 +110,27 @@ export const SignInUpWithCredentials = () => { {(signInUpStep === SignInUpStep.Password || signInUpStep === SignInUpStep.Email || signInUpStep === SignInUpStep.Init) && ( - <> - {/* eslint-disable-next-line react/jsx-props-no-spreading */} - - - {signInUpStep !== SignInUpStep.Init && ( - - )} - {signInUpStep === SignInUpStep.Password && ( - - )} - (form.formState.isSubmitting ? : null)} - disabled={isSubmitButtonDisabled} - fullWidth - /> - - - + + {signInUpStep !== SignInUpStep.Init && ( + + )} + {signInUpStep === SignInUpStep.Password && ( + + )} + (form.formState.isSubmitting ? : null)} + disabled={isSubmitButtonDisabled} + fullWidth + /> + )} ); diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx index 17f46f954..a5ee130b9 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpWorkspaceScopeForm.tsx @@ -8,6 +8,7 @@ import { useSignInUpForm } from '@/auth/sign-in-up/hooks/useSignInUpForm'; import { SignInUpStep } from '@/auth/states/signInUpStepState'; import { workspaceAuthProvidersState } from '@/workspace/states/workspaceAuthProvidersState'; import styled from '@emotion/styled'; +import { FormProvider } from 'react-hook-form'; import { useRecoilValue } from 'recoil'; import { ActionLink, HorizontalSeparator } from 'twenty-ui'; @@ -20,6 +21,7 @@ export const SignInUpWorkspaceScopeForm = () => { const workspaceAuthProviders = useRecoilValue(workspaceAuthProvidersState); const { form } = useSignInUpForm(); + const { handleResetPassword } = useHandleResetPassword(); const { signInUpStep } = useSignInUp(form); @@ -39,8 +41,12 @@ export const SignInUpWorkspaceScopeForm = () => { workspaceAuthProviders.password ? ( ) : null} - - {workspaceAuthProviders.password && } + {workspaceAuthProviders.password && ( + // eslint-disable-next-line react/jsx-props-no-spreading + + + + )} {signInUpStep === SignInUpStep.Password && ( diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts b/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts index 93a6e16c2..ef1af97ed 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts +++ b/packages/twenty-front/src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts @@ -70,5 +70,5 @@ export const useSignInUpForm = () => { prefilledEmail, location.search, ]); - return { form: form, validationSchema }; + return { form: form }; };