"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")} {t("view_all")} {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) */} ); }
{t("metrics_health")}
{item.user_name} {item.description || item.action}
{new Date(item.created_at).toLocaleString()}
{t("no_activity")}
{title}