// assets/js/pages/admin/tabs/AuditLogTab.js const AuditLogTab = ({ state, handlers }) => { const { filteredAuditLogs, // Data yang ditampilkan (sekarang langsung dari API) auditLogSearchTerm, setAuditLogSearchTerm, auditLogActionFilter, setAuditLogActionFilter, auditLogUserFilter, setAuditLogUserFilter, auditLogDateFilter, setAuditLogDateFilter, // State Pagination currentPage, totalPages, totalRecords, loading, } = state; const { loadAuditLogs } = handlers; // ✅ UPDATED: Trigger load data saat halaman atau filter berubah // Menggunakan debounce untuk search text agar tidak spam API React.useEffect(() => { const timer = setTimeout(() => { // Reset ke halaman 1 jika filter berubah, tapi tetap di halaman x jika hanya navigasi loadAuditLogs(currentPage); }, 500); // Delay 500ms return () => clearTimeout(timer); }, [ currentPage, auditLogActionFilter, auditLogUserFilter, auditLogDateFilter, ]); // Catatan: auditLogSearchTerm bisa dimasukkan dependency jika backend support text search // Handler ganti halaman const handlePageChange = (newPage) => { state.setCurrentPage(newPage); // useEffect di atas akan otomatis memanggil API karena currentPage berubah }; // Helper styles (Tetap sama seperti sebelumnya) const getActionStyle = (action) => { const styles = { login: { icon: "🔐", color: "text-blue-400", bg: "bg-blue-500/10", border: "border-blue-500/30", }, logout: { icon: "🚪", color: "text-gray-400", bg: "bg-gray-500/10", border: "border-gray-500/30", }, create_item: { icon: "➕", color: "text-green-400", bg: "bg-green-500/10", border: "border-green-500/30", }, update_item: { icon: "✏️", color: "text-yellow-400", bg: "bg-yellow-500/10", border: "border-yellow-500/30", }, delete_item: { icon: "🗑️", color: "text-red-400", bg: "bg-red-500/10", border: "border-red-500/30", }, create_claim: { icon: "🤝", color: "text-blue-400", bg: "bg-blue-500/10", border: "border-blue-500/30", }, verify_claim: { icon: "✅", color: "text-green-400", bg: "bg-green-500/10", border: "border-green-500/30", }, reject_claim: { icon: "❌", color: "text-red-400", bg: "bg-red-500/10", border: "border-red-500/30", }, close_case: { icon: "📋", color: "text-purple-400", bg: "bg-purple-500/10", border: "border-purple-500/30", }, reopen_case: { icon: "🔄", color: "text-orange-400", bg: "bg-orange-500/10", border: "border-orange-500/30", }, update_user_role: { icon: "👤", color: "text-yellow-400", bg: "bg-yellow-500/10", border: "border-yellow-500/30", }, block_user: { icon: "🚫", color: "text-red-400", bg: "bg-red-500/10", border: "border-red-500/30", }, unblock_user: { icon: "✅", color: "text-green-400", bg: "bg-green-500/10", border: "border-green-500/30", }, export_report: { icon: "📊", color: "text-cyan-400", bg: "bg-cyan-500/10", border: "border-cyan-500/30", }, }; return ( styles[action] || { icon: "📌", color: "text-slate-400", bg: "bg-slate-500/10", border: "border-slate-500/30", } ); }; const formatActionName = (action) => { return action .split("_") .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) .join(" "); }; // Daftar aksi unik untuk dropdown (bisa hardcode atau ambil dari API/konstanta jika perlu) // Karena pagination server-side, kita tidak bisa ambil unique dari 'all data' di frontend. // Sebaiknya sediakan list statis atau endpoint khusus. Disini kita pakai statis umum. const actionOptions = [ "login", "logout", "create_item", "update_item", "delete_item", "create_claim", "verify_claim", "reject_claim", "close_case", "reopen_case", "update_user_role", "block_user", "unblock_user", "export_report", ]; return (

📜 Audit Log

{/* Filters */}
{/* Note: Search text frontend mungkin tidak jalan sempurna jika backend belum support LIKE query global */} setAuditLogSearchTerm(e.target.value)} disabled // Sementara disable jika backend belum support full-text search global className="px-4 py-2 bg-slate-800 border-2 border-slate-600 rounded-xl text-slate-500 cursor-not-allowed" title="Pencarian teks belum aktif" /> { setAuditLogUserFilter(e.target.value); // state.setCurrentPage(1); // Optional: reset page immediately }} className="px-4 py-2 bg-slate-700 border-2 border-slate-600 rounded-xl text-white placeholder-slate-400 focus:border-blue-500 focus:outline-none" /> setAuditLogDateFilter(e.target.value)} className="px-4 py-2 bg-slate-700 border-2 border-slate-600 rounded-xl text-white focus:border-blue-500 focus:outline-none" />
{loading ? (

Memuat data...

) : (
{filteredAuditLogs.map((log, index) => { const style = getActionStyle(log.action); return (
{/* ... (Isi Card Log tetap sama seperti sebelumnya) ... */}
{style.icon}

{formatActionName(log.action)}

{log.user_name || "System"} {Helpers.formatDateTime(log.created_at)}
{log.details && (

{log.details}

)}
); })}
)} {/* Empty State */} {!loading && filteredAuditLogs.length === 0 && (
📜

Tidak ada data log.

)} {/* ✅ ADDED: Pagination Component */} {!loading && filteredAuditLogs.length > 0 && ( )}
); }; window.AuditLogTab = AuditLogTab;