241 lines
9.6 KiB
JavaScript
241 lines
9.6 KiB
JavaScript
// 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>
|
||
);
|
||
};
|