WORKFLOW-APP/components/DeleteConfirmModal.tsx

103 lines
3.7 KiB
TypeScript
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.

"use client";
// components/DeleteConfirmModal.tsx
// Generic delete confirmation modal.
// Accepts any PocketBase record and calls DELETE on confirm.
// On success: invalidates list cache so the table refreshes.
import { useState } from "react";
import { useQueryClient } from "@tanstack/react-query";
import { pbDelete } from "@/lib/api";
interface Props {
/** "ysterbaard_directors" | "ysterbaard_companies" */
collection: "ysterbaard_directors" | "ysterbaard_companies";
/** The record to delete — used only for display (id + name fields) */
record: { id: string; surname?: string; first_names?: string; enterprise_name?: string; [key: string]: unknown };
open: boolean;
onClose: () => void;
}
export default function DeleteConfirmModal({ collection, record, open, onClose }: Props) {
const qc = useQueryClient();
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
if (!open) return null;
const isDirector = collection === "ysterbaard_directors";
const displayName = isDirector
? `${record.surname ?? ""}, ${record.first_names ?? ""}`.trim()
: (record.enterprise_name as string) ?? record.id;
const handleConfirm = async () => {
setError(null);
setLoading(true);
try {
await pbDelete({ collection, id: record.id });
await qc.invalidateQueries({ queryKey: ["pb-list", collection] });
onClose();
} catch (err) {
setError(err instanceof Error ? err.message : "Delete failed. Please try again.");
} finally {
setLoading(false);
}
};
return (
<div
onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}
className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4"
role="dialog"
aria-modal="true"
aria-label={`Delete ${isDirector ? "director" : "company"}`}
>
<div className="bg-surface border border-border rounded-xl shadow-2xl w-full max-w-sm">
{/* Header */}
<div className="px-6 pt-6 pb-4">
<div className="flex items-start justify-between">
<div>
<h2 className="text-lg font-bold text-fg">Delete {isDirector ? "director" : "company"}?</h2>
<p className="text-sm text-muted mt-1">
This will permanently delete <strong className="text-fg">{displayName}</strong> from PocketBase. This action cannot be undone.
</p>
</div>
<button
onClick={onClose}
className="ml-4 text-muted hover:text-fg text-xl leading-none p-1 rounded transition-colors"
aria-label="Close"
>
×
</button>
</div>
</div>
{/* Body */}
<div className="px-6 pb-6">
{error && (
<div className="bg-red-500/10 border border-red-500/30 rounded-lg px-4 py-3 text-sm text-red-400 mb-4">
{error}
</div>
)}
<div className="flex gap-3">
<button
type="button"
onClick={onClose}
className="flex-1 px-4 py-2.5 rounded-lg border border-border bg-surface-warm text-sm font-semibold text-fg hover:bg-surface transition-colors"
>
Cancel
</button>
<button
type="button"
onClick={handleConfirm}
disabled={loading}
className="flex-1 px-4 py-2.5 rounded-lg bg-red-600 text-white text-sm font-bold hover:bg-red-700 transition-colors disabled:opacity-60 disabled:cursor-not-allowed"
>
{loading ? "Deleting..." : "Yes, delete"}
</button>
</div>
</div>
</div>
</div>
);
}