'use client'; import React, { useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import { RootState } from '@/store/store'; import { BarChart3, Users, FileText, TrendingUp, Clock, AlertTriangle, CheckCircle2, Loader2, Cpu, Zap, } from 'lucide-react'; import { Card } from '@/components/ui/card'; import { getHeader } from '@/app/(presentation-generator)/services/api/header'; import { cn } from '@/lib/utils'; interface OverviewData { total_presentations: number; this_month: number; this_week: number; active_users: number; approval_rate: number; } interface UsageData { daily: { date: string; count: number }[]; top_users: { user_id: string; count: number }[]; } interface QualityData { status_distribution: Record; presentations_with_comments: number; } interface PerformanceData { job_status_distribution: Record; avg_generation_time_seconds: number | null; error_rate: number; total_jobs: number; } interface AIUsageData { total_calls: number; total_input_tokens: number; total_output_tokens: number; total_tokens: number; by_provider: { provider: string; calls: number; tokens: number }[]; by_model: { model: string; calls: number; tokens: number }[]; daily: { date: string; calls: number; tokens: number }[]; } async function fetchAnalytics(endpoint: string, clientId?: string) { const params = clientId ? `?client_id=${clientId}` : ''; const response = await fetch(`/api/v1/admin/analytics/${endpoint}${params}`, { headers: getHeader(), }); if (!response.ok) throw new Error(`Failed to fetch ${endpoint}`); return response.json(); } function StatCard({ title, value, icon: Icon, subtitle, color = 'text-[hsl(var(--primary))]', }: { title: string; value: string | number; icon: React.ElementType; subtitle?: string; color?: string; }) { return (

{title}

{value}

{subtitle &&

{subtitle}

}
); } function MiniBarChart({ data }: { data: { date: string; count: number }[] }) { if (!data.length) return

No data

; const max = Math.max(...data.map((d) => d.count), 1); const last14 = data.slice(-14); return (
{last14.map((d, i) => (
0 ? 4 : 0 }} /> {d.date.slice(5)}
))}
); } function StatusBar({ distribution }: { distribution: Record }) { const total = Object.values(distribution).reduce((a, b) => a + b, 0); if (total === 0) return

No data

; const colors: Record = { draft: 'bg-yellow-400', in_review: 'bg-blue-400', approved: 'bg-green-400', }; return (
{Object.entries(distribution).map(([status, count]) => (
))}
{Object.entries(distribution).map(([status, count]) => (
{status.replace('_', ' ')} ({count})
))}
); } function formatTokens(n: number): string { if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`; if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`; return String(n); } export default function AnalyticsPage() { const user = useSelector((state: RootState) => state.auth.user); const [overview, setOverview] = useState(null); const [usage, setUsage] = useState(null); const [quality, setQuality] = useState(null); const [performance, setPerformance] = useState(null); const [aiUsage, setAiUsage] = useState(null); const [isLoading, setIsLoading] = useState(true); // Auto-filter by user's clientId const clientId = user?.clientId || undefined; useEffect(() => { if (!user) return; loadAll(); }, [user?.clientId]); const loadAll = async () => { setIsLoading(true); try { const [o, u, q, p, ai] = await Promise.all([ fetchAnalytics('overview', clientId), fetchAnalytics('usage', clientId), fetchAnalytics('quality', clientId), fetchAnalytics('performance', clientId), fetchAnalytics('ai-usage', clientId).catch(() => null), ]); setOverview(o); setUsage(u); setQuality(q); setPerformance(p); setAiUsage(ai); } catch (e) { console.error('Analytics load error:', e); } finally { setIsLoading(false); } }; if (isLoading && !overview) { return (
); } return (

Analytics

{/* Overview Cards */} {overview && (
)} {/* Charts Row */}

Presentations per Day

{usage ? :

Loading...

}

Status Distribution

{quality ? ( ) : (

Loading...

)}
{/* Performance Row */} {performance && (
10 ? 'text-red-600' : 'text-green-600'} />
)} {/* AI Usage Section */} {aiUsage && ( <>

AI Model Usage

{aiUsage.by_provider.length > 0 && (

Usage by Provider

{aiUsage.by_provider.map((p) => { const maxCalls = Math.max(...aiUsage.by_provider.map((x) => x.calls), 1); return (
{p.provider}
{p.calls} calls
{formatTokens(p.tokens)} tokens
); })}
)} )} {/* Top Users */} {usage && usage.top_users.length > 0 && (

Top Users (Last 30 Days)

{usage.top_users.map((u, i) => { const maxCount = usage.top_users[0].count || 1; return (
{i + 1}.
{u.user_id.slice(0, 8)}...
{u.count}
); })}
)}
); }