import { useEffect, useState } from "react"; import { useListTrashedTools, useRestoreTools, useDeleteTrashedTools, useEmptyTrash, getListTrashedToolsQueryKey, getListToolsQueryKey, getListCategoriesQueryKey, getListAllFeaturesQueryKey, getListAllTagsQueryKey, getGetTopToolsQueryKey, getGetAnalyticsSummaryQueryKey, } from "@workspace/api-client-react"; import { useQueryClient } from "@tanstack/react-query"; import { useAuth } from "@/hooks/use-auth"; import { Layout } from "@/components/layout"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Checkbox } from "@/components/ui/checkbox"; import { Skeleton } from "@/components/ui/skeleton"; import { useToast } from "@/hooks/use-toast"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog"; import { Trash2, RotateCcw, Search, ShieldAlert, Trash as TrashIcon, RefreshCcw } from "lucide-react"; import { format } from "date-fns"; import { useTranslation } from "react-i18next"; export default function Trash() { const { t } = useTranslation(); const { user, isAdmin, hasFeature, isLoading: authLoading } = useAuth(); const { toast } = useToast(); const queryClient = useQueryClient(); const [searchInput, setSearchInput] = useState(""); const [search, setSearch] = useState(""); const [selected, setSelected] = useState>(new Set()); const [confirmDelete, setConfirmDelete] = useState(false); const [confirmEmpty, setConfirmEmpty] = useState(false); useEffect(() => { const t = setTimeout(() => setSearch(searchInput), 300); return () => clearTimeout(t); }, [searchInput]); const hasTrash = hasFeature("trash"); const { data: tools, isLoading: loading } = useListTrashedTools( search ? { search } : undefined, { query: { queryKey: getListTrashedToolsQueryKey(search ? { search } : undefined), enabled: hasTrash } }, ); const restore = useRestoreTools(); const deletePermanent = useDeleteTrashedTools(); const empty = useEmptyTrash(); const trashed = tools ?? []; function invalidate() { queryClient.invalidateQueries({ queryKey: getListTrashedToolsQueryKey() }); queryClient.invalidateQueries({ queryKey: getListToolsQueryKey() }); queryClient.invalidateQueries({ queryKey: getListCategoriesQueryKey() }); queryClient.invalidateQueries({ queryKey: getListAllFeaturesQueryKey() }); queryClient.invalidateQueries({ queryKey: getListAllTagsQueryKey() }); queryClient.invalidateQueries({ queryKey: getGetTopToolsQueryKey() }); queryClient.invalidateQueries({ queryKey: getGetAnalyticsSummaryQueryKey() }); } function toggle(id: number) { setSelected((prev) => { const next = new Set(prev); if (next.has(id)) next.delete(id); else next.add(id); return next; }); } function toggleAll() { if (selected.size === trashed.length) { setSelected(new Set()); } else { setSelected(new Set(trashed.map((t) => t.id))); } } function handleRestore(ids: number[]) { restore.mutate( { data: { ids } }, { onSuccess: (res) => { toast({ title: t("trash.toastRestored"), description: t("trash.toastRestoredSub", { count: res.restored ?? ids.length }) }); setSelected(new Set()); invalidate(); }, onError: (err) => { toast({ title: t("trash.toastRestoreFailed"), description: err.data?.error ?? err.message, variant: "destructive" }); }, }, ); } function handleDeletePermanent(ids: number[]) { deletePermanent.mutate( { data: { ids } }, { onSuccess: () => { toast({ title: t("trash.toastDeleted"), description: t("trash.toastDeletedSub", { count: ids.length }) }); setSelected(new Set()); setConfirmDelete(false); invalidate(); }, onError: (err) => { toast({ title: t("trash.toastDeleteFailed"), description: err.data?.error ?? err.message, variant: "destructive" }); }, }, ); } function handleEmpty() { empty.mutate( undefined, { onSuccess: (res) => { toast({ title: t("trash.toastEmptied"), description: t("trash.toastEmptiedSub", { count: res.deleted ?? 0 }) }); setSelected(new Set()); setConfirmEmpty(false); invalidate(); }, onError: (err) => { toast({ title: t("trash.toastEmptyFailed"), description: err.data?.error ?? err.message, variant: "destructive" }); }, }, ); } if (!authLoading && !hasTrash) { return (

{t("trash.requiresPremium")}

{t("trash.requiresPremiumSub")}

); } const selectedIds = [...selected]; return (

{t("trash.title")}

{t("trash.subtitle")}

{t("trash.trashedTools")} {selectedIds.length > 0 ? t("trash.selected", { count: selectedIds.length }) : t("trash.toolsInTrash", { count: trashed.length })}
setSearchInput(e.target.value)} />
{isAdmin && ( <> )}
{loading ? (
{[1, 2, 3].map((i) => )}
) : trashed.length === 0 ? (
{search ? t("trash.noMatch") : t("trash.empty")}
) : ( 0} onCheckedChange={toggleAll} aria-label={t("trash.selectAll")} /> {t("trash.name")} {t("trash.category")} {t("trash.deletedAt")} {t("trash.deletedBy")} {t("trash.actions")} {trashed.map((tool) => ( toggle(tool.id)} aria-label={t("trash.selectName", { name: tool.name })} /> {tool.name} {tool.category} {tool.deletedAt ? format(new Date(tool.deletedAt), "dd.MM.yyyy HH:mm") : "—"} {tool.deletedBy ?? "—"}
{isAdmin && ( )}
))}
)}
{t("trash.deleteConfirmTitle", { count: selectedIds.length })} {t("trash.deleteConfirmSub")} {t("common.cancel")} handleDeletePermanent(selectedIds)} > {t("trash.deletePermanently")} {t("trash.emptyConfirmTitle")} {t("trash.emptyConfirmSub", { count: trashed.length })} {t("common.cancel")} {t("trash.emptyTrash")}
); }