From 3a3c8dae8cc6c5eae0ab1e8234b6773fb45dae4c Mon Sep 17 00:00:00 2001 From: admin-valentin Date: Sun, 2 Aug 2026 12:38:19 +0000 Subject: [PATCH] feat(CC-074): add Document Archive page (docs > 1yr or tagged "archived") --- src/app/dashboard/documents/archive/page.tsx | 137 +++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 src/app/dashboard/documents/archive/page.tsx diff --git a/src/app/dashboard/documents/archive/page.tsx b/src/app/dashboard/documents/archive/page.tsx new file mode 100644 index 0000000..764a4bd --- /dev/null +++ b/src/app/dashboard/documents/archive/page.tsx @@ -0,0 +1,137 @@ +'use client'; + +import { useState } from 'react'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import Link from 'next/link'; +import { apiFetch } from '../../../../lib/api'; +import { useSession } from '../../../../components/session-provider'; + +interface Document { + id: string; title: string; fileType: string | null; classification: string | null; + expiresAt: string | null; ocrStatus: string | null; status?: string; + createdAt: string; updatedAt: string; tags: string[]; +} + +const CLS_CLS: Record = { + C0: 'bg-muted text-ink-faint', C1: 'bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400', + C2: 'bg-amber-50 dark:bg-amber-900/20 text-amber-600 dark:text-amber-400', + C3: 'bg-orange-50 dark:bg-orange-900/20 text-orange-600 dark:text-orange-400', + C4: 'bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400', +}; + +export default function DocumentArchivePage() { + const { activeTenant } = useSession(); + const tenantId = activeTenant?.tenantId ?? ''; + const qc = useQueryClient(); + const [search, setSearch] = useState(''); + const [clsFilter, setClsFilter] = useState('all'); + + const { data: docs = [], isLoading } = useQuery({ + queryKey: ['docs-archive', tenantId], + queryFn: () => apiFetch('/v1/documents?limit=500', { tenantId }), + enabled: Boolean(tenantId), staleTime: 60_000, + }); + + // Archive = docs older than 1 year or explicitly tagged/classified + const archived = docs.filter((d) => { + const createdLong = (Date.now() - new Date(d.createdAt).getTime()) > 365 * 86400_000; + const isTagged = d.tags?.includes('archived') || d.tags?.includes('archive'); + return createdLong || isTagged; + }); + + const filtered = archived.filter((d) => { + if (clsFilter !== 'all' && d.classification !== clsFilter) return false; + if (search && !d.title.toLowerCase().includes(search.toLowerCase())) return false; + return true; + }); + + const classBreakdown: Record = {}; + for (const d of archived) { + const cls = d.classification ?? 'none'; + classBreakdown[cls] = (classBreakdown[cls] ?? 0) + 1; + } + + const unarchiveMut = useMutation({ + mutationFn: (id: string) => + apiFetch(`/v1/documents/${id}`, { tenantId, method: 'PATCH', body: { tags: [] } }), + onSuccess: () => qc.invalidateQueries({ queryKey: ['docs-archive', tenantId] }), + }); + + return ( +
+
+
+

Arhivă Documente

+

+ {archived.length} documente arhivate din {docs.length} total. +

+
+ + ← Toate documentele + +
+ + {/* Classification breakdown */} +
+ + {Object.entries(classBreakdown).map(([cls, count]) => ( + + ))} +
+ + {/* Search */} + setSearch(e.target.value)} + className="w-full rounded-lg border bg-card px-4 py-2.5 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring" /> + + {/* Documents list */} + {isLoading ? ( +
Se încarcă…
+ ) : filtered.length === 0 ? ( +
+

📦

+

+ {archived.length === 0 ? 'Nicio arhivă. Documentele mai vechi de 1 an apar automat.' : 'Niciun rezultat.'} +

+
+ ) : ( +
+ {filtered.map((d) => ( +
+ + {d.fileType?.includes('pdf') ? '📄' : d.fileType?.includes('image') ? '🖼️' : '📁'} + +
+

{d.title}

+
+ {d.classification && ( + + {d.classification} + + )} + {d.fileType && {d.fileType}} + {d.expiresAt && ( + + exp: {new Date(d.expiresAt).toLocaleDateString('ro-RO', { year: 'numeric', month: 'short' })} + + )} +
+
+
+

+ {new Date(d.createdAt).toLocaleDateString('ro-RO', { year: 'numeric', month: 'short' })} +

+
+
+ ))} +
+ )} +
+ ); +}