Locked bulk delete on archives
X-Lovable-Edit-ID: edt-c5698142-6949-4748-b679-b17fa8d781c2 Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com>
This commit is contained in:
@@ -19,7 +19,7 @@ import {
|
||||
import { supabase } from "@/integrations/supabase/client";
|
||||
import { useAuth } from "@/lib/auth";
|
||||
import { toast } from "sonner";
|
||||
import { Archive as ArchiveIcon, Plus, Upload, Trash2, FileSpreadsheet } from "lucide-react";
|
||||
import { Archive as ArchiveIcon, Plus, Upload, Trash2, FileSpreadsheet, Lock, Unlock } from "lucide-react";
|
||||
import { formatDateTime } from "@/lib/format";
|
||||
|
||||
export const Route = createFileRoute("/archive/")({
|
||||
@@ -62,6 +62,24 @@ function ArchivePage() {
|
||||
const [totalCount, setTotalCount] = useState(0);
|
||||
const [uploadOpen, setUploadOpen] = useState(false);
|
||||
const [newCatOpen, setNewCatOpen] = useState(false);
|
||||
const [lockedTabs, setLockedTabs] = useState<Record<string, boolean>>(() => {
|
||||
if (typeof window === "undefined") return {};
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem("archive-locked-tabs") || "{}");
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
});
|
||||
const isLocked = activeId ? lockedTabs[activeId] !== false : true; // default locked
|
||||
const toggleLock = () => {
|
||||
if (!activeId) return;
|
||||
const next = { ...lockedTabs, [activeId]: !isLocked };
|
||||
setLockedTabs(next);
|
||||
try {
|
||||
localStorage.setItem("archive-locked-tabs", JSON.stringify(next));
|
||||
} catch {}
|
||||
toast.success(next[activeId] ? "Tab locked" : "Tab unlocked");
|
||||
};
|
||||
|
||||
// Debounce search input (300ms)
|
||||
useEffect(() => {
|
||||
@@ -153,6 +171,10 @@ function ArchivePage() {
|
||||
}, [rows]);
|
||||
|
||||
const deleteRow = async (id: string) => {
|
||||
if (isLocked) {
|
||||
toast.error("Tab is locked. Unlock it to delete records.");
|
||||
return;
|
||||
}
|
||||
if (!confirm("Delete this record?")) return;
|
||||
const { error } = await supabase.from("archive_records").delete().eq("id", id);
|
||||
if (error) {
|
||||
@@ -166,6 +188,10 @@ function ArchivePage() {
|
||||
|
||||
const deleteAllInCategory = async () => {
|
||||
if (!activeCategory) return;
|
||||
if (isLocked) {
|
||||
toast.error("Tab is locked. Unlock it to clear records.");
|
||||
return;
|
||||
}
|
||||
if (!confirm(`Delete ALL ${totalCount} records in "${activeCategory.label}"? This cannot be undone.`)) return;
|
||||
const { error } = await supabase.from("archive_records").delete().eq("category_id", activeCategory.id);
|
||||
if (error) {
|
||||
@@ -232,8 +258,32 @@ function ArchivePage() {
|
||||
<div className="text-xs text-muted-foreground whitespace-nowrap">
|
||||
Showing {rows.length} of {totalCount} {debouncedSearch ? "matching" : ""} rows
|
||||
</div>
|
||||
{isAdmin && activeId && (
|
||||
<Button
|
||||
variant={isLocked ? "default" : "outline"}
|
||||
size="sm"
|
||||
onClick={toggleLock}
|
||||
title={isLocked ? "Tab is locked — click to unlock" : "Tab is unlocked — click to lock"}
|
||||
>
|
||||
{isLocked ? (
|
||||
<>
|
||||
<Lock className="h-4 w-4 mr-1" /> Locked
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Unlock className="h-4 w-4 mr-1" /> Unlocked
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
{isAdmin && rows.length > 0 && (
|
||||
<Button variant="outline" size="sm" onClick={deleteAllInCategory}>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={deleteAllInCategory}
|
||||
disabled={isLocked}
|
||||
title={isLocked ? "Unlock tab to clear" : "Delete all rows in this tab"}
|
||||
>
|
||||
<Trash2 className="h-4 w-4 mr-1" /> Clear tab
|
||||
</Button>
|
||||
)}
|
||||
@@ -290,10 +340,11 @@ function ArchivePage() {
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => deleteRow(r.id)}
|
||||
title="Delete row"
|
||||
disabled={isLocked}
|
||||
title={isLocked ? "Tab locked" : "Delete row"}
|
||||
className="text-destructive hover:text-destructive h-7 w-7 p-0"
|
||||
>
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
{isLocked ? <Lock className="h-3.5 w-3.5" /> : <Trash2 className="h-3.5 w-3.5" />}
|
||||
</Button>
|
||||
</td>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user