diff --git a/src/app/dashboard/documents/templates/page.tsx b/src/app/dashboard/documents/templates/page.tsx new file mode 100644 index 0000000..2ac0129 --- /dev/null +++ b/src/app/dashboard/documents/templates/page.tsx @@ -0,0 +1,200 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { apiFetch } from '../../../../lib/api'; +import { useSession } from '../../../../components/session-provider'; + +interface Document { + id: string; title: string; type: string | null; content: string | null; + classification: string | null; tags: string[]; status: string | null; + createdAt: string; updatedAt: string; +} + +const TEMPLATE_MARKERS = ['template', 'sablon', 'model', 'template-']; + +function isTemplate(doc: Document) { + const tags = doc.tags.map((t) => t.toLowerCase()); + const type = (doc.type ?? '').toLowerCase(); + return tags.some((t) => TEMPLATE_MARKERS.some((m) => t.includes(m))) || + type === 'template' || type === 'sablon'; +} + +const TEMPLATE_CATEGORIES = [ + { key: 'all', label: 'Toate' }, + { key: 'contract', label: 'Contracte' }, + { key: 'raport', label: 'Rapoarte' }, + { key: 'propunere', label: 'Propuneri' }, + { key: 'acord', label: 'Acorduri' }, + { key: 'factura', label: 'Facturi' }, + { key: 'other', label: 'Altele' }, +]; + +function categoryOf(doc: Document) { + const text = `${doc.title} ${doc.type ?? ''} ${doc.tags.join(' ')}`.toLowerCase(); + if (text.includes('contract')) return 'contract'; + if (text.includes('raport') || text.includes('report')) return 'raport'; + if (text.includes('propun') || text.includes('propos')) return 'propunere'; + if (text.includes('acord') || text.includes('nda')) return 'acord'; + if (text.includes('factur') || text.includes('invoic')) return 'factura'; + return 'other'; +} + +export default function DocTemplatesPage() { + const { activeTenant } = useSession(); + const tenantId = activeTenant?.tenantId ?? ''; + const qc = useQueryClient(); + const [category, setCategory] = useState('all'); + const [search, setSearch] = useState(''); + const [selected, setSelected] = useState(null); + const [showCreate, setShowCreate] = useState(false); + const [form, setForm] = useState({ title: '', type: 'template', content: '', tags: 'template' }); + + const { data: allDocs = [], isLoading } = useQuery({ + queryKey: ['docs-templates', tenantId], + queryFn: () => apiFetch('/v1/documents?limit=500', { tenantId }), + enabled: Boolean(tenantId), staleTime: 60_000, + }); + + const templates = useMemo(() => allDocs.filter(isTemplate), [allDocs]); + + const filtered = useMemo(() => { + return templates.filter((d) => { + if (category !== 'all' && categoryOf(d) !== category) return false; + if (search && !d.title.toLowerCase().includes(search.toLowerCase())) return false; + return true; + }); + }, [templates, category, search]); + + const createMut = useMutation({ + mutationFn: (body: typeof form) => + apiFetch('/v1/documents', { tenantId, method: 'POST', body: { ...body, tags: body.tags.split(',').map(t => t.trim()).filter(Boolean) } }), + onSuccess: () => { qc.invalidateQueries({ queryKey: ['docs-templates', tenantId] }); setShowCreate(false); setForm({ title: '', type: 'template', content: '', tags: 'template' }); }, + }); + + return ( +
+
+
+

Șabloane Documente

+

+ {isLoading ? 'Se încarcă…' : `${templates.length} șabloane din ${allDocs.length} documente`} +

+
+ +
+ +
+ setSearch(e.target.value)} + className="rounded-lg border bg-card px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring" /> +
+ {TEMPLATE_CATEGORIES.map((c) => ( + + ))} +
+
+ + {showCreate && ( +
+

Șablon nou

+
+ setForm((p) => ({ ...p, title: e.target.value }))} + className="rounded-lg border bg-background px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring" /> + setForm((p) => ({ ...p, tags: e.target.value }))} + className="rounded-lg border bg-background px-3 py-2 text-sm text-ink focus:outline-none focus:ring-2 focus:ring-ring" /> +
+