mirror of
https://github.com/documenso/documenso.git
synced 2025-11-18 02:32:00 +10:00
feat: use pin-input on sign in
This commit is contained in:
@ -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>
|
||||
|
||||
@ -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>
|
||||
)}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user