Files
Reactive-Resume/src/dialogs/auth/disable-two-factor.tsx
T
Amruth Pillai 08e9c80037 refactor(ui): improve error handling and input safety in app flows
Normalize frontend error rendering and tighten input/path handling across auth, builder, dashboard, and shared components for more resilient UX behavior.

Made-with: Cursor
2026-04-25 15:31:13 +02:00

136 lines
4.7 KiB
TypeScript

import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/core/macro";
import { Trans } from "@lingui/react/macro";
import { EyeIcon, EyeSlashIcon, LockOpenIcon } from "@phosphor-icons/react";
import { useRouter } from "@tanstack/react-router";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { useToggle } from "usehooks-ts";
import z from "zod";
import { Button } from "@/components/ui/button";
import { DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { useFormBlocker } from "@/hooks/use-form-blocker";
import { authClient } from "@/integrations/auth/client";
import { getReadableErrorMessage } from "@/utils/error-message";
import { type DialogProps, useDialogStore } from "../store";
const formSchema = z.object({
password: z.string().min(6).max(64),
});
type FormValues = z.infer<typeof formSchema>;
export function DisableTwoFactorDialog(_: DialogProps<"auth.two-factor.disable">) {
const router = useRouter();
const [showPassword, toggleShowPassword] = useToggle(false);
const closeDialog = useDialogStore((state) => state.closeDialog);
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
password: "",
},
});
const { blockEvents } = useFormBlocker(form);
const onSubmit = async (data: FormValues) => {
const toastId = toast.loading(t`Disabling two-factor authentication...`);
const { error } = await authClient.twoFactor.disable({ password: data.password });
if (error) {
toast.error(
getReadableErrorMessage(
error,
t({
comment: "Fallback toast when disabling two-factor authentication fails",
message: "Failed to disable two-factor authentication. Please try again.",
}),
),
{ id: toastId },
);
return;
}
toast.success(t`Two-factor authentication has been disabled successfully.`, { id: toastId });
void router.invalidate();
closeDialog();
form.reset();
};
return (
<DialogContent {...blockEvents}>
<DialogHeader>
<DialogTitle className="flex items-center gap-x-2">
<LockOpenIcon />
<Trans>Disable Two-Factor Authentication</Trans>
</DialogTitle>
<DialogDescription>
<Trans>
Enter your password to disable two-factor authentication. Your account will be less secure without 2FA
enabled.
</Trans>
</DialogDescription>
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>
<Trans>Password</Trans>
</FormLabel>
<div className="flex items-center gap-x-1.5">
<FormControl
render={
<Input
min={6}
max={64}
type={showPassword ? "text" : "password"}
autoComplete="current-password"
{...field}
/>
}
/>
<Button size="icon" variant="ghost" type="button" onClick={toggleShowPassword}>
<span className="sr-only">
{showPassword
? t({
comment:
"Accessible label for toggle button that hides the visible password in two-factor disable dialog",
message: "Hide password",
})
: t({
comment:
"Accessible label for toggle button that reveals the masked password in two-factor disable dialog",
message: "Show password",
})}
</span>
{showPassword ? <EyeIcon /> : <EyeSlashIcon />}
</Button>
</div>
<FormMessage />
</FormItem>
)}
/>
<DialogFooter>
<Button type="submit" variant="destructive">
<Trans comment="Destructive action button to turn off two-factor authentication">Disable 2FA</Trans>
</Button>
</DialogFooter>
</form>
</Form>
</DialogContent>
);
}