diff --git a/src/app/dashboard/trust/professional/page.tsx b/src/app/dashboard/trust/professional/page.tsx new file mode 100644 index 0000000..5f43f28 --- /dev/null +++ b/src/app/dashboard/trust/professional/page.tsx @@ -0,0 +1,146 @@ +'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 Goal { id: string; title: string; status: string; progress: number | null; tags: string[]; createdAt: string; updatedAt: string; } +interface Task { id: string; title: string; status: string; priority: string | null; tags: string[]; createdAt: string; } +interface Decision { id: string; title: string; impact: string | null; rationale: string | null; tags: string[]; createdAt: string; } +interface Contract { id: string; title: string; status: string; value: number | null; currency: string | null; counterpartyName: string | null; } + +export default function TrustProfessionalPage() { + const { activeTenant } = useSession(); + const tenantId = activeTenant?.tenantId ?? ''; + + const { data: goals = [] } = useQuery({ queryKey: ['tp-goals', tenantId], queryFn: () => apiFetch('/v1/goals?limit=200', { tenantId }), enabled: Boolean(tenantId), staleTime: 120_000 }); + const { data: tasks = [] } = useQuery({ queryKey: ['tp-tasks', tenantId], queryFn: () => apiFetch('/v1/tasks?limit=500', { tenantId }), enabled: Boolean(tenantId), staleTime: 120_000 }); + const { data: decisions = [] } = useQuery({ queryKey: ['tp-decisions', tenantId], queryFn: () => apiFetch('/v1/decisions?limit=200', { tenantId }), enabled: Boolean(tenantId), staleTime: 120_000 }); + const { data: contracts = [] } = useQuery({ queryKey: ['tp-contracts', tenantId], queryFn: () => apiFetch('/v1/contracts?limit=200', { tenantId }), enabled: Boolean(tenantId), staleTime: 120_000 }); + + const metrics = useMemo(() => { + const completedGoals = goals.filter((g) => g.status === 'completed'); + const activeGoals = goals.filter((g) => g.status === 'active'); + const completedTasks = tasks.filter((t) => t.status === 'completed'); + const urgentDone = completedTasks.filter((t) => t.priority === 'urgent'); + const docDecisions = decisions.filter((d) => d.rationale && d.rationale.length > 30); + const highImpact = decisions.filter((d) => ['high','critical'].includes(d.impact ?? '')); + const signedContracts = contracts.filter((c) => c.status === 'signed' || c.status === 'active'); + const totalValue = signedContracts.reduce((s, c) => s + (c.value ?? 0), 0); + + const goalCompletionRate = goals.length > 0 ? Math.round((completedGoals.length / goals.length) * 100) : 0; + const taskCompletionRate = tasks.length > 0 ? Math.round((completedTasks.length / tasks.length) * 100) : 0; + const decisionQuality = decisions.length > 0 ? Math.round((docDecisions.length / decisions.length) * 100) : 0; + + return { completedGoals, activeGoals, completedTasks, urgentDone, docDecisions, highImpact, signedContracts, totalValue, goalCompletionRate, taskCompletionRate, decisionQuality }; + }, [goals, tasks, decisions, contracts]); + + function scoreColor(s: number) { return s >= 70 ? 'text-signal-ok' : s >= 40 ? 'text-warn' : 'text-signal-danger'; } + function barColor(s: number) { return s >= 70 ? 'bg-signal-ok' : s >= 40 ? 'bg-warn' : 'bg-signal-danger'; } + + const INDICATORS = [ + { label: 'Rată finalizare obiective', score: metrics.goalCompletionRate, detail: `${metrics.completedGoals.length}/${goals.length} goals` }, + { label: 'Rată finalizare task-uri', score: metrics.taskCompletionRate, detail: `${metrics.completedTasks.length}/${tasks.length} tasks` }, + { label: 'Calitate decizii documentate', score: metrics.decisionQuality, detail: `${metrics.docDecisions.length}/${decisions.length} cu rațional` }, + ]; + + return ( +
+
+ +

Reputație Profesională

+

Indicatori derivați din execuție: obiective, taskuri, decizii, contracte.

+
+ + {/* KPI cards */} +
+
+

{metrics.completedGoals.length}

+

obiective finalizate

+
+
+

{metrics.activeGoals.length}

+

obiective active

+
+
+

{metrics.highImpact.length}

+

decizii high-impact

+
+
+

{metrics.signedContracts.length}

+

contracte active

+
+
+ + {/* Indicators */} +
+

Indicatori de performanță

+ {INDICATORS.map((ind) => ( +
+
+
+

{ind.label}

+

{ind.detail}

+
+ {ind.score}% +
+
+
+
+
+ ))} +
+ + {/* Recent completed goals */} + {metrics.completedGoals.length > 0 && ( +
+

Obiective finalizate recente

+
+ {metrics.completedGoals.slice(0, 8).map((g) => ( +
+ +

{g.title}

+ + {new Date(g.updatedAt).toLocaleDateString('ro-RO', { month: 'short', year: 'numeric' })} + +
+ ))} +
+ {metrics.completedGoals.length > 8 && ( + + +{metrics.completedGoals.length - 8} mai multe → + + )} +
+ )} + + {/* Contracts */} + {metrics.signedContracts.length > 0 && ( +
+

Contracte semnate / active

+
+ {metrics.signedContracts.slice(0, 6).map((c) => ( +
+

{c.title}

+
+ {c.counterpartyName && {c.counterpartyName}} + {c.value ? {c.value.toLocaleString()} {c.currency} : null} +
+
+ ))} +
+
+ )} + +
+ Obiective → + Decizii → + Contracte → +
+
+ ); +}