"use client"; import { useCallback, useEffect, useMemo, useState } from "react"; import Link from "next/link"; import { motion, AnimatePresence } from "motion/react"; import { Activity, AlertTriangle, ArrowRight, BarChart3, Brain, CheckCircle2, Clock3, Database, FileText, RefreshCw, Sparkles, TrendingUp, Zap, Shield, Fingerprint, ChevronRight, Tag, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Card } from "@/components/ui/card"; import { getStatsAction } from "@/features/analytics/api/stats.action"; import { checkDeadlineNotifications } from "@/features/notifications/api/notification.action"; import dynamic from "next/dynamic"; // Dynamically import heavy charting libraries to dramatically improve initial load and rendering time const ContractStatusChart = dynamic( () => import("@/features/analytics/components/charts").then( (mod) => mod.ContractStatusChart, ), { ssr: false, loading: () => (
), }, ); const ContractTypeChart = dynamic( () => import("@/features/analytics/components/charts").then( (mod) => mod.ContractTypeChart, ), { ssr: false, loading: () => (
), }, ); const TrendChart = dynamic( () => import("@/features/analytics/components/charts").then( (mod) => mod.TrendChart, ), { ssr: false, loading: () => (
), }, ); interface DashboardStats { totalContracts: number; analyzedContracts: number; processingContracts: number; uploadedContracts: number; failedContracts: number; analysisRate: number; } interface ChartData { byType: Array<{ type: string; count: number }>; byStatus: Array<{ status: string; count: number }>; trends: Array<{ date: string; count: number }>; } interface PremiumInfo { averagePremium: number; totalPremium: number; count: number; } interface RecentContract { id: string; title: string | null; type: string | null; createdAt: string; premium: number | null; } interface AILearningTelemetry { completedSamples: number; completedLast7Days: number; avgSummaryLength: number; avgExtractedTextLength: number; avgKeyPointsPerContract: number; learningScore: number; improvementHint: string; } interface StatsActionResult { success: boolean; stats?: DashboardStats; chartData?: ChartData; premiumInfo?: PremiumInfo; aiLearningTelemetry?: AILearningTelemetry; recentContracts?: RecentContract[]; error?: string; } const numberFormatter = new Intl.NumberFormat("en-US"); const currencyFormatter = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", maximumFractionDigits: 2, }); const defaultStats: DashboardStats = { totalContracts: 0, analyzedContracts: 0, processingContracts: 0, uploadedContracts: 0, failedContracts: 0, analysisRate: 0, }; const formatLastUpdated = (date: Date | null): string => { if (!date) { return "Just now"; } const seconds = Math.max(1, Math.floor((Date.now() - date.getTime()) / 1000)); if (seconds < 60) return `${seconds}s ago`; const minutes = Math.floor(seconds / 60); if (minutes < 60) return `${minutes}m ago`; const hours = Math.floor(minutes / 60); return `${hours}h ago`; }; const clampPercent = (value: number): number => Math.max(0, Math.min(100, value)); export default function DashboardPage() { const [stats, setStats] = useState(defaultStats); const [chartData, setChartData] = useState(null); const [premiumInfo, setPremiumInfo] = useState({ averagePremium: 0, totalPremium: 0, count: 0, }); const [recentContracts, setRecentContracts] = useState([]); const [aiLearningTelemetry, setAiLearningTelemetry] = useState({ completedSamples: 0, completedLast7Days: 0, avgSummaryLength: 0, avgExtractedTextLength: 0, avgKeyPointsPerContract: 0, learningScore: 0, improvementHint: "Analyze contracts to build your AI quality profile.", }); const [isLoading, setIsLoading] = useState(true); const [isRefreshing, setIsRefreshing] = useState(false); const [lastUpdated, setLastUpdated] = useState(null); const loadStats = useCallback(async (options?: { silent?: boolean }) => { const isSilentRefresh = options?.silent ?? false; if (isSilentRefresh) { setIsRefreshing(true); } else { setIsLoading(true); } try { const result = (await getStatsAction()) as StatsActionResult; if (!result.success) { return; } if (result.stats) setStats(result.stats); if (result.chartData) setChartData(result.chartData); if (result.premiumInfo) setPremiumInfo(result.premiumInfo); if (result.aiLearningTelemetry) { setAiLearningTelemetry(result.aiLearningTelemetry); } if (result.recentContracts) setRecentContracts(result.recentContracts); setLastUpdated(new Date()); } finally { if (isSilentRefresh) { setIsRefreshing(false); } else { setIsLoading(false); } } }, []); useEffect(() => { void loadStats(); // Check for upcoming contract deadlines and create notifications void checkDeadlineNotifications(); }, [loadStats]); useEffect(() => { if (stats.processingContracts === 0 && stats.uploadedContracts === 0) { return; } const intervalId = window.setInterval(() => { void loadStats({ silent: true }); }, 10000); return () => window.clearInterval(intervalId); }, [loadStats, stats.processingContracts, stats.uploadedContracts]); const hasChartData = useMemo(() => { if (!chartData) return false; const trendsCount = chartData.trends.reduce( (total, entry) => total + entry.count, 0, ); const byStatusCount = chartData.byStatus.reduce( (total, entry) => total + entry.count, 0, ); const byTypeCount = chartData.byType.reduce( (total, entry) => total + entry.count, 0, ); return trendsCount + byStatusCount + byTypeCount > 0; }, [chartData]); const pendingContracts = stats.processingContracts + stats.uploadedContracts; const analyzedPercent = stats.totalContracts > 0 ? clampPercent((stats.analyzedContracts / stats.totalContracts) * 100) : 0; const pendingPercent = stats.totalContracts > 0 ? clampPercent((pendingContracts / stats.totalContracts) * 100) : 0; const failedPercent = stats.totalContracts > 0 ? clampPercent((stats.failedContracts / stats.totalContracts) * 100) : 0; const statusRows = [ { label: "Uploaded", value: stats.uploadedContracts, colorClass: "bg-amber-500", icon: , }, { label: "Processing", value: stats.processingContracts, colorClass: "bg-blue-500", icon: , }, { label: "Analyzed", value: stats.analyzedContracts, colorClass: "bg-emerald-500", icon: , }, { label: "Failed", value: stats.failedContracts, colorClass: "bg-red-500", icon: , }, ]; if (isLoading) { return (
{[1, 2, 3].map((i) => (
))}
); } return (
{/* Ambient Background */}
{/* Hero Section */}
Performance Overview

Financial Contracts Analytics

A reliable command center for uploaded documents, AI analysis throughput, and portfolio quality across your BFSI workflow.

Live metrics {isRefreshing ? "Syncing..." : `Updated ${formatLastUpdated(lastUpdated)}`}
{/* Pipeline Snapshot Card */}

Pipeline Snapshot

{numberFormatter.format(stats.totalContracts)}{" "} files

Analyzed

{numberFormatter.format(stats.analyzedContracts)}

Pending

{numberFormatter.format(pendingContracts)}

{/* Bento Stats Grid */} } label="Total Files" value={numberFormatter.format(stats.totalContracts)} subtitle="Uploaded into your workspace" gradient="from-primary/20 to-primary/5" border="border-primary/20" iconColor="text-primary" delay={0} /> } label="Analyzed" value={numberFormatter.format(stats.analyzedContracts)} subtitle="Completed by AI pipeline" gradient="from-emerald-500/20 to-emerald-500/5" border="border-emerald-500/20" iconColor="text-emerald-500" progress={analyzedPercent} progressColor="bg-emerald-500" delay={0.05} /> } label="Pending Queue" value={numberFormatter.format(pendingContracts)} subtitle="Uploaded and processing files" gradient="from-amber-500/20 to-amber-500/5" border="border-amber-500/20" iconColor="text-amber-500" progress={pendingPercent} progressColor="bg-amber-500" delay={0.1} /> } label="Failed" value={numberFormatter.format(stats.failedContracts)} subtitle="Items needing re-analysis" gradient="from-red-500/20 to-red-500/5" border="border-red-500/20" iconColor="text-red-500" progress={failedPercent} progressColor="bg-red-500" delay={0.15} /> {/* Pipeline Pulse + Premium Info */}

