diff --git a/apps/meteor/client/components/TwoFactorModal/TwoFactorEmailModal.tsx b/apps/meteor/client/components/TwoFactorModal/TwoFactorEmailModal.tsx index 7880d2f375594..c80fb09e78ae1 100644 --- a/apps/meteor/client/components/TwoFactorModal/TwoFactorEmailModal.tsx +++ b/apps/meteor/client/components/TwoFactorModal/TwoFactorEmailModal.tsx @@ -1,9 +1,9 @@ -import { Box, FieldGroup, TextInput, Field, FieldLabel, FieldRow, FieldError, Button } from '@rocket.chat/fuselage'; -import { useAutoFocus } from '@rocket.chat/fuselage-hooks'; +import { Box, Button } from '@rocket.chat/fuselage'; +import { FieldGroup, TextInput, Field, FieldLabel, FieldRow, FieldError } from '@rocket.chat/fuselage-forms'; import { GenericModal } from '@rocket.chat/ui-client'; import { useToastMessageDispatch, useEndpoint } from '@rocket.chat/ui-contexts'; -import type { ReactElement, ChangeEvent, SyntheticEvent } from 'react'; -import { useId, useState } from 'react'; +import type { ReactElement } from 'react'; +import { useForm, Controller } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import type { OnConfirm } from './TwoFactorModal'; @@ -13,14 +13,25 @@ type TwoFactorEmailModalProps = { onConfirm: OnConfirm; onClose: () => void; emailOrUsername: string; - invalidAttempt?: boolean; }; -const TwoFactorEmailModal = ({ onConfirm, onClose, emailOrUsername, invalidAttempt }: TwoFactorEmailModalProps): ReactElement => { +type TwoFactorEmailFormData = { + code: string; +}; + +const TwoFactorEmailModal = ({ onConfirm, onClose, emailOrUsername }: TwoFactorEmailModalProps): ReactElement => { const dispatchToastMessage = useToastMessageDispatch(); const { t } = useTranslation(); - const [code, setCode] = useState(''); - const ref = useAutoFocus(); + + const { + control, + handleSubmit, + setError, + setValue, + formState: { errors, isSubmitting }, + } = useForm({ + defaultValues: { code: '' }, + }); const sendEmailCode = useEndpoint('POST', '/v1/users.2fa.sendEmailCode'); @@ -36,46 +47,51 @@ const TwoFactorEmailModal = ({ onConfirm, onClose, emailOrUsername, invalidAttem } }; - const onConfirmEmailCode = (e: SyntheticEvent): void => { - e.preventDefault(); - onConfirm(code, Method.EMAIL); - }; - - const onChange = ({ currentTarget }: ChangeEvent): void => { - setCode(currentTarget.value); - }; - - const id = useId(); + const onSubmit = handleSubmit(async ({ code }) => { + try { + await onConfirm(code, Method.EMAIL); + } catch (error) { + setError('code', { + type: 'manual', + message: t('Invalid_two_factor_code'), + }); + setValue('code', ''); + } + }); return ( } + wrapperFunction={(props) => } onCancel={onClose} confirmText={t('Verify')} title={t('Enter_authentication_code')} onClose={onClose} variant='warning' - confirmDisabled={!code} + confirmDisabled={isSubmitting} tagline={t('Email_two-factor_authentication')} icon={null} > - - {t('Enter_the_code_we_just_emailed_you')} - + {t('Enter_the_code_we_just_emailed_you')} - ( + + )} /> - {invalidAttempt && {t('Invalid_password')}} + {errors.code && {errors.code.message}}