From 0d8d8627a2548a0088ddddcbc016ee2d439a3b45 Mon Sep 17 00:00:00 2001 From: Marko Djordjevic Date: Fri, 20 Feb 2026 13:37:03 +0100 Subject: [PATCH] Add Danger Zone section to settings page with delete account dialog Adds a destructively-styled Danger Zone card to src/app/app/settings/page.tsx. Clicking "Delete Account" opens a shadcn/ui Dialog that warns the user the action is irreversible, requires typing "DELETE" to enable the confirm button, calls DELETE /api/auth/account on confirmation, then signs the user out and redirects to "/". Marks task 12.3 complete in tasks.md. Co-Authored-By: Claude Sonnet 4.6 --- openspec/changes/user-accounts/tasks.md | 2 +- src/app/app/settings/page.tsx | 132 +++++++++++++++++++++++- 2 files changed, 131 insertions(+), 3 deletions(-) diff --git a/openspec/changes/user-accounts/tasks.md b/openspec/changes/user-accounts/tasks.md index e5b84c7..0f9bec0 100644 --- a/openspec/changes/user-accounts/tasks.md +++ b/openspec/changes/user-accounts/tasks.md @@ -70,7 +70,7 @@ - [x] 12.1 `[sonnet]` Create `src/app/app/settings/page.tsx` — Profile section: display name input with save, read-only email - [x] 12.2 `[sonnet]` Add Security section: change password form (current/new/confirm) for credentials users, "Signed in via Google" for OAuth users -- [ ] 12.3 `[sonnet]` Add Danger Zone section: delete account button with confirmation dialog (type "DELETE" to confirm) +- [x] 12.3 `[sonnet]` Add Danger Zone section: delete account button with confirmation dialog (type "DELETE" to confirm) - [ ] 12.4 `[haiku]` Add back navigation link to `/app` ## 13. App Layout & User Menu diff --git a/src/app/app/settings/page.tsx b/src/app/app/settings/page.tsx index efe0f5d..c432d00 100644 --- a/src/app/app/settings/page.tsx +++ b/src/app/app/settings/page.tsx @@ -1,12 +1,20 @@ "use client"; import { useState, useEffect } from "react"; -import { useSession } from "next-auth/react"; +import { useSession, signOut } from "next-auth/react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; -import { CheckCircle, AlertCircle } from "lucide-react"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { CheckCircle, AlertCircle, Trash2 } from "lucide-react"; export default function SettingsPage() { const { data: session, update } = useSession(); @@ -20,6 +28,12 @@ export default function SettingsPage() { // User provider state (fetched from API) const [userProvider, setUserProvider] = useState(null); + // Danger Zone — delete account state + const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); + const [deleteConfirmText, setDeleteConfirmText] = useState(""); + const [isDeletingAccount, setIsDeletingAccount] = useState(false); + const [deleteError, setDeleteError] = useState(null); + // Security / change-password state const [currentPassword, setCurrentPassword] = useState(""); const [newPassword, setNewPassword] = useState(""); @@ -120,6 +134,25 @@ export default function SettingsPage() { } } + async function handleDeleteAccount() { + setDeleteError(null); + setIsDeletingAccount(true); + try { + const response = await fetch("/api/auth/account", { method: "DELETE" }); + if (!response.ok) { + const data = await response.json(); + setDeleteError(data.error ?? "Failed to delete account."); + return; + } + // Account deleted — sign out and redirect to home + await signOut({ redirectTo: "/" }); + } catch { + setDeleteError("An unexpected error occurred. Please try again."); + } finally { + setIsDeletingAccount(false); + } + } + const email = session?.user?.email ?? ""; const isCredentialsUser = userProvider === "credentials"; const isOAuthUser = userProvider !== null && userProvider !== "credentials"; @@ -198,6 +231,7 @@ export default function SettingsPage() { + {/* ------------------------------------------------------------------ */} {/* Security section */} {userProvider !== null && ( @@ -318,6 +352,100 @@ export default function SettingsPage() { )} + {/* Danger Zone section */} + + + Danger Zone + + Irreversible actions that affect your account and all your data. + + + +
+
+

Delete Account

+

+ Permanently delete your account and all associated data. This cannot be undone. +

+
+ +
+
+
+ + {/* Delete account confirmation dialog */} + { + if (!isDeletingAccount) setDeleteDialogOpen(open); + }} + > + + + Delete Account + + This action is irreversible. + All your charts, annotations, and data will be permanently deleted. + + + +
+ {deleteError && ( +
+ +

{deleteError}

+
+ )} + +
+ + setDeleteConfirmText(e.target.value)} + className="font-mono text-sm" + disabled={isDeletingAccount} + autoComplete="off" + /> +
+
+ + + + + +
+
); }