From 14416eb20ee9a2595d3952763e590b9af6e53901 Mon Sep 17 00:00:00 2001 From: admin-valentin Date: Sun, 2 Aug 2026 17:34:54 +0000 Subject: [PATCH] feat(CC-085): add Trust References page (contacts with reference/recomandare tags) --- src/app/dashboard/trust/references/page.tsx | 126 ++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 src/app/dashboard/trust/references/page.tsx diff --git a/src/app/dashboard/trust/references/page.tsx b/src/app/dashboard/trust/references/page.tsx new file mode 100644 index 0000000..f2f2920 --- /dev/null +++ b/src/app/dashboard/trust/references/page.tsx @@ -0,0 +1,126 @@ +'use client'; + +import { useMemo, useState } from 'react'; +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import Link from 'next/link'; +import { apiFetch } from '../../../lib/api'; +import { useSession } from '../../../components/session-provider'; + +interface Contact { id: string; firstName: string; lastName: string | null; role: string | null; organization: string | null; tags: string[]; email: string | null; phone: string | null; linkedinUrl: string | null; createdAt: string; } + +const REF_TAGS = ['reference', 'referinta', 'referința', 'testimonial', 'recomandare', 'recommendation']; + +export default function TrustReferencesPage() { + const { activeTenant } = useSession(); + const tenantId = activeTenant?.tenantId ?? ''; + const qc = useQueryClient(); + const [showAdd, setShowAdd] = useState(false); + + const { data: contacts = [], isLoading } = useQuery({ + queryKey: ['refs', tenantId], + queryFn: () => apiFetch('/v1/contacts?limit=500', { tenantId }), + enabled: Boolean(tenantId), staleTime: 60_000, + }); + + const references = useMemo(() => + contacts.filter((c) => c.tags.some((t) => REF_TAGS.includes(t.toLowerCase()))) + .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()), + [contacts]); + + const [form, setForm] = useState({ firstName: '', lastName: '', role: '', organization: '', email: '', linkedinUrl: '', note: '' }); + + const addMut = useMutation({ + mutationFn: () => apiFetch('/v1/contacts', { tenantId, method: 'POST', body: { + firstName: form.firstName, lastName: form.lastName || undefined, + role: form.role || undefined, organization: form.organization || undefined, + email: form.email || undefined, linkedinUrl: form.linkedinUrl || undefined, + tags: ['reference', 'recomandare'], + notes: form.note || undefined, + }}), + onSuccess: () => { qc.invalidateQueries({ queryKey: ['refs', tenantId] }); setShowAdd(false); setForm({ firstName: '', lastName: '', role: '', organization: '', email: '', linkedinUrl: '', note: '' }); }, + }); + + return ( +
+
+
+ +

Referințe & Recomandări

+

+ {isLoading ? 'Se încarcă…' : `${references.length} contacte care pot oferi referințe`} +

+
+ +
+ +
+

+ Contactele cu tag-ul reference sau recomandare apar automat. + Poți adăuga tag-ul și din pagina de Contacte. +

+
+ + {showAdd && ( +
+

Referință nouă

+
+ setForm((p) => ({ ...p, firstName: 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, lastName: 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, role: 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, organization: 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, email: 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, linkedinUrl: e.target.value }))} + className="rounded-lg border bg-background px-3 py-2 text-sm text-ink font-mono text-xs focus:outline-none focus:ring-2 focus:ring-ring" /> + setForm((p) => ({ ...p, note: 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 sm:col-span-2" /> +
+
+ + +
+
+ )} + + {isLoading ? ( +
Se încarcă…
+ ) : references.length === 0 ? ( +
+

📋

+

Nicio referință. Adaugă contacte care pot confirma experiența ta.

+
+ ) : ( +
+ {references.map((ref) => ( +
+
+
+

{ref.firstName} {ref.lastName ?? ''}

+ {ref.role &&

{ref.role}

} + {ref.organization &&

{ref.organization}

} +
+ REF +
+
+ {ref.email && {ref.email}} + {ref.linkedinUrl && LinkedIn →} +
+
+ ))} +
+ )} +
+ ); +}