Basdat/web/js/pages/admin/tabs/ArchivesTabAdmin.js
2025-12-20 00:01:08 +07:00

241 lines
9.6 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// assets/js/pages/admin/tabs/ArchivesTabAdmin.js
const ArchivesTabAdmin = ({ state, handlers }) => {
const {
archives,
filteredArchives,
archiveSearchTerm,
setArchiveSearchTerm,
archiveCategoryFilter,
setArchiveCategoryFilter,
} = state;
const { handleViewArchiveDetail } = handlers;
// Filter archives locally
React.useEffect(() => {
let filtered = archives.filter((item) => {
const matchesSearch =
item.name.toLowerCase().includes(archiveSearchTerm.toLowerCase()) ||
item.location.toLowerCase().includes(archiveSearchTerm.toLowerCase()) ||
(item.berita_acara_no &&
item.berita_acara_no
.toLowerCase()
.includes(archiveSearchTerm.toLowerCase()));
const matchesCategory =
!archiveCategoryFilter ||
Helpers.getCategoryValue(item.category_id) === archiveCategoryFilter;
return matchesSearch && matchesCategory;
});
state.setFilteredArchives(filtered);
}, [archiveSearchTerm, archiveCategoryFilter, archives]);
return (
<div className="bg-gradient-to-br from-slate-800 to-slate-900 rounded-xl shadow-xl border border-slate-700">
<div className="p-6 border-b border-slate-700">
<div className="flex justify-between items-center mb-4">
<h2 className="text-xl font-semibold text-white">
📂 Kelola Arsip (Case Closed)
</h2>
<div className="flex gap-3">
<button
onClick={() => handlers.loadArchives()}
className="px-4 py-2 bg-gradient-to-r from-blue-600 to-blue-700 text-white rounded-lg font-semibold hover:from-blue-700 hover:to-blue-800 transition shadow-lg"
>
🔄 Refresh
</button>
</div>
</div>
<div className="flex gap-3 flex-wrap">
<input
type="text"
placeholder="Cari arsip (nama, lokasi, no. BA)..."
value={archiveSearchTerm}
onChange={(e) => setArchiveSearchTerm(e.target.value)}
className="flex-1 min-w-[200px] 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"
/>
<select
value={archiveCategoryFilter}
onChange={(e) => setArchiveCategoryFilter(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"
>
<option value="">Semua Kategori</option>
{state.categories &&
state.categories.map((cat) => (
<option key={cat.id} value={cat.slug || cat.id}>
{" "}
{/* Sesuaikan value dengan slug/id dari DB */}
{cat.name}
</option>
))}
</select>
</div>
{/* Stats Summary */}
<div className="grid grid-cols-3 gap-4 mt-4">
<div className="bg-green-500/10 border border-green-500/30 p-3 rounded-lg text-center">
<div className="text-green-400 font-bold text-2xl">
{archives.length}
</div>
<div className="text-slate-400 text-sm">Total Arsip</div>
</div>
<div className="bg-blue-500/10 border border-blue-500/30 p-3 rounded-lg text-center">
<div className="text-blue-400 font-bold text-2xl">
{
archives.filter(
(a) =>
new Date(a.case_closed_at).getMonth() ===
new Date().getMonth()
).length
}
</div>
<div className="text-slate-400 text-sm">Bulan Ini</div>
</div>
<div className="bg-purple-500/10 border border-purple-500/30 p-3 rounded-lg text-center">
<div className="text-purple-400 font-bold text-2xl">
{
archives.filter(
(a) =>
new Date(a.case_closed_at).getFullYear() ===
new Date().getFullYear()
).length
}
</div>
<div className="text-slate-400 text-sm">Tahun Ini</div>
</div>
</div>
</div>
<div className="p-6">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{filteredArchives.map((item) => (
<div
key={item.id}
className="bg-gradient-to-br from-slate-700 to-slate-800 border-2 border-green-500/30 rounded-xl p-5 hover:border-green-500 hover:shadow-xl hover:shadow-green-500/20 transition-all"
>
{/* Header */}
<div className="flex justify-between items-start mb-4 border-b border-slate-600 pb-3">
<div className="flex-1">
<h3 className="text-lg font-bold text-white">{item.name}</h3>
<p className="text-xs text-slate-400 mt-1">
📍 {item.location} 📅{" "}
{Helpers.formatDate(item.date_found)}
</p>
</div>
<span className="px-3 py-1 rounded-full text-xs font-bold uppercase tracking-wider bg-green-500/20 text-green-400 border border-green-500/50">
CLOSED
</span>
</div>
{/* Image */}
{item.photo_url && (
<div className="mb-4">
<img
src={item.photo_url}
alt={item.name}
className="w-full h-40 object-cover rounded-lg border border-slate-600"
onError={(e) =>
(e.target.src =
"https://via.placeholder.com/400x200?text=No+Image")
}
/>
</div>
)}
{/* Case Closed Info */}
<div className="bg-green-500/10 border-2 border-green-500/30 p-4 rounded-lg mb-4">
<div className="flex items-center gap-2 mb-2">
<span className="text-2xl">📋</span>
<strong className="text-green-400">Case Closed</strong>
</div>
<div className="space-y-1 text-sm text-slate-300">
<div>
No. BA:{" "}
<strong className="text-white">
{item.berita_acara_no || "-"}
</strong>
</div>
{item.case_closed_at && (
<div>
Ditutup: {Helpers.formatDateTime(item.case_closed_at)}
</div>
)}
{item.case_closed_by_name && (
<div>Oleh: {item.case_closed_by_name}</div>
)}
{item.claimer_name && (
<div>
Penerima:{" "}
<strong className="text-white">
{item.claimer_name}
</strong>
</div>
)}
</div>
{item.bukti_serah_terima && (
<a
href={item.bukti_serah_terima}
target="_blank"
rel="noopener noreferrer"
className="inline-block mt-2 px-3 py-1 bg-blue-600 text-white text-xs rounded hover:bg-blue-700 transition"
>
📄 Lihat Bukti
</a>
)}
</div>
{/* Reporter Info */}
<div className="bg-slate-900/50 p-3 rounded-lg border border-slate-600 mb-4">
<div className="grid grid-cols-2 gap-2 text-xs text-slate-400">
<div>
<strong className="text-slate-300">Pelapor:</strong>
<br />
{item.reporter_name || "N/A"}
</div>
<div>
<strong className="text-slate-300">Kontak:</strong>
<br />
{item.reporter_contact || "N/A"}
</div>
</div>
</div>
{/* Category */}
<div className="flex items-center justify-between mb-4">
<span className="text-sm text-slate-400">
🏷 {item.category || "-"}
</span>
{item.case_closed_notes && (
<span className="text-xs text-blue-400">📝 Ada catatan</span>
)}
</div>
{/* Actions */}
<div className="flex gap-2">
<button
onClick={() => handleViewArchiveDetail(item)}
className="flex-1 px-3 py-2 bg-gradient-to-r from-blue-600 to-blue-700 text-white text-sm rounded-lg hover:from-blue-700 hover:to-blue-800 transition shadow-lg"
>
📋 Detail Lengkap
</button>
</div>
</div>
))}
</div>
{filteredArchives.length === 0 && (
<div className="text-center py-12 text-slate-400">
<div className="text-6xl mb-4">📂</div>
<p>
{archiveSearchTerm || archiveCategoryFilter
? "Tidak ada arsip yang sesuai filter"
: "Belum ada arsip"}
</p>
</div>
)}
</div>
</div>
);
};