"use client"; import React, { useEffect, useState } from "react"; import dynamic from "next/dynamic"; import useSWR from "swr"; import { useRouter } from "next/navigation"; import { useTranslations } from "next-intl"; import axios from "@/lib/axios"; import { BarChart3, Users, FileText, AlertCircle, Activity, Clock, Wifi, WifiOff, Server, CheckCircle, MessageSquare, Download, LogIn, UserPlus, Trash2, FilePlus, Image as ImageIcon } from "lucide-react"; import Image from "next/image"; import echo from "@/lib/echo"; import PageLoader from "@/components/ui/PageLoader"; import Tooltip from "@/components/ui/Tooltip"; import { getUserAvatar } from "@/lib/utils"; const Chart = dynamic(() => import("react-apexcharts"), { ssr: false }); const getActivityIcon = (action: string) => { switch (action) { case 'login': return ; case 'register': return ; case 'issue_cert': return ; case 'delete_cert': return ; case 'create_ticket': return ; case 'reply_ticket': return ; case 'close_ticket': return ; default: return ; } }; const fetcher = (url: string) => axios.get(url).then((res) => res.data); export default function DashboardClient() { const t = useTranslations("Dashboard"); const { data, error, isLoading, mutate } = useSWR("/api/dashboard", fetcher, { refreshInterval: 0, // Disable auto polling, rely on WS or manual refresh }); const router = useRouter(); const { data: userData } = useSWR("/api/user", fetcher); const user = userData; useEffect(() => { if (user?.default_landing_page && user.default_landing_page !== '/dashboard') { router.push(user.default_landing_page); } }, [user, router]); const [wsStatus, setWsStatus] = useState<"connected" | "disconnected" | "connecting">("connecting"); const [apiLatency, setApiLatency] = useState(null); const [wsLatency, setWsLatency] = useState("Unknown"); const stats = data?.data?.stats; const activity = data?.data?.recent_activity; const chartData = data?.data?.chart_data; // Realtime & Latency Logic useEffect(() => { if (!echo) return; // WebSocket Status if (echo.connector.pusher.connection.state === 'connected') { setWsStatus('connected'); } echo.connector.pusher.connection.bind('connected', () => { setWsStatus('connected'); setWsLatency("Active"); }); echo.connector.pusher.connection.bind('disconnected', () => { setWsStatus('disconnected'); }); echo.connector.pusher.connection.bind('connecting', () => { setWsStatus('connecting'); }); // Listen for global dashboard updates if implemented // echo.channel('dashboard').listen('.DashboardUpdated', () => { mutate(); }); return () => { // cleanup if needed }; }, []); // API Latency Check const checkApiLatency = async () => { const start = performance.now(); try { await axios.get('/api/dashboard/ping'); const end = performance.now(); setApiLatency(Math.round(end - start)); } catch (e) { setApiLatency(null); } }; useEffect(() => { checkApiLatency(); const interval = setInterval(checkApiLatency, 1000); // Check every 1s (Realtime-like) return () => clearInterval(interval); }, []); if (isLoading) return ; if (error) return
{t('error_loading')}
; // Chart Configuration const chartOptions: any = { colors: ["#465fff"], chart: { fontFamily: "inherit", type: "area", height: 310, toolbar: { show: false }, }, stroke: { curve: "smooth", width: 2 }, fill: { type: "gradient", gradient: { shadeIntensity: 1, opacityFrom: 0.45, opacityTo: 0.05, stops: [0, 80, 100], }, }, dataLabels: { enabled: false }, grid: { borderColor: "#e5e7eb", strokeDashArray: 3, xaxis: { lines: { show: false } }, }, xaxis: { categories: chartData?.map((d: any) => d.day) || [], axisBorder: { show: false }, axisTicks: { show: false }, }, yaxis: { labels: { formatter: (val: number) => Math.floor(val) } }, tooltip: { x: { format: "dd/MM/yy HH:mm" }, }, }; const chartSeries = [ { name: t("issued_certs"), data: chartData?.map((d: any) => d.count) || [], }, ]; return (

{t("overview")}

{t("metrics_health")}

{/* System Health Indicators */}
{wsStatus === 'connected' ? : } {t("ws_status")}: {wsStatus === 'connected' ? t("live") : t("offline")}
{t("api_status")}: {apiLatency !== null ? `${apiLatency}ms` : 'N/A'}
{/* Stats Grid */}
{/* Certificate Stats */} } /> } /> } footer={stats?.expired_certificates?.value > 0 ? t("action_needed") : t("all_good")} alert={stats?.expired_certificates?.value > 0} /> } />
{/* Admin Extra Stats (Conditional Render in real app, filtering here for demo) */} {stats?.total_users !== undefined && (
} /> } alert={stats.pending_inquiries?.value > 0} footer={stats.pending_inquiries?.value > 0 ? t("response_required") : t("no_new_messages")} />
)} {/* CA Download Stats (Admin Only) */} {stats?.ca_downloads_root !== undefined && (

{t("ca_downloads")}

} footer={t("global_trust_root")} /> } footer={t("standard_issuance")} /> } footer={t("high_security")} />
)} {/* Log / Activity Section */}

{t("recent_activity")}

{activity && activity.length > 0 ? (
{activity.map((item: any, i: number) => (
{getActivityIcon(item.action)}

{item.user_name} {item.description || item.action}

{new Date(item.created_at).toLocaleString()}

))}
) : (

{t("no_activity")}

)}

{t("certificate_trends")}

{t("last_7_days")}
); } // Subcomponents function StatsCard({ title, value, icon, trend, trendLabel, footer, alert }: any) { const t = useTranslations("Dashboard"); const isPositive = typeof trend === 'number' ? trend >= 0 : false; const trendValue = typeof trend === 'number' ? `${isPositive ? '+' : ''}${trend}%` : trend; // Determine the value to display const displayValue = typeof value === 'object' ? value.value : value; // Determine trend data from value object or props const effectiveTrend = value?.trend !== undefined ? value.trend : trend; const effectiveTrendLabel = value?.trend_label !== undefined ? value.trend_label : trendLabel; return (

{title}

{displayValue}

{icon}
{/* Dynamic Bottom Section - Standardized Layout */} {(effectiveTrend !== undefined || footer) && (
= 0) ? 'text-green-500' : 'text-red-500' }`}> {footer ? ( // Custom Footer (replaces trend) {footer} ) : ( // Standard Trend <> {typeof effectiveTrend === 'number' && effectiveTrend > 0 ? '+' : ''} {effectiveTrend}% {effectiveTrendLabel || t("vs_last_month")} )}
)} {/* Fallback for cards with NO footer/trend to keep height consistent (optional, removed for now as not requested) */}
); }