diff --git a/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/DeleteAccountDialog.tsx b/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/DeleteAccountDialog.tsx new file mode 100644 index 000000000..c80d4b58a --- /dev/null +++ b/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/DeleteAccountDialog.tsx @@ -0,0 +1,89 @@ +"use client"; + +import { useTranslations } from "next-intl"; +import { useEffect, useState } from "react"; +import { toast } from "sonner"; +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Spinner } from "@/components/ui/spinner"; +import { userApiService } from "@/lib/apis/user-api.service"; +import { logout } from "@/lib/auth-utils"; + +// Not translated: the label interpolates this exact word. +const CONFIRMATION_WORD = "DELETE"; + +interface DeleteAccountDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; +} + +/** Spell out what leaving costs, then erase the account. */ +export function DeleteAccountDialog({ open, onOpenChange }: DeleteAccountDialogProps) { + const t = useTranslations("userSettings"); + const [confirmation, setConfirmation] = useState(""); + const [deleting, setDeleting] = useState(false); + + useEffect(() => { + if (open) setConfirmation(""); + }, [open]); + + const handleDelete = async () => { + setDeleting(true); + try { + await userApiService.deleteMe(); + await logout(); + // Reload, not a route push: no cache should outlive the account. + window.location.href = "/"; + } catch { + toast.error(t("delete_account_error")); + setDeleting(false); + } + }; + + return ( + + ); +} diff --git a/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/ProfileContent.tsx b/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/ProfileContent.tsx index 89bc362eb..01a91b4de 100644 --- a/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/ProfileContent.tsx +++ b/surfsense_web/app/dashboard/[workspace_id]/user-settings/components/ProfileContent.tsx @@ -12,6 +12,7 @@ import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Spinner } from "@/components/ui/spinner"; import { getUserAvatarColor, getUserInitials } from "@/lib/user-avatar"; +import { DeleteAccountDialog } from "./DeleteAccountDialog"; function AvatarDisplay({ url, @@ -56,6 +57,7 @@ export function ProfileContent() { const { mutateAsync: updateUser, isPending } = useAtomValue(updateUserMutationAtom); const [displayName, setDisplayName] = useState(""); + const [deleteOpen, setDeleteOpen] = useState(false); useEffect(() => { if (user) { @@ -131,6 +133,20 @@ export function ProfileContent() { )} + + {!isUserLoading && ( +
{t("delete_account_description")}
+