import { zodResolver } from "@hookform/resolvers/zod" import type { Account } from "better-auth" import { Loader2 } from "lucide-react" import { type ComponentProps, useContext } from "react" import { useForm } from "react-hook-form" import * as z from "zod" import { AuthUIContext } from "../../../lib/auth-ui-provider" import { cn, getLocalizedError } from "../../../lib/utils" import type { AuthLocalization } from "../../../localization/auth-localization" import { Button } from "../../ui/button" import { Card } from "../../ui/card" import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "../../ui/dialog" import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../../ui/form" import { Input } from "../../ui/input" import { UserView } from "../../user-view" import type { SettingsCardClassNames } from "../shared/settings-card" export interface DeleteAccountDialogProps extends ComponentProps { classNames?: SettingsCardClassNames accounts?: Account[] | null localization?: AuthLocalization } export function DeleteAccountDialog({ classNames, accounts, localization, onOpenChange, ...props }: DeleteAccountDialogProps) { const { authClient, basePath, baseURL, deleteUser, freshAge, hooks: { useSession }, localization: contextLocalization, viewPaths, navigate, toast, localizeErrors } = useContext(AuthUIContext) localization = { ...contextLocalization, ...localization } const { data: sessionData } = useSession() const session = sessionData?.session const user = sessionData?.user const isFresh = session ? Date.now() - new Date(session?.createdAt).getTime() < freshAge * 1000 : false const credentialsLinked = accounts?.some( (acc) => acc.providerId === "credential" ) const formSchema = z.object({ password: credentialsLinked ? z.string().min(1, { message: localization.PASSWORD_REQUIRED! }) : z.string().optional() }) const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { password: "" } }) const { isSubmitting } = form.formState const deleteAccount = async ({ password }: z.infer) => { const params = {} as Record if (credentialsLinked) { params.password = password! } else if (!isFresh) { navigate(`${basePath}/${viewPaths.SIGN_OUT}`) return } if (deleteUser?.verification) { params.callbackURL = `${baseURL}${basePath}/${viewPaths.SIGN_OUT}` } try { await authClient.deleteUser({ ...params, fetchOptions: { throw: true } }) if (deleteUser?.verification) { toast({ variant: "success", message: localization.DELETE_ACCOUNT_VERIFY! }) } else { toast({ variant: "success", message: localization.DELETE_ACCOUNT_SUCCESS! }) navigate(`${basePath}/${viewPaths.SIGN_OUT}`) } } catch (error) { toast({ variant: "error", message: getLocalizedError({ error, localization, localizeErrors }) }) } onOpenChange?.(false) } return ( {localization?.DELETE_ACCOUNT} {isFresh ? localization?.DELETE_ACCOUNT_INSTRUCTIONS : localization?.SESSION_NOT_FRESH}
{credentialsLinked && ( ( {localization?.PASSWORD} )} /> )}
) }