diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpForm.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpForm.tsx index ccbd87b70..c4b690e41 100644 --- a/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpForm.tsx +++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/SignInUpForm.tsx @@ -13,11 +13,13 @@ import { useSignInWithMicrosoft } from '@/auth/sign-in-up/hooks/useSignInWithMic import { useWorkspaceFromInviteHash } from '@/auth/sign-in-up/hooks/useWorkspaceFromInviteHash'; import { isRequestingCaptchaTokenState } from '@/captcha/states/isRequestingCaptchaTokenState'; import { authProvidersState } from '@/client-config/states/authProvidersState'; +import { captchaProviderState } from '@/client-config/states/captchaProviderState'; import { Loader } from '@/ui/feedback/loader/components/Loader'; import { MainButton } from '@/ui/input/button/components/MainButton'; import { TextInput } from '@/ui/input/components/TextInput'; import { ActionLink } from '@/ui/navigation/link/components/ActionLink.tsx'; import { AnimatedEaseIn } from '@/ui/utilities/animation/components/AnimatedEaseIn'; +import { isDefined } from '~/utils/isDefined'; import { Logo } from '../../components/Logo'; import { Title } from '../../components/Title'; @@ -47,6 +49,7 @@ const StyledInputContainer = styled.div` `; export const SignInUpForm = () => { + const captchaProvider = useRecoilValue(captchaProviderState); const isRequestingCaptchaToken = useRecoilValue( isRequestingCaptchaTokenState, ); @@ -117,6 +120,27 @@ export const SignInUpForm = () => { const theme = useTheme(); + const shouldWaitForCaptchaToken = + signInUpStep !== SignInUpStep.Init && + isDefined(captchaProvider?.provider) && + isRequestingCaptchaToken; + + const isEmailStepSubmitButtonDisabledCondition = + signInUpStep === SignInUpStep.Email && + (form.watch('email').length === 0 || 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 + const isPasswordStepSubmitButtonDisabledCondition = + signInUpStep === SignInUpStep.Password && + (!form.formState.isValid || + form.formState.isSubmitting || + shouldWaitForCaptchaToken); + + const isSubmitButtonDisabled = + isEmailStepSubmitButtonDisabledCondition || + isPasswordStepSubmitButtonDisabledCondition; + return ( <> @@ -245,17 +269,7 @@ export const SignInUpForm = () => { form.handleSubmit(submitCredentials)(); }} Icon={() => form.formState.isSubmitting && } - disabled={ - signInUpStep === SignInUpStep.Init - ? false - : isRequestingCaptchaToken - ? true - : signInUpStep === SignInUpStep.Email - ? !form.watch('email') - : !form.watch('email') || - !form.watch('password') || - form.formState.isSubmitting - } + disabled={isSubmitButtonDisabled} fullWidth /> diff --git a/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx b/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx index f53236247..8713ea4c5 100644 --- a/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/TextInput.tsx @@ -1,27 +1,23 @@ -import { FocusEventHandler, forwardRef, useRef } from 'react'; +import { FocusEventHandler, forwardRef, ForwardRefRenderFunction } from 'react'; import { Key } from 'ts-key-enum'; import { TextInputV2, TextInputV2ComponentProps, } from '@/ui/input/components/TextInputV2'; +import { InputHotkeyScope } from '@/ui/input/types/InputHotkeyScope'; import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; - -import { InputHotkeyScope } from '../types/InputHotkeyScope'; +import { isDefined } from '~/utils/isDefined'; export type TextInputComponentProps = TextInputV2ComponentProps & { disableHotkeys?: boolean; }; -const TextInputComponent = ({ - onFocus, - onBlur, - disableHotkeys = false, - ...props -}: TextInputComponentProps): JSX.Element => { - const inputRef = useRef(null); - +const TextInputComponent: ForwardRefRenderFunction< + HTMLInputElement, + TextInputComponentProps +> = ({ onFocus, onBlur, disableHotkeys = false, ...props }, ref) => { const { goBackToPreviousHotkeyScope, setHotkeyScopeAndMemorizePreviousScope, @@ -46,14 +42,23 @@ const TextInputComponent = ({ useScopedHotkeys( [Key.Escape, Key.Enter], () => { - inputRef.current?.blur(); + if (isDefined(ref) && 'current' in ref) { + ref.current?.blur(); + } }, InputHotkeyScope.TextInput, { enabled: !disableHotkeys }, ); - // eslint-disable-next-line react/jsx-props-no-spreading - return ; + return ( + + ); }; export const TextInput = forwardRef(TextInputComponent);