'use client'; import Link from 'next/link'; import { useQuery } from '@tanstack/react-query'; import { apiFetch } from '../../../../lib/api'; import type { Goal, Decision, Task } from '../../../../lib/api'; import { useSession } from '../../../../components/session-provider'; const B = '/dashboard'; interface Organization { id: string; name: string; country?: string | null; createdAt: string; } interface Opportunity { id: string; source: string; probability?: string | null; expiresAt?: string | null; } function StatCard({ label, value, sub, href, color = 'text-ink' }: { label: string; value: number | string; sub?: string; href?: string; color?: string; }) { const inner = (

{label}

{value}

{sub &&

{sub}

}
); return href ? {inner} : inner; } function ProgressBar({ value, total, color = 'bg-primary' }: { value: number; total: number; color?: string }) { const pct = total > 0 ? Math.round((value / total) * 100) : 0; return (
{pct}%
); } export default function BusinessReportsPage() { const { activeTenant } = useSession(); const tenantId = activeTenant?.tenantId ?? ''; const opts = { enabled: Boolean(tenantId), staleTime: 120_000 }; const { data: orgs = [] } = useQuery({ queryKey: ['rep-orgs', tenantId], queryFn: () => apiFetch('/v1/organizations', { tenantId }), ...opts, }); const { data: tasks = [] } = useQuery({ queryKey: ['rep-tasks', tenantId], queryFn: () => apiFetch('/v1/tasks', { tenantId }), ...opts, }); const { data: goals = [] } = useQuery({ queryKey: ['rep-goals', tenantId], queryFn: () => apiFetch('/v1/goals', { tenantId }), ...opts, }); const { data: decisions = [] } = useQuery({ queryKey: ['rep-decisions', tenantId], queryFn: () => apiFetch('/v1/decisions', { tenantId }), ...opts, }); const { data: opps = [] } = useQuery({ queryKey: ['rep-opps', tenantId], queryFn: () => apiFetch('/v1/opportunities', { tenantId }), ...opts, }); // Task stats const taskDone = tasks.filter((t) => t.status === 'done').length; const taskOpen = tasks.filter((t) => t.status === 'open').length; const taskInProg = tasks.filter((t) => t.status === 'in_progress').length; const taskBlocked = tasks.filter((t) => t.status === 'blocked').length; const taskRate = tasks.length > 0 ? Math.round((taskDone / tasks.length) * 100) : 0; // Goal stats const goalAchieved = goals.filter((g) => g.status === 'achieved').length; const goalOnTrack = goals.filter((g) => g.status === 'on_track').length; const goalAtRisk = goals.filter((g) => g.status === 'at_risk').length; const goalNotStart = goals.filter((g) => g.status === 'not_started').length; // Decision stats const decDecided = decisions.filter((d) => d.selectedOption).length; const decPending = decisions.filter((d) => !d.selectedOption).length; const decWithReview = decisions.filter((d) => d.outcomeReview).length; // Opportunity stats const now = new Date(); const oppsActive = opps.filter((o) => !o.expiresAt || new Date(o.expiresAt) > now).length; const oppsExpiring = opps.filter((o) => { if (!o.expiresAt) return false; const exp = new Date(o.expiresAt); const in7 = new Date(now.getTime() + 7 * 86400_000); return exp > now && exp <= in7; }).length; // Recent orgs (last 30 days) const in30 = new Date(now.getTime() - 30 * 86400_000); const recentOrgs = orgs.filter((o) => new Date(o.createdAt) > in30).length; return (

Raport Business

Metrici cheie — organizații, taskuri, obiective, decizii, oportunități

{/* KPI grid */}
0 ? 'text-signal-warn' : 'text-ink'} /> 0 ? `${oppsExpiring} expiră curând` : 'toate active'} href={`${B}/opportunities`} color={oppsExpiring > 0 ? 'text-signal-warn' : 'text-ink'} />
{/* Tasks breakdown */}

Taskuri

Deschide →
{[ { label: 'Finalizate', count: taskDone, color: 'bg-signal-ok' }, { label: 'În progres', count: taskInProg, color: 'bg-primary' }, { label: 'Deschise', count: taskOpen, color: 'bg-amber-400' }, { label: 'Blocate', count: taskBlocked, color: 'bg-signal-danger' }, ].map(({ label, count, color }) => (
{label} {count}
))}
Rată completare {taskRate}%
{/* Goals + Decisions in 2 cols */}
{/* Goals breakdown */}

Obiective

Deschide →
{goals.length === 0 ? (

Niciun obiectiv înregistrat

) : (
{[ { label: 'Realizate', count: goalAchieved, cls: 'text-signal-ok' }, { label: 'Pe plan', count: goalOnTrack, cls: 'text-primary' }, { label: 'Neîncepute', count: goalNotStart, cls: 'text-ink-faint' }, { label: 'La risc', count: goalAtRisk, cls: 'text-signal-warn' }, ].map(({ label, count, cls }) => (
{label} {count}
))}
)}
{/* Decisions breakdown */}

Decizii

Deschide →
{decisions.length === 0 ? (

Nicio decizie înregistrată

) : (
{[ { label: 'Total decizii', count: decisions.length, cls: 'text-ink' }, { label: 'Pronunțate', count: decDecided, cls: 'text-signal-ok' }, { label: 'În analiză', count: decPending, cls: 'text-signal-warn' }, { label: 'Cu review', count: decWithReview, cls: 'text-primary' }, ].map(({ label, count, cls }) => (
{label} {count}
))}
)}
{/* Recent organizations */} {orgs.length > 0 && (

Organizații recente

{orgs.slice(0, 8).map((org) => (

{org.name}

{org.country &&

{org.country}

}

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

))}
{orgs.length > 8 && ( Vezi toate {orgs.length} organizații → )}
)}
); }