import React, { useState, useCallback } from 'react'; import { useSearchParams } from 'react-router-dom'; import { useForm, Controller } from 'react-hook-form'; import { REGEXP_ONLY_DIGITS, REGEXP_ONLY_DIGITS_AND_CHARS } from 'input-otp'; import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Label } from '~/components'; import { useVerifyTwoFactorTempMutation } from '~/data-provider'; import { useToastContext } from '~/Providers'; import { useLocalize } from '~/hooks'; interface VerifyPayload { tempToken: string; token?: string; backupCode?: string; } type TwoFactorFormInputs = { token?: string; backupCode?: string; }; const TwoFactorScreen: React.FC = React.memo(() => { const [searchParams] = useSearchParams(); const tempTokenRaw = searchParams.get('tempToken'); const tempToken = tempTokenRaw !== null && tempTokenRaw !== '' ? tempTokenRaw : ''; const { control, handleSubmit, formState: { errors }, } = useForm(); const localize = useLocalize(); const { showToast } = useToastContext(); const [useBackup, setUseBackup] = useState(false); const [isLoading, setIsLoading] = useState(false); const { mutate: verifyTempMutate } = useVerifyTwoFactorTempMutation({ onSuccess: (result) => { if (result.token != null && result.token !== '') { window.location.href = '/'; } }, onMutate: () => { setIsLoading(true); }, onError: (error: unknown) => { setIsLoading(false); const err = error as { response?: { data?: { message?: unknown } } }; const errorMsg = typeof err.response?.data?.message === 'string' ? err.response.data.message : 'Error verifying 2FA'; showToast({ message: errorMsg, status: 'error' }); }, }); const onSubmit = useCallback( (data: TwoFactorFormInputs) => { const payload: VerifyPayload = { tempToken }; if (useBackup && data.backupCode != null && data.backupCode !== '') { payload.backupCode = data.backupCode; } else if (data.token != null && data.token !== '') { payload.token = data.token; } verifyTempMutate(payload); }, [tempToken, useBackup, verifyTempMutate], ); const toggleBackupOn = useCallback(() => { setUseBackup(true); }, []); const toggleBackupOff = useCallback(() => { setUseBackup(false); }, []); return (
{!useBackup && (
( )} /> {errors.token && {errors.token.message}}
)} {useBackup && (
( )} /> {errors.backupCode && ( {errors.backupCode.message} )}
)}
{!useBackup ? ( ) : ( )}
); }); export default TwoFactorScreen;