BillTracker/client/components/data/EraseDataSection.jsx

98 lines
4.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from 'react';
import { toast } from 'sonner';
import { ShieldAlert, Loader2, Trash2 } from 'lucide-react';
import { api } from '@/api';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import {
AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent,
AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger,
} from '@/components/ui/alert-dialog';
import { SectionCard } from './dataShared';
/**
* Danger zone: permanently erase the user's financial data. Type-to-confirm, and
* makes clear that the account/login/2FA are preserved. Reuses POST
* /api/user/erase-data (transactional, audited, re-seeds default categories).
*/
export default function EraseDataSection({ onErased, cardProps = {} }) {
const [open, setOpen] = useState(false);
const [confirm, setConfirm] = useState('');
const [busy, setBusy] = useState(false);
const canErase = confirm.trim().toUpperCase() === 'ERASE';
async function handleErase() {
if (!canErase) return;
setBusy(true);
try {
const r = await api.eraseMyData(confirm.trim());
toast.success(`Your data was erased — ${r.erased} record${r.erased === 1 ? '' : 's'} removed.`);
setOpen(false);
setConfirm('');
onErased?.();
} catch (err) {
toast.error(err.message || 'Erase failed.');
} finally {
setBusy(false);
}
}
return (
<SectionCard {...cardProps}>
<div className="space-y-4 px-6 py-5">
<div className="rounded-lg border border-rose-300/60 bg-rose-50 p-4 dark:border-rose-800/50 dark:bg-rose-950/20">
<div className="flex items-start gap-3">
<ShieldAlert className="mt-0.5 h-5 w-5 shrink-0 text-rose-600 dark:text-rose-400" />
<div className="min-w-0 text-sm">
<p className="font-medium text-rose-700 dark:text-rose-300">This permanently deletes your financial data.</p>
<p className="mt-1 text-muted-foreground">
Bills, payments, transactions, categories, bank connections, imports and rules will be erased and
cant be recovered. Your <span className="font-medium text-foreground">account, login and 2FA are kept</span>.
Consider downloading a backup first.
</p>
</div>
</div>
</div>
<AlertDialog open={open} onOpenChange={(v) => { setOpen(v); if (!v) setConfirm(''); }}>
<AlertDialogTrigger asChild>
<Button
variant="outline"
className="gap-2 border-rose-300 text-rose-600 hover:bg-rose-50 dark:border-rose-800/60 dark:text-rose-400 dark:hover:bg-rose-950/30"
>
<Trash2 className="h-4 w-4" /> Erase my data
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Erase all your data?</AlertDialogTitle>
<AlertDialogDescription>
This permanently deletes your bills, payments, transactions, categories, bank connections and imports.
It cannot be undone. Type <span className="font-mono font-semibold text-foreground">ERASE</span> to confirm.
</AlertDialogDescription>
</AlertDialogHeader>
<Input
autoFocus
value={confirm}
onChange={(e) => setConfirm(e.target.value)}
placeholder="Type ERASE"
className="font-mono"
aria-label="Type ERASE to confirm"
/>
<AlertDialogFooter>
<AlertDialogCancel disabled={busy}>Cancel</AlertDialogCancel>
<AlertDialogAction
disabled={!canErase || busy}
onClick={(e) => { e.preventDefault(); handleErase(); }}
className="bg-rose-600 text-white hover:bg-rose-700"
>
{busy ? <><Loader2 className="mr-1.5 h-4 w-4 animate-spin" />Erasing</> : 'Permanently erase'}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</div>
</SectionCard>
);
}