mirror of
https://github.com/documenso/documenso.git
synced 2025-11-10 04:22:32 +10:00
feat: 2fa pin input component
This commit is contained in:
@ -35,6 +35,7 @@
|
||||
"perfect-freehand": "^1.2.0",
|
||||
"posthog-js": "^1.75.3",
|
||||
"posthog-node": "^3.1.1",
|
||||
"rci": "^0.1.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-dropzone": "^14.2.3",
|
||||
@ -47,6 +48,7 @@
|
||||
"typescript": "5.2.2",
|
||||
"ua-parser-js": "^1.0.37",
|
||||
"uqr": "^0.1.2",
|
||||
"use-is-focused": "^0.0.1",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
@ -27,8 +27,8 @@ import {
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} 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';
|
||||
|
||||
import { RecoveryCodeList } from './recovery-code-list';
|
||||
@ -54,6 +54,7 @@ export const EnableAuthenticatorAppDialog = ({
|
||||
open,
|
||||
onOpenChange,
|
||||
}: EnableAuthenticatorAppDialogProps) => {
|
||||
const [state, setState] = useState<PinInputState>('input');
|
||||
const router = useRouter();
|
||||
const { toast } = useToast();
|
||||
|
||||
@ -119,13 +120,15 @@ export const EnableAuthenticatorAppDialog = ({
|
||||
token,
|
||||
}: TEnableTwoFactorAuthenticationForm) => {
|
||||
try {
|
||||
await enableTwoFactorAuthentication({ code: token });
|
||||
const enabled2fa = await enableTwoFactorAuthentication({ code: token });
|
||||
|
||||
toast({
|
||||
title: 'Two-factor authentication enabled',
|
||||
description:
|
||||
'Two-factor authentication has been enabled for your account. You will now be required to enter a code from your authenticator app when signing in.',
|
||||
});
|
||||
|
||||
return enabled2fa;
|
||||
} catch (_err) {
|
||||
toast({
|
||||
title: 'Unable to setup two-factor authentication',
|
||||
@ -136,6 +139,31 @@ 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);
|
||||
@ -146,7 +174,7 @@ export const EnableAuthenticatorAppDialog = ({
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="w-full max-w-xl md:max-w-xl lg:max-w-xl">
|
||||
<DialogContent className="w-full max-w-md md:max-w-md lg:max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Enable Authenticator App</DialogTitle>
|
||||
|
||||
@ -241,18 +269,18 @@ export const EnableAuthenticatorAppDialog = ({
|
||||
<FormField
|
||||
name="token"
|
||||
control={enableTwoFactorAuthenticationForm.control}
|
||||
render={({ field }) => (
|
||||
render={({ field: _field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="text-muted-foreground">Token</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} type="text" value={field.value ?? ''} />
|
||||
<PinInput id="remix" state={state} onChange={onPinInputChange} autoFocus />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<DialogFooter>
|
||||
{/* <DialogFooter>
|
||||
<Button type="button" variant="secondary" onClick={() => onOpenChange(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
@ -260,7 +288,7 @@ export const EnableAuthenticatorAppDialog = ({
|
||||
<Button type="submit" loading={isEnableTwoFactorAuthenticationSubmitting}>
|
||||
Enable 2FA
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogFooter> */}
|
||||
</form>
|
||||
</Form>
|
||||
))
|
||||
|
||||
32
package-lock.json
generated
32
package-lock.json
generated
@ -151,6 +151,7 @@
|
||||
"perfect-freehand": "^1.2.0",
|
||||
"posthog-js": "^1.75.3",
|
||||
"posthog-node": "^3.1.1",
|
||||
"rci": "^0.1.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-dropzone": "^14.2.3",
|
||||
@ -163,6 +164,7 @@
|
||||
"typescript": "5.2.2",
|
||||
"ua-parser-js": "^1.0.37",
|
||||
"uqr": "^0.1.2",
|
||||
"use-is-focused": "^0.0.1",
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -15726,6 +15728,18 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/rci": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/rci/-/rci-0.1.0.tgz",
|
||||
"integrity": "sha512-o/elFrXXRLdYDAq/qQUFE175TqzJ5nU3MYwIwa6WOZfljNJ4akQSy1n7zA79swB696MNIFDWJs+Do0q2FBTy+Q==",
|
||||
"dependencies": {
|
||||
"use-code-input": "0.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/re-resizable": {
|
||||
"version": "6.9.6",
|
||||
"resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.9.6.tgz",
|
||||
@ -18860,6 +18874,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/use-code-input": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/use-code-input/-/use-code-input-0.0.2.tgz",
|
||||
"integrity": "sha512-lDIUiRca0K8sF+c/KZ9cz5g6oPqlFiTmaDgwGzg0wlNSnFAvROtweKy0XpihEWJwo2tjETtgAxIh82RVGaBFHQ==",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/use-is-focused": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/use-is-focused/-/use-is-focused-0.0.1.tgz",
|
||||
"integrity": "sha512-EXVmfDqdzUJOYukC9rBCs4TYd93lDVAL6TxegnV0+3U4cBxWxhbyt1bOm5u1ox+0MZZjamBFU/NSTLTtex2uwQ==",
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/use-sidecar": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz",
|
||||
|
||||
Reference in New Issue
Block a user