Pipeline Pulse

{statusRows.map((row) => { const rowPercent = stats.totalContracts > 0 ? clampPercent((row.value / stats.totalContracts) * 100) : 0; return (
{row.icon} {row.label}

{numberFormatter.format(row.value)}

); })}

Success Rate

{stats.analysisRate}%

Completed vs total files

Avg Premium

{currencyFormatter.format(premiumInfo.averagePremium)}

Across {numberFormatter.format(premiumInfo.count)} analyzed files

Total Premium

{currencyFormatter.format(premiumInfo.totalPremium)}

Portfolio value captured by AI

{/* AI Learning Telemetry */}

AI Learning Telemetry

Score {aiLearningTelemetry.learningScore}/100
{[ { label: "Completed Samples", value: numberFormatter.format( aiLearningTelemetry.completedSamples, ), sub: `${numberFormatter.format(aiLearningTelemetry.completedLast7Days)} in last 7 days`, icon: , color: "emerald", }, { label: "Avg Summary Length", value: numberFormatter.format( aiLearningTelemetry.avgSummaryLength, ), sub: "characters", icon: , color: "primary", }, { label: "Avg Extracted Text", value: numberFormatter.format( aiLearningTelemetry.avgExtractedTextLength, ), sub: "characters", icon: , color: "blue", }, { label: "Avg Key Points", value: aiLearningTelemetry.avgKeyPointsPerContract.toFixed(1), sub: "items per analysis", icon: , color: "violet", }, ].map((item) => (
{item.icon}

{item.label}

{item.value}

{item.sub}

))}
Learning quality index {aiLearningTelemetry.learningScore}%

{aiLearningTelemetry.improvementHint}

{hasChartData ? ( {chartData && chartData.trends.length > 0 && (

Upload Trend (30 days)

)} {chartData && chartData.byStatus.length > 0 && (

Processing Status

({ ...s, name: s.status, }))} />
)} {chartData && chartData.byType.length > 0 && (

Contract Type Distribution

)}

Recent Analyses

{recentContracts.length > 0 ? (
{recentContracts.map((contract, idx) => (

{contract.title || "Untitled contract"}

{contract.type || "Unknown type"} {new Date(contract.createdAt).toLocaleDateString( "en-US", { month: "short", day: "numeric", }, )}

Premium:{" "} {contract.premium !== null ? currencyFormatter.format(contract.premium) : "Not detected"}

))}
) : (

No recent analyses yet

Analyze a contract to populate this activity feed.

)} ) : (

Your analytics will appear here

Upload and analyze contracts to unlock trend and distribution charts.

)}
); } // ───────────────────────────────────────────────── // Bento Stat Sub-Component // ───────────────────────────────────────────────── function BentoStat({ icon, label, value, subtitle, gradient, border, iconColor, progress, progressColor, delay, }: { icon: React.ReactNode; label: string; value: string; subtitle: string; gradient: string; border: string; iconColor: string; progress?: number; progressColor?: string; delay: number; }) { return (
{icon}

{label}

{value}

{subtitle}

{progress !== undefined && (
)}
); }