From ea21cbdcd4be515ec20491a88835a5bdc5d9e0e2 Mon Sep 17 00:00:00 2001 From: Scott McKendry Date: Sun, 12 Apr 2026 11:11:57 +1200 Subject: [PATCH] fix(ui): allow pw manager extensions to autofill totp --- frontend/bun.lock | 3 - frontend/package.json | 1 - frontend/src/components/auth/totp-form.tsx | 37 ++++------- frontend/src/components/ui/input-otp.tsx | 75 ---------------------- 4 files changed, 13 insertions(+), 103 deletions(-) delete mode 100644 frontend/src/components/ui/input-otp.tsx diff --git a/frontend/bun.lock b/frontend/bun.lock index 9b2503d..d986087 100644 --- a/frontend/bun.lock +++ b/frontend/bun.lock @@ -19,7 +19,6 @@ "i18next": "^26.0.3", "i18next-browser-languagedetector": "^8.2.1", "i18next-resources-to-backend": "^1.2.1", - "input-otp": "^1.4.2", "lucide-react": "^1.7.0", "next-themes": "^0.4.6", "radix-ui": "^1.4.3", @@ -623,8 +622,6 @@ "inline-style-parser": ["inline-style-parser@0.2.4", "", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="], - "input-otp": ["input-otp@1.4.2", "", { "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA=="], - "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="], "is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="], diff --git a/frontend/package.json b/frontend/package.json index 914afc6..dd5fa2e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -25,7 +25,6 @@ "i18next": "^26.0.3", "i18next-browser-languagedetector": "^8.2.1", "i18next-resources-to-backend": "^1.2.1", - "input-otp": "^1.4.2", "lucide-react": "^1.7.0", "next-themes": "^0.4.6", "radix-ui": "^1.4.3", diff --git a/frontend/src/components/auth/totp-form.tsx b/frontend/src/components/auth/totp-form.tsx index 2be9216..15e490c 100644 --- a/frontend/src/components/auth/totp-form.tsx +++ b/frontend/src/components/auth/totp-form.tsx @@ -1,10 +1,5 @@ import { Form, FormControl, FormField, FormItem } from "../ui/form"; -import { - InputOTP, - InputOTPGroup, - InputOTPSeparator, - InputOTPSlot, -} from "../ui/input-otp"; +import { Input } from "../ui/input"; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; import { totpSchema, TotpSchema } from "@/schemas/totp-schema"; @@ -29,11 +24,11 @@ export const TotpForm = (props: Props) => { resolver: zodResolver(totpSchema), }); - const handleChange = (value: string) => { + const handleChange = (e: React.ChangeEvent) => { + const value = e.target.value.replace(/\D/g, "").slice(0, 6); form.setValue("code", value, { shouldDirty: true, shouldValidate: true }); - if (value.length === 6) { - onSubmit({ code: value }); + form.handleSubmit(onSubmit)(); } }; @@ -46,25 +41,19 @@ export const TotpForm = (props: Props) => { render={({ field }) => ( - - - - - - - - - - - - - + className="text-center" + /> )} diff --git a/frontend/src/components/ui/input-otp.tsx b/frontend/src/components/ui/input-otp.tsx deleted file mode 100644 index 43c6ea0..0000000 --- a/frontend/src/components/ui/input-otp.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import * as React from "react"; -import { OTPInput, OTPInputContext } from "input-otp"; -import { MinusIcon } from "lucide-react"; - -import { cn } from "@/lib/utils"; - -function InputOTP({ - className, - containerClassName, - ...props -}: React.ComponentProps & { - containerClassName?: string; -}) { - return ( - - ); -} - -function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ); -} - -function InputOTPSlot({ - index, - className, - ...props -}: React.ComponentProps<"div"> & { - index: number; -}) { - const inputOTPContext = React.useContext(OTPInputContext); - const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {}; - - return ( -
- {char} - {hasFakeCaret && ( -
-
-
- )} -
- ); -} - -function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) { - return ( -
- -
- ); -} - -export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };