"use client"; import DashboardLayout from "@/components/DashboardLayout"; import SearchField from "@/components/SearchField"; import TablePagination from "@/components/TablePagination"; import { logs as logsApi, type AuditLog } from "@/lib/api"; import { useEffect, useState } from "react"; import { Activity, Clock, Download, Server, Container, Globe, Shield, Terminal, } from "lucide-react"; const PAGE_SIZE = 10; const categoryIcons: Record = { container: Container, server: Server, ssl: Shield, security: Shield, domain: Globe, terminal: Terminal, auth: Shield, system: Activity, }; const typeColors: Record = { success: { bg: "rgba(16,185,129,0.1)", color: "#10b981", label: "Success" }, info: { bg: "rgba(59,130,246,0.1)", color: "#3b82f6", label: "Info" }, warning: { bg: "rgba(245,158,11,0.1)", color: "#f59e0b", label: "Warning" }, error: { bg: "rgba(239,68,68,0.1)", color: "#ef4444", label: "Error" }, }; const levelMap: Record = { all: undefined, success: "SUCCESS", info: "INFO", warning: "WARNING", error: "ERROR", }; const categoryMap: Record = { all: undefined, auth: "AUTH", server: "SERVER", container: "CONTAINER", domain: "DOMAIN", ssl: "SSL", security: "SECURITY", system: "SYSTEM", terminal: "TERMINAL", }; function formatTimestamp(value: string) { const date = new Date(value); if (Number.isNaN(date.getTime())) { return "Unknown time"; } return date.toLocaleString("id-ID", { year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit", }); } function normalizeLevel(level: string) { return level.toLowerCase(); } function normalizeCategory(category: string) { return category.toLowerCase(); } export default function ActivityPage() { const [logs, setLogs] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); const [search, setSearch] = useState(""); const [typeFilter, setTypeFilter] = useState("all"); const [categoryFilter, setCategoryFilter] = useState("all"); const [currentPage, setCurrentPage] = useState(1); const [totalItems, setTotalItems] = useState(0); useEffect(() => { setCurrentPage(1); }, [search, typeFilter, categoryFilter]); useEffect(() => { let cancelled = false; async function loadLogs() { setLoading(true); setError(""); try { const response = await logsApi.list({ search: search.trim() || undefined, level: levelMap[typeFilter], category: categoryMap[categoryFilter], limit: PAGE_SIZE, offset: (currentPage - 1) * PAGE_SIZE, }); if (cancelled) return; setLogs(response.data ?? []); setTotalItems(response.total ?? 0); } catch (err) { if (cancelled) return; setLogs([]); setTotalItems(0); setError( err instanceof Error ? err.message : "Failed to load activity logs", ); } finally { if (!cancelled) { setLoading(false); } } } void loadLogs(); return () => { cancelled = true; }; }, [search, typeFilter, categoryFilter, currentPage]); const totalPages = Math.max(1, Math.ceil(totalItems / PAGE_SIZE)); const startItem = totalItems === 0 ? 0 : (currentPage - 1) * PAGE_SIZE + 1; const endItem = totalItems === 0 ? 0 : Math.min(currentPage * PAGE_SIZE, totalItems); useEffect(() => { if (currentPage > totalPages) { setCurrentPage(totalPages); } }, [currentPage, totalPages]); return (
{/* Toolbar */}
setSearch(e.target.value)} containerStyle={{ flex: "1 1 280px", minWidth: 220, maxWidth: 420 }} />
{["all", "success", "info", "warning", "error"].map((f) => ( ))}
{[ "all", "auth", "container", "server", "domain", "ssl", "security", "system", "terminal", ].map((c) => ( ))}
{/* Log table */}
{loading && ( )} {!loading && error && ( )} {!loading && !error && logs.length === 0 && ( )} {!loading && !error && logs.map((log) => { const normalizedType = normalizeLevel(log.level); const normalizedCategory = normalizeCategory(log.category); const type = typeColors[normalizedType] ?? typeColors.info; const CatIcon = categoryIcons[normalizedCategory] || Activity; return ( ); })}
Time Status Category Server Message User
Loading activity logs...
{error}
No activity logs found.
{formatTimestamp(log.createdAt)} {type.label}
{normalizedCategory}
{log.server?.name ?? "System"} {log.message} {log.user?.name ?? "system"}
{/* {totalItems === 0 ? "Showing 0 of 0 events" : `Showing ${startItem}-${endItem} of ${totalItems} events`} */}
Live monitoring active
); }