import React, { useEffect, useState } from "react"; import { format } from "date-fns"; import { Input } from "@/shared/common/ui/input"; import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, } from "@/shared/common/ui/select"; import { Button } from "@/shared/common/ui/button"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/shared/common/ui/table"; import { CollectionQueryDTO, fetchAuditLogs } from "@/user-management/services/api/auditService"; import { useTranslation } from "react-i18next"; import { useLocalizedName } from "@/shared/common/localizedName"; interface AuditLogItem { id: string; user: string | { id: string; name: string; email?: string; phone?: string; position?: string; userType?: string; employeeId?: string; employeePositionId?: string }; action: string; message: string; timestamp: string; } const AuditLog: React.FC = () => { const {t} = useTranslation() const [logs, setLogs] = useState([]); const [loading, setLoading] = useState(false); const [search, setSearch] = useState(""); const [sort, setSort] = useState("timestamp:DESC"); const [dateRange, setDateRange] = useState<{ start?: string; end?: string }>({}); const [page, setPage] = useState(1); const [total, setTotal] = useState(0); const [status, setStatus] = useState("") const localizedName = useLocalizedName() const pageSize = 10; const statuses = [ { status: "Draft", color: "bg-gray-200", detail: t("landingPage.notForwarded"), }, { status: "Submitted", color: "bg-purple-100", detail: t("landingPage.awaiting"), }, { status: "Accepted", color: "bg-primary-100", detail: t("landingPage.accepted"), }, { status: "Approved", color: "bg-primary-200", detail: t("landingPage.approvedSent"), }, { status: "Adjustment", color: "bg-yellow-100", detail: t("landingPage.returned"), }, { status: "Rejected", color: "bg-red-100", detail: t("landingPage.rejected"), }, { status: "Sent", color: "bg-primary-300", detail: t("landingPage.sent") }, { status: "Returned", color: "bg-gray-400", detail: t("landingPage.returnedByOfficer"), }, ]; const buildQuery = (): CollectionQueryDTO => { const query: CollectionQueryDTO = { s: "id,user,action,message,timestamp", o: sort, t: pageSize, sk: (page - 1) * pageSize, }; const where: string[] = []; if (search) where.push(`message:ILIKE:%${search}%`); if (status) where.push(`status:=:${status}`); if (status && status !== "all") where.push(`status:=:${status}`); if (dateRange.start && dateRange.end) where.push(`timestamp:>=:${dateRange.start}|timestamp:<=:${dateRange.end}`); if (where.length) query.w = where.join("|"); return query; }; const fetchLogs = async () => { setLoading(true); try { const result = await fetchAuditLogs(buildQuery()); setLogs(result.items); setTotal(result.total ?? 0); } catch (err) { console.error(err); setLogs([]); } finally { setLoading(false); } }; useEffect(() => { fetchLogs(); }, [search, sort, dateRange, page]); return (

Audit Logs

{/* Filter Bar */}
setSearch(e.target.value)} className="w-64" />
setDateRange({ ...dateRange, start: e.target.value }) } /> to setDateRange({ ...dateRange, end: e.target.value }) } />
{/* ✅ Status Dropdown */}
{/* Table */}
User Action Message Timestamp {loading ? ( Loading logs... ) : logs.length > 0 ? ( logs.map((log) => ( {typeof log.user === "string" ? log.user : typeof log.user?.name === "string" ? log.user.name : localizedName(log.user?.name) || "Unknown"} {log.action} {log.message} {log.timestamp && !isNaN(new Date(log.timestamp).getTime()) ? format(new Date(log.timestamp), "yyyy-MM-dd HH:mm:ss") : "N/A"} )) ) : ( No logs found )}
{/* Pagination */}
Page {page} of {Math.ceil(total / pageSize) || 1}
); }; export default AuditLog;