469 lines
17 KiB
JavaScript
469 lines
17 KiB
JavaScript
// assets/js/pages/manager/ManagerModals.js
|
||
|
||
const DetailModal = ({ isOpen, onClose, item }) => (
|
||
<Modal isOpen={isOpen} onClose={onClose} title="Detail Barang">
|
||
{item && (
|
||
<div>
|
||
<img
|
||
src={item.photo_url || "https://via.placeholder.com/600x400"}
|
||
alt={item.name}
|
||
className="w-full h-64 object-cover rounded-xl mb-4 border-2 border-slate-600"
|
||
/>
|
||
<h3 className="text-2xl font-bold mb-4 text-white">{item.name}</h3>
|
||
|
||
<div className="space-y-3 text-slate-300">
|
||
<div className="bg-slate-700/50 p-3 rounded-lg">
|
||
<strong className="text-blue-400">Kategori:</strong>
|
||
<span className="ml-2">
|
||
{item.category ||
|
||
Helpers.getCategoryName(item.category_id) ||
|
||
"Tidak ada data"}
|
||
</span>
|
||
</div>
|
||
|
||
<div className="bg-slate-700/50 p-3 rounded-lg">
|
||
<strong className="text-blue-400">Lokasi:</strong>
|
||
<span className="ml-2">{item.location || "Tidak ada data"}</span>
|
||
</div>
|
||
|
||
<div className="bg-slate-700/50 p-3 rounded-lg">
|
||
<strong className="text-blue-400">Tanggal Ditemukan:</strong>
|
||
<span className="ml-2">
|
||
{Helpers.formatDate(item.date_found) || "Tidak ada data"}
|
||
</span>
|
||
</div>
|
||
|
||
<div className="bg-slate-700/50 p-3 rounded-lg">
|
||
<strong className="text-blue-400">Status:</strong>
|
||
<span
|
||
className={`ml-2 px-3 py-1 rounded-full text-xs font-semibold ${Helpers.getStatusBadgeClass(
|
||
item.status
|
||
)}`}
|
||
>
|
||
{item.status || "Tidak ada data"}
|
||
</span>
|
||
</div>
|
||
|
||
<div className="bg-slate-700/50 p-3 rounded-lg">
|
||
<strong className="text-blue-400">Deskripsi Umum:</strong>
|
||
<p className="text-slate-300 mt-2">
|
||
{item.description || "Tidak ada deskripsi"}
|
||
</p>
|
||
</div>
|
||
|
||
<div className="bg-slate-700/50 p-3 rounded-lg">
|
||
<strong className="text-blue-400">Pelapor:</strong>
|
||
<span className="ml-2">
|
||
{item.reporter_name || "Tidak ada data"}
|
||
</span>
|
||
</div>
|
||
|
||
<div className="bg-slate-700/50 p-3 rounded-lg">
|
||
<strong className="text-blue-400">Kontak Pelapor:</strong>
|
||
<span className="ml-2">
|
||
{item.reporter_contact || "Tidak ada data"}
|
||
</span>
|
||
</div>
|
||
|
||
<div className="bg-yellow-500/10 border-2 border-yellow-500/30 p-4 rounded-xl">
|
||
<div className="flex items-center gap-2 mb-2">
|
||
<span className="text-2xl">🔒</span>
|
||
<strong className="text-yellow-400 text-lg">
|
||
Ciri Khusus Rahasia (Untuk Verifikasi)
|
||
</strong>
|
||
</div>
|
||
<p className="text-slate-300 leading-relaxed">
|
||
{item.secret_details || "Tidak ada deskripsi rahasia"}
|
||
</p>
|
||
<p className="text-xs text-yellow-400 mt-2">
|
||
⚠️ Info ini RAHASIA - gunakan untuk verifikasi klaim
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</Modal>
|
||
);
|
||
|
||
const VerifyClaimModal = ({
|
||
isOpen,
|
||
onClose,
|
||
claim,
|
||
onApprove,
|
||
onReject,
|
||
onCloseCase,
|
||
}) => (
|
||
<Modal
|
||
isOpen={isOpen}
|
||
onClose={onClose}
|
||
title="Verifikasi Klaim"
|
||
size="large"
|
||
>
|
||
{claim && (
|
||
<div>
|
||
<div className="grid grid-cols-2 gap-6 mb-6">
|
||
<div className="bg-blue-500/10 p-4 rounded-xl border border-blue-500/30">
|
||
<h4 className="font-semibold mb-3 text-blue-400">
|
||
Deskripsi Asli Barang (Rahasia)
|
||
</h4>
|
||
<p className="text-sm text-slate-300 font-medium">
|
||
{claim.item_secret_details || "Tidak ada ciri khusus rahasia"}
|
||
</p>
|
||
|
||
<div className="mt-3 pt-3 border-t border-slate-600/50">
|
||
<span className="text-xs text-slate-500 uppercase">
|
||
Deskripsi Umum:
|
||
</span>
|
||
<p className="text-xs text-slate-400">{claim.item_description}</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="bg-yellow-500/10 p-4 rounded-xl border border-yellow-500/30">
|
||
<h4 className="font-semibold mb-3 text-yellow-400">
|
||
Deskripsi dari Pengklaim
|
||
</h4>
|
||
<p className="text-sm text-slate-300">{claim.description}</p>
|
||
</div>
|
||
</div>
|
||
|
||
{claim.match_percentage && (
|
||
<div
|
||
className={`p-6 rounded-xl text-center mb-6 ${
|
||
claim.match_percentage >= 70
|
||
? "bg-green-500/10 border border-green-500/30"
|
||
: "bg-yellow-500/10 border border-yellow-500/30"
|
||
}`}
|
||
>
|
||
<strong className="text-slate-300">Similarity Match:</strong>
|
||
<div
|
||
className={`text-4xl font-bold mt-2 ${
|
||
claim.match_percentage >= 70
|
||
? "text-green-400"
|
||
: "text-yellow-400"
|
||
}`}
|
||
>
|
||
{claim.match_percentage}%
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
<div className="bg-slate-900/50 p-4 rounded-xl mb-6 border border-slate-700">
|
||
<strong className="text-slate-300">Info Pengklaim:</strong>
|
||
<div className="mt-2 space-y-1 text-slate-400">
|
||
<div>Nama: {claim.user_name}</div>
|
||
<div>Kontak: {claim.contact}</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="flex gap-4">
|
||
{claim.status === "pending" && (
|
||
<>
|
||
<button
|
||
onClick={onApprove}
|
||
className="flex-1 px-4 py-3 bg-gradient-to-r from-green-600 to-green-700 text-white rounded-xl hover:from-green-700 hover:to-green-800 transition font-semibold shadow-lg"
|
||
>
|
||
✓ Approve Klaim
|
||
</button>
|
||
<button
|
||
onClick={onReject}
|
||
className="flex-1 px-4 py-3 bg-gradient-to-r from-red-600 to-red-700 text-white rounded-xl hover:from-red-700 hover:to-red-800 transition font-semibold shadow-lg"
|
||
>
|
||
✗ Reject Klaim
|
||
</button>
|
||
</>
|
||
)}
|
||
</div>
|
||
|
||
{claim.status === "approved" && !claim.berita_acara_no && (
|
||
<button
|
||
onClick={() => {
|
||
onClose();
|
||
onCloseCase(claim);
|
||
}}
|
||
className="w-full mt-4 px-4 py-3 bg-gradient-to-r from-blue-600 to-blue-700 text-white rounded-xl hover:from-blue-700 hover:to-blue-800 transition font-semibold shadow-lg"
|
||
>
|
||
📋 Close Case (Serah Terima)
|
||
</button>
|
||
)}
|
||
|
||
{claim.status === "approved" && claim.berita_acara_no && (
|
||
<div className="mt-4 p-4 bg-green-500/10 border-2 border-green-500/30 rounded-xl">
|
||
<div className="text-green-400 font-semibold text-center mb-2">
|
||
✓ Case Already Closed
|
||
</div>
|
||
<div className="text-sm text-slate-300 text-center">
|
||
No. BA: <strong>{claim.berita_acara_no}</strong>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
</Modal>
|
||
);
|
||
|
||
const CloseCaseModal = ({
|
||
isOpen,
|
||
onClose,
|
||
claim,
|
||
closeCaseData,
|
||
setCloseCaseData,
|
||
onSubmit,
|
||
loading,
|
||
}) => (
|
||
<Modal
|
||
isOpen={isOpen}
|
||
onClose={() => {
|
||
onClose();
|
||
setCloseCaseData({
|
||
berita_acara_no: "",
|
||
bukti_serah_terima: "",
|
||
notes: "",
|
||
});
|
||
}}
|
||
title="Close Case - Serah Terima Barang"
|
||
>
|
||
<form onSubmit={onSubmit} className="space-y-4">
|
||
<div className="bg-blue-500/10 p-4 rounded-lg border border-blue-500/30 mb-4">
|
||
<strong className="text-blue-400">Barang:</strong>
|
||
<p className="text-white mt-1">{claim?.item_name}</p>
|
||
<strong className="text-blue-400 mt-2 block">Penerima:</strong>
|
||
<p className="text-white">{claim?.user_name}</p>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block font-semibold mb-2 text-slate-300">
|
||
No. Berita Acara *
|
||
</label>
|
||
<input
|
||
type="text"
|
||
value={closeCaseData.berita_acara_no}
|
||
onChange={(e) =>
|
||
setCloseCaseData({
|
||
...closeCaseData,
|
||
berita_acara_no: e.target.value,
|
||
})
|
||
}
|
||
placeholder="BA/LNF/2025/001"
|
||
required
|
||
className="w-full px-4 py-3 bg-slate-700 border-2 border-slate-600 rounded-xl text-white placeholder-slate-400 focus:border-blue-500 focus:outline-none"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block font-semibold mb-2 text-slate-300">
|
||
Bukti Serah Terima (Foto/PDF)
|
||
</label>
|
||
<input
|
||
type="file"
|
||
name="bukti_file"
|
||
accept="image/*,application/pdf"
|
||
className="w-full px-4 py-3 bg-slate-700 border-2 border-slate-600 rounded-xl text-white file:mr-4 file:py-2 file:px-4 file:rounded-lg file:border-0 file:text-sm file:font-semibold file:bg-blue-600 file:text-white hover:file:bg-blue-700 focus:outline-none"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block font-semibold mb-2 text-slate-300">
|
||
Catatan (Opsional)
|
||
</label>
|
||
<textarea
|
||
value={closeCaseData.notes}
|
||
onChange={(e) =>
|
||
setCloseCaseData({ ...closeCaseData, notes: e.target.value })
|
||
}
|
||
rows="3"
|
||
className="w-full px-4 py-3 bg-slate-700 border-2 border-slate-600 rounded-xl text-white placeholder-slate-400 focus:border-blue-500 focus:outline-none"
|
||
placeholder="Catatan tambahan..."
|
||
/>
|
||
</div>
|
||
|
||
<button
|
||
type="submit"
|
||
disabled={loading}
|
||
className="w-full px-4 py-3 bg-gradient-to-r from-blue-600 to-blue-700 text-white rounded-xl hover:from-blue-700 hover:to-blue-800 transition font-semibold shadow-lg disabled:from-slate-600 disabled:to-slate-700"
|
||
>
|
||
{loading ? "Memproses..." : "✓ Close Case"}
|
||
</button>
|
||
</form>
|
||
</Modal>
|
||
);
|
||
|
||
const LostItemDetailModal = ({ isOpen, onClose, item }) => (
|
||
<Modal isOpen={isOpen} onClose={onClose} title="😢 Detail Barang Hilang">
|
||
{item && (
|
||
<div className="space-y-6">
|
||
{/* Header Section */}
|
||
<div className="bg-gradient-to-r from-slate-800 to-slate-900 p-5 rounded-xl border-l-4 border-yellow-500 shadow-lg">
|
||
<h3 className="text-2xl font-bold text-white mb-1">{item.name}</h3>
|
||
<div className="flex items-center gap-2 text-sm text-slate-400">
|
||
<span className="bg-slate-700 px-2 py-1 rounded text-xs text-white border border-slate-600">
|
||
{item.status === "active" ? "Aktif" : "Ditemukan"}
|
||
</span>
|
||
<span>•</span>
|
||
<span>ID #{item.id}</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Grid Informasi Utama */}
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div className="bg-slate-700/30 p-4 rounded-xl border border-slate-600">
|
||
<p className="text-xs text-slate-400 uppercase font-semibold mb-1">
|
||
Kategori
|
||
</p>
|
||
<p className="text-white flex items-center gap-2">
|
||
🏷️ {item.category || "-"}
|
||
</p>
|
||
</div>
|
||
<div className="bg-slate-700/30 p-4 rounded-xl border border-slate-600">
|
||
<p className="text-xs text-slate-400 uppercase font-semibold mb-1">
|
||
Tanggal Hilang
|
||
</p>
|
||
<p className="text-white flex items-center gap-2">
|
||
📅 {Helpers.formatDate(item.date_lost)}
|
||
</p>
|
||
</div>
|
||
<div className="bg-slate-700/30 p-4 rounded-xl border border-slate-600">
|
||
<p className="text-xs text-slate-400 uppercase font-semibold mb-1">
|
||
Warna
|
||
</p>
|
||
<p className="text-white flex items-center gap-2">
|
||
🎨 {item.color || "-"}
|
||
</p>
|
||
</div>
|
||
<div className="bg-slate-700/30 p-4 rounded-xl border border-slate-600">
|
||
<p className="text-xs text-slate-400 uppercase font-semibold mb-1">
|
||
Lokasi
|
||
</p>
|
||
<p className="text-white flex items-center gap-2">
|
||
📍 {item.location || "-"}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Deskripsi */}
|
||
<div className="bg-slate-900/50 p-5 rounded-xl border border-slate-600">
|
||
<h4 className="text-yellow-400 font-semibold mb-2 flex items-center gap-2">
|
||
<span>📝</span> Deskripsi Lengkap
|
||
</h4>
|
||
<p className="text-slate-300 leading-relaxed text-sm">
|
||
"{item.description}"
|
||
</p>
|
||
</div>
|
||
|
||
{/* Informasi Pelapor */}
|
||
<div className="bg-blue-500/10 border border-blue-500/30 p-5 rounded-xl">
|
||
<h4 className="text-blue-400 font-semibold mb-3 flex items-center gap-2">
|
||
<span>👤</span> Informasi Pelapor
|
||
</h4>
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<div>
|
||
<p className="text-xs text-slate-400">Nama Pelapor</p>
|
||
<p className="text-white font-medium">{item.user_name}</p>
|
||
</div>
|
||
<div>
|
||
<p className="text-xs text-slate-400">Kontak</p>
|
||
<div className="flex items-center gap-2">
|
||
<span className="text-white font-medium">
|
||
{item.user_contact || "-"}
|
||
</span>
|
||
{item.user_contact && (
|
||
<a
|
||
href={`https://wa.me/${item.user_contact
|
||
.replace(/^0/, "62")
|
||
.replace(/\D/g, "")}`}
|
||
target="_blank"
|
||
className="text-xs bg-green-600 px-2 py-1 rounded text-white hover:bg-green-700 transition"
|
||
>
|
||
Chat WA
|
||
</a>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Footer Actions */}
|
||
<div className="flex justify-end pt-4 border-t border-slate-700">
|
||
<button
|
||
onClick={onClose}
|
||
className="px-6 py-2 bg-slate-700 text-white rounded-lg hover:bg-slate-600 transition"
|
||
>
|
||
Tutup
|
||
</button>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</Modal>
|
||
);
|
||
|
||
const ApproveClaimModal = ({ isOpen, onClose, onSubmit, loading }) => {
|
||
const [notes, setNotes] = React.useState("");
|
||
|
||
// Reset input saat modal dibuka
|
||
React.useEffect(() => {
|
||
if (isOpen) setNotes("");
|
||
}, [isOpen]);
|
||
|
||
const handleSubmit = (e) => {
|
||
e.preventDefault();
|
||
onSubmit(notes); // Kirim notes ke handler submitApproveClaim
|
||
};
|
||
|
||
return (
|
||
<Modal
|
||
isOpen={isOpen}
|
||
onClose={onClose}
|
||
title="✅ Konfirmasi Approval"
|
||
size="small"
|
||
>
|
||
<form onSubmit={handleSubmit} className="space-y-4">
|
||
<div className="bg-green-500/10 border border-green-500/30 p-4 rounded-xl">
|
||
<p className="text-sm text-green-200">
|
||
Apakah Anda yakin ingin menyetujui klaim ini? Status barang akan
|
||
berubah menjadi <strong>Approved</strong>.
|
||
</p>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block font-semibold mb-2 text-slate-300">
|
||
Catatan Approval (Opsional)
|
||
</label>
|
||
<textarea
|
||
value={notes}
|
||
onChange={(e) => setNotes(e.target.value)}
|
||
rows="3"
|
||
className="w-full px-4 py-3 bg-slate-700 border-2 border-slate-600 rounded-xl text-white placeholder-slate-400 focus:border-green-500 focus:outline-none transition"
|
||
placeholder="Contoh: Identitas telah diverifikasi..."
|
||
autoFocus
|
||
/>
|
||
</div>
|
||
|
||
<div className="flex gap-3 pt-2">
|
||
<button
|
||
type="button"
|
||
onClick={onClose}
|
||
disabled={loading}
|
||
className="flex-1 px-4 py-3 bg-slate-700 text-white rounded-xl hover:bg-slate-600 transition font-semibold"
|
||
>
|
||
Batal
|
||
</button>
|
||
<button
|
||
type="submit"
|
||
disabled={loading}
|
||
className="flex-1 px-4 py-3 bg-gradient-to-r from-green-600 to-green-700 text-white rounded-xl hover:from-green-700 hover:to-green-800 transition font-semibold shadow-lg disabled:opacity-50"
|
||
>
|
||
{loading ? "Memproses..." : "Ya, Approve"}
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</Modal>
|
||
);
|
||
};
|
||
|
||
// Jangan lupa export ke window
|
||
window.LostItemDetailModal = LostItemDetailModal;
|
||
|
||
window.DetailModal = DetailModal;
|
||
window.VerifyClaimModal = VerifyClaimModal;
|
||
window.CloseCaseModal = CloseCaseModal;
|
||
window.LostItemDetailModal = LostItemDetailModal;
|
||
window.ApproveClaimModal = ApproveClaimModal; |