diff --git a/src/app/dashboard/trust/social/page.tsx b/src/app/dashboard/trust/social/page.tsx new file mode 100644 index 0000000..8feb154 --- /dev/null +++ b/src/app/dashboard/trust/social/page.tsx @@ -0,0 +1,117 @@ +'use client'; + +import { useMemo } from 'react'; +import { useQuery } 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; tags: string[]; consentStatus: string | null; createdAt: string; } +interface Observation { id: string; metric: string; value: string; subjectType: string; confidence: number | null; createdAt: string; } + +const NETWORK_TAGS = ['mentor', 'investor', 'partner', 'advisors', 'advisor', 'board', 'collaborator', 'client', 'client-key']; +const MONTHS_12 = Array.from({ length: 12 }, (_, i) => { + const d = new Date(); + d.setMonth(d.getMonth() - (11 - i)); + return d.toISOString().slice(0, 7); +}); + +export default function TrustSocialPage() { + const { activeTenant } = useSession(); + const tenantId = activeTenant?.tenantId ?? ''; + + const { data: contacts = [] } = useQuery({ queryKey: ['ts-contacts', tenantId], queryFn: () => apiFetch('/v1/contacts?limit=500', { tenantId }), enabled: Boolean(tenantId), staleTime: 120_000 }); + const { data: observations = [] } = useQuery({ queryKey: ['ts-obs', tenantId], queryFn: () => apiFetch('/v1/observations', { tenantId }), enabled: Boolean(tenantId), staleTime: 120_000 }); + + const stats = useMemo(() => { + const networkContacts = contacts.filter((c) => c.tags.some((t) => NETWORK_TAGS.includes(t.toLowerCase()))); + const consentGranted = contacts.filter((c) => c.consentStatus === 'granted'); + const mentors = contacts.filter((c) => c.tags.some((t) => t.toLowerCase() === 'mentor')); + const investors = contacts.filter((c) => c.tags.some((t) => ['investor','investitor'].includes(t.toLowerCase()))); + const partners = contacts.filter((c) => c.tags.some((t) => ['partner','partener'].includes(t.toLowerCase()))); + const clients = contacts.filter((c) => c.tags.some((t) => t.toLowerCase().startsWith('client'))); + + const socialObs = observations.filter((o) => o.subjectType === 'relationship' || o.metric.toLowerCase().includes('relat') || o.metric.toLowerCase().includes('network')); + + const growthByMonth = MONTHS_12.map((m) => ({ + month: m, + count: contacts.filter((c) => c.createdAt.startsWith(m)).length, + })); + const maxCount = Math.max(...growthByMonth.map((g) => g.count), 1); + + return { networkContacts, consentGranted, mentors, investors, partners, clients, socialObs, growthByMonth, maxCount }; + }, [contacts, observations]); + + return ( +
+
+ +

Reputație Socială & Rețea

+

Calitatea și diversitatea rețelei de relații profesionale.

+
+ + {/* KPIs */} +
+
+

{contacts.length}

+

contacte totale

+
+
+

{stats.networkContacts.length}

+

rețea profesională

+
+
+

{stats.consentGranted.length}

+

consimțite GDPR

+
+
+

{stats.socialObs.length}

+

obs. relații

+
+
+ + {/* Network breakdown */} +
+

Compoziția rețelei

+ {[ + { label: 'Mentori', count: stats.mentors.length, icon: '🧭' }, + { label: 'Investitori', count: stats.investors.length, icon: '💰' }, + { label: 'Parteneri', count: stats.partners.length, icon: '🤝' }, + { label: 'Clienți', count: stats.clients.length, icon: '🎯' }, + ].map((cat) => ( +
+ {cat.icon} +
+
+

{cat.label}

+ {cat.count} +
+
+
0 ? `${(cat.count / contacts.length) * 100}%` : '0%' }} /> +
+
+
+ ))} +
+ + {/* Growth chart */} +
+

Creștere rețea (12 luni)

+
+ {stats.growthByMonth.map((g) => ( +
+
0 ? '4px' : '0' }} /> +

{g.month.slice(5)}

+
+ ))} +
+
+ + ← Toate relațiile +
+ ); +}