diff --git a/apps/web/src/app/accounts/[id]/delete-account-card.tsx b/apps/web/src/app/accounts/[id]/delete-account-card.tsx new file mode 100644 index 0000000..a0ebbd7 --- /dev/null +++ b/apps/web/src/app/accounts/[id]/delete-account-card.tsx @@ -0,0 +1,104 @@ +"use client"; + +import { useState, useTransition } from "react"; +import { ChevronRightIcon, Loader2Icon, Trash2Icon } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent } from "@/components/ui/card"; +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { deleteAccountAction } from "@/actions/accounts"; + +interface DeleteAccountCardProps { + accountId: string; + accountLabel: string; +} + +export function DeleteAccountCard({ + accountId, + accountLabel, +}: DeleteAccountCardProps) { + const [open, setOpen] = useState(false); + const [pending, start] = useTransition(); + + function confirm() { + start(async () => { + const fd = new FormData(); + fd.append("accountId", accountId); + await deleteAccountAction(fd); + setOpen(false); + }); + } + + return ( + + setOpen(true)} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + setOpen(true); + } + }} + className="transition-all hover:shadow-md hover:ring-destructive/30 cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-destructive focus-visible:ring-offset-2" + > + + + + + + + + Delete Account + + + Remove the account and all its reminders, groups, and history + + + + + + + + + Delete this account permanently? + + {accountLabel} will be removed along with its + synced groups, scheduled reminders, and all run history. This + cannot be undone. + + + + + + Cancel + + + + {pending ? ( + + ) : ( + + )} + Yes, delete + + + + + ); +} diff --git a/apps/web/src/app/accounts/[id]/page.tsx b/apps/web/src/app/accounts/[id]/page.tsx index f31e675..dc0cf6c 100644 --- a/apps/web/src/app/accounts/[id]/page.tsx +++ b/apps/web/src/app/accounts/[id]/page.tsx @@ -2,7 +2,6 @@ import Link from "next/link"; import { notFound } from "next/navigation"; import { UsersIcon, - Trash2Icon, ArrowLeftIcon, SmartphoneIcon, CalendarIcon, @@ -10,7 +9,6 @@ import { DatabaseIcon, PencilIcon, PowerIcon, - PowerOffIcon, ChevronRightIcon, } from "lucide-react"; import { Button } from "@/components/ui/button"; @@ -20,23 +18,12 @@ import { CardHeader, CardTitle, } from "@/components/ui/card"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@/components/ui/dialog"; import { AccountStatusBadge } from "@/components/account-status-badge"; import { getSeededOperator } from "@/lib/operator"; import { getAccount } from "@/lib/queries"; -import { - unpairAccountAction, - pairAccountAction, - deleteAccountAction, -} from "@/actions/accounts"; +import { pairAccountAction } from "@/actions/accounts"; +import { DeleteAccountCard } from "./delete-account-card"; +import { UnpairAccountCard } from "./unpair-account-card"; interface AccountDetailPageProps { params: Promise<{ id: string }>; @@ -156,110 +143,11 @@ export default async function AccountDetailPage({ params }: AccountDetailPagePro - {/* Unpair — transparent overlay (sibling of Card, - inside a relative wrapper). Same pattern as Delete below. */} - - - - - - - - - - Unpair - - Disconnect from WhatsApp; keep the account so you can re-pair later - - - - - - - - - - - - - Unpair this account? - - {account.label} will disconnect from WhatsApp and - scheduled reminders using it will stop firing until you re-pair. - The account itself is kept; reminders and other data are not deleted. - - - - - - - - Yes, unpair - - - - - + > )} - {/* Delete — transparent overlay opens the dialog. - The button lives as a sibling of (inside a relative - wrapper) instead of inside the Card. Radix's asChild-driven - DialogTrigger stops emitting the underlying button when the - wrapper Card adds an `absolute inset-0` sibling on the same - stacking context, so we mirror the working pattern from the - Pair/Re-pair card above. */} - - - - - - - - - - Delete Account - - Remove the account and all its reminders, groups, and history - - - - - - - - - - - - - Delete this account permanently? - - {account.label} will be removed along with its - synced groups, scheduled reminders, and all run history. This cannot be - undone. - - - - - - - - Yes, delete - - - - - + diff --git a/apps/web/src/app/accounts/[id]/unpair-account-card.tsx b/apps/web/src/app/accounts/[id]/unpair-account-card.tsx new file mode 100644 index 0000000..c682e75 --- /dev/null +++ b/apps/web/src/app/accounts/[id]/unpair-account-card.tsx @@ -0,0 +1,102 @@ +"use client"; + +import { useState, useTransition } from "react"; +import { ChevronRightIcon, Loader2Icon, PowerOffIcon } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent } from "@/components/ui/card"; +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { unpairAccountAction } from "@/actions/accounts"; + +interface UnpairAccountCardProps { + accountId: string; + accountLabel: string; +} + +export function UnpairAccountCard({ + accountId, + accountLabel, +}: UnpairAccountCardProps) { + const [open, setOpen] = useState(false); + const [pending, start] = useTransition(); + + function confirm() { + start(async () => { + const fd = new FormData(); + fd.append("accountId", accountId); + await unpairAccountAction(fd); + setOpen(false); + }); + } + + return ( + + setOpen(true)} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + setOpen(true); + } + }} + className="transition-all hover:shadow-md hover:ring-amber-500/30 cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2" + > + + + + + + + Unpair + + Disconnect from WhatsApp; keep the account so you can re-pair later + + + + + + + + + Unpair this account? + + {accountLabel} will disconnect from WhatsApp and + scheduled reminders using it will stop firing until you re-pair. + The account itself is kept; reminders and other data are not + deleted. + + + + + + Cancel + + + + {pending ? ( + + ) : ( + + )} + Yes, unpair + + + + + ); +} diff --git a/apps/web/src/app/login/login-form-client.tsx b/apps/web/src/app/login/login-form-client.tsx index f5516b2..15cd900 100644 --- a/apps/web/src/app/login/login-form-client.tsx +++ b/apps/web/src/app/login/login-form-client.tsx @@ -84,14 +84,7 @@ export function LoginFormClient({ next }: { next: string }) { Forgot your password? - Self-service password reset is intentionally disabled on - this deployment. To recover access, contact an - administrator. They can reset your password from - Settings → Users, or run{" "} - - ./scripts/set-password.sh <username> - {" "} - from the tools container. + Contact your administrator to reset it.
+ Delete Account +
+ Remove the account and all its reminders, groups, and history +
Unpair
- Disconnect from WhatsApp; keep the account so you can re-pair later -
Delete Account
- Remove the account and all its reminders, groups, and history -
+ Disconnect from WhatsApp; keep the account so you can re-pair later +
- ./scripts/set-password.sh <username> -