feat: use pin-input on sign in

This commit is contained in:
Ephraim Atta-Duncan
2024-02-15 15:55:58 +00:00
parent 897f0dabde
commit 345c4b8b14
4 changed files with 176 additions and 32 deletions

View File

@ -139,31 +139,6 @@ export const EnableAuthenticatorAppDialog = ({
}
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const onPinInputChange = ({ currentTarget: input }: any) => {
input.value = input.value.replace(/\D+/g, '');
if (input.value.length === 6) {
setState('loading');
void onEnableTwoFactorAuthenticationFormSubmit({ token: input.value }).then((success) => {
if (success) {
setState('success');
return;
}
setState('error');
setTimeout(() => {
setState('input');
input.value = '';
input.dispatchEvent(new Event('input'));
input.focus();
}, 500);
});
}
};
const onCompleteClick = () => {
flushSync(() => {
onOpenChange(false);
@ -273,7 +248,36 @@ export const EnableAuthenticatorAppDialog = ({
<FormItem>
<FormLabel className="text-muted-foreground">Token</FormLabel>
<FormControl>
<PinInput id="remix" state={state} onChange={onPinInputChange} autoFocus />
<PinInput
id="enable-2fa-pin-input"
state={state}
onSubmit={({ code, input }) => {
console.log(code);
if (code.length === 6) {
setState('loading');
void onEnableTwoFactorAuthenticationFormSubmit({ token: code }).then(
(success) => {
if (success) {
setState('success');
return;
}
setState('error');
setTimeout(() => {
setState('input');
input.value = '';
input.dispatchEvent(new Event('input'));
input.focus();
}, 500);
},
);
}
}}
autoFocus
/>
</FormControl>
<FormMessage />
</FormItem>

View File

@ -31,6 +31,7 @@ import {
} from '@documenso/ui/primitives/form/form';
import { Input } from '@documenso/ui/primitives/input';
import { PasswordInput } from '@documenso/ui/primitives/password-input';
import { PinInput, type PinInputState } from '@documenso/ui/primitives/pin-input';
import { useToast } from '@documenso/ui/primitives/use-toast';
const ERROR_MESSAGES: Partial<Record<keyof typeof ErrorCode, string>> = {
@ -72,6 +73,7 @@ export const SignInForm = ({ className, initialEmail, isGoogleSSOEnabled }: Sign
const [twoFactorAuthenticationMethod, setTwoFactorAuthenticationMethod] = useState<
'totp' | 'backup'
>('totp');
const [state, setState] = useState<PinInputState>('input');
const form = useForm<TSignInFormSchema>({
values: {
@ -151,18 +153,24 @@ export const SignInForm = ({ className, initialEmail, isGoogleSSOEnabled }: Sign
title: 'Unable to sign in',
description: errorMessage ?? 'An unknown error occurred',
});
return;
}
setState('success');
console.log(result);
if (!result?.url) {
throw new Error('An unknown error occurred');
}
window.location.href = result.url;
} catch (err) {
form.setError('totpCode', {
message: 'invalid totp',
});
toast({
title: 'An unknown error occurred',
variant: 'destructive',
description:
'We encountered an unknown error while attempting to sign you In. Please try again later.',
});
@ -254,7 +262,7 @@ export const SignInForm = ({ className, initialEmail, isGoogleSSOEnabled }: Sign
open={isTwoFactorAuthenticationDialogOpen}
onOpenChange={onCloseTwoFactorAuthenticationDialog}
>
<DialogContent>
<DialogContent className="w-full max-w-md md:max-w-md lg:max-w-md">
<DialogHeader>
<DialogTitle>Two-Factor Authentication</DialogTitle>
</DialogHeader>
@ -265,13 +273,38 @@ export const SignInForm = ({ className, initialEmail, isGoogleSSOEnabled }: Sign
<FormField
control={form.control}
name="totpCode"
render={({ field }) => (
render={({ field: _field }) => (
<FormItem>
<FormLabel>Authentication Token</FormLabel>
<FormControl>
<Input type="text" {...field} />
<PinInput
id="verify-2fa-signin-pin-input"
state={state}
onSubmit={async ({ code, input }) => {
if (code.length === 6) {
setState('loading');
form.setValue('totpCode', code);
await form.handleSubmit(onFormSubmit)();
if (form.formState.isSubmitted && !form.formState.errors.totpCode) {
setState('success');
return;
}
setState('error');
setTimeout(() => {
setState('input');
input.value = '';
input.dispatchEvent(new Event('input'));
input.focus();
}, 500);
}
}}
autoFocus
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>