Files
lcbp3/frontend/app/(admin)/admin/audit-logs/page.tsx
admin 18f78f8a5e
Some checks failed
Spec Validation / validate-markdown (push) Has been cancelled
Spec Validation / validate-diagrams (push) Has been cancelled
Spec Validation / check-todos (push) Has been cancelled
251205:0000 Just start debug backend/frontend
2025-12-05 00:32:02 +07:00

123 lines
3.8 KiB
TypeScript

"use client";
import { useState, useEffect } from "react";
import { Card } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Badge } from "@/components/ui/badge";
import { formatDistanceToNow } from "date-fns";
import { AuditLog } from "@/types/admin";
import { adminApi } from "@/lib/api/admin";
import { Loader2 } from "lucide-react";
export default function AuditLogsPage() {
const [logs, setLogs] = useState<AuditLog[]>([]);
const [loading, setLoading] = useState(true);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [filters, setFilters] = useState({
user: "",
action: "",
entity: "",
});
useEffect(() => {
const fetchLogs = async () => {
setLoading(true);
try {
const data = await adminApi.getAuditLogs();
setLogs(data);
} catch (error) {
console.error("Failed to fetch audit logs", error);
} finally {
setLoading(false);
}
};
fetchLogs();
}, []);
return (
<div className="p-6 space-y-6">
<div>
<h1 className="text-3xl font-bold">Audit Logs</h1>
<p className="text-muted-foreground mt-1">View system activity and changes</p>
</div>
{/* Filters */}
<Card className="p-4">
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<div>
<Input placeholder="Search user..." />
</div>
<div>
<Select>
<SelectTrigger>
<SelectValue placeholder="Action" />
</SelectTrigger>
<SelectContent>
<SelectItem value="CREATE">Create</SelectItem>
<SelectItem value="UPDATE">Update</SelectItem>
<SelectItem value="DELETE">Delete</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Select>
<SelectTrigger>
<SelectValue placeholder="Entity Type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="correspondence">Correspondence</SelectItem>
<SelectItem value="rfa">RFA</SelectItem>
<SelectItem value="user">User</SelectItem>
</SelectContent>
</Select>
</div>
</div>
</Card>
{/* Logs List */}
{loading ? (
<div className="flex justify-center py-12">
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
</div>
) : (
<div className="space-y-2">
{logs.map((log) => (
<Card key={log.audit_log_id} className="p-4">
<div className="flex items-start justify-between">
<div className="flex-1">
<div className="flex items-center gap-3 mb-2">
<span className="font-medium">{log.user_name}</span>
<Badge variant={log.action === "CREATE" ? "default" : "secondary"}>
{log.action}
</Badge>
<Badge variant="outline">{log.entity_type}</Badge>
</div>
<p className="text-sm text-muted-foreground">{log.description}</p>
<p className="text-xs text-muted-foreground mt-2">
{formatDistanceToNow(new Date(log.created_at), {
addSuffix: true,
})}
</p>
</div>
{log.ip_address && (
<span className="text-xs text-muted-foreground bg-muted px-2 py-1 rounded">
IP: {log.ip_address}
</span>
)}
</div>
</Card>
))}
</div>
)}
</div>
);
}