Basdat/web/js/pages/user/UserModals.js
2025-12-20 00:01:08 +07:00

524 lines
18 KiB
JavaScript
Raw Permalink 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/user/UserModals.js
// ✅ [BARU] Modal untuk memilih Laporan Hilang yang cocok
const SelectLostItemModal = ({
isOpen,
onClose,
lostItems,
onSelect,
onManual,
}) => (
<Modal isOpen={isOpen} onClose={onClose} title="💡 Ditemukan Laporan Cocok">
<div className="space-y-4">
<div className="bg-blue-500/10 border border-blue-500/30 p-4 rounded-xl">
<p className="text-sm text-blue-200">
Kami menemukan laporan <strong>Barang Hilang Anda</strong> dengan
kategori yang sama. Pilih salah satu untuk mengisi form klaim secara
otomatis.
</p>
</div>
<div className="space-y-3 max-h-80 overflow-y-auto pr-1">
{lostItems.map((item) => (
<div
key={item.id}
onClick={() => onSelect(item)}
className="bg-slate-800 border border-slate-600 hover:border-blue-500 hover:bg-slate-700/50 p-4 rounded-xl cursor-pointer transition group"
>
<div className="flex justify-between items-start">
<div>
<h4 className="font-bold text-white group-hover:text-blue-400 transition">
{item.name}
</h4>
<p className="text-xs text-slate-400 mt-1">
📅 {Helpers.formatDate(item.date_lost)} 📍{" "}
{item.location || "?"}
</p>
</div>
<span className="text-2xl opacity-50 group-hover:opacity-100 transition">
👉
</span>
</div>
<p className="text-xs text-slate-300 mt-2 line-clamp-2 italic">
"{item.description}"
</p>
</div>
))}
</div>
<div className="pt-4 border-t border-slate-700">
<button
onClick={onManual}
className="w-full py-3 bg-slate-700 hover:bg-slate-600 text-white rounded-xl font-semibold transition"
>
📝 Tidak, Saya Ingin Input Manual
</button>
</div>
</div>
</Modal>
);
const DetailModalUser = ({ isOpen, onClose, item, user, onClaim }) => (
<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-200">
<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)}
</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}</span>
</div>
<div className="bg-slate-700/50 p-3 rounded-lg">
<strong className="text-blue-400">Tanggal:</strong>
<span className="ml-2">{Helpers.formatDate(item.date_found)}</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}
</span>
</div>
</div>
{item.status === "unclaimed" && item.reporter_id !== user?.id && (
<button
onClick={() => {
onClose();
onClaim(item);
}}
className="w-full mt-6 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"
>
Klaim Barang Ini
</button>
)}
{item.reporter_id === user?.id && (
<div className="mt-6 p-4 bg-green-500/10 border-2 border-green-500/30 rounded-xl text-center">
<div className="text-green-400 font-semibold text-lg mb-2">
Ini adalah barang yang Anda laporkan
</div>
<p className="text-slate-400 text-sm">
Anda tidak dapat mengklaim barang yang Anda sendiri temukan
</p>
</div>
)}
</div>
)}
</Modal>
);
const ClaimModalUser = ({
isOpen,
onClose,
onSubmit,
loading,
initialData,
categories, // Pastikan prop ini diterima
}) => {
const [formData, setFormData] = React.useState({
description: "",
contact: "",
});
React.useEffect(() => {
if (isOpen) {
if (initialData) {
setFormData({
description: initialData.description || "",
contact: initialData.contact || "",
});
} else {
setFormData({ description: "", contact: "" });
}
}
}, [isOpen, initialData]);
const handleChange = (e) => {
const { name, value } = e.target;
setFormData((prev) => ({ ...prev, [name]: value }));
};
if (!isOpen) return null;
return (
<Modal isOpen={isOpen} onClose={onClose} title="Klaim Barang">
<form onSubmit={onSubmit} className="space-y-4">
{initialData && (
<div className="bg-green-500/10 border border-green-500/30 p-3 rounded-lg mb-2">
<p className="text-xs text-green-300">
Data terisi otomatis dari laporan hilang Anda. Silakan lengkapi
bukti.
</p>
</div>
)}
{/* Deskripsi */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Deskripsi Barang *
</label>
<textarea
name="description"
required
rows="4"
value={formData.description}
onChange={handleChange}
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="Jelaskan ciri khusus barang yang hanya Anda tahu..."
/>
</div>
{/* Kontak */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Kontak yang bisa dihubungi *
</label>
<input
type="text"
name="contact"
required
value={formData.contact}
onChange={handleChange}
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="No HP / WhatsApp / Line"
/>
</div>
{/* Bukti */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Bukti Pendukung (Opsional)
</label>
<input
type="file"
name="proof"
accept="image/*,.pdf"
className="w-full px-4 py-3 bg-slate-700 border-2 border-slate-600 rounded-xl text-slate-300 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-blue-600 file:text-white hover:file:bg-blue-700 transition"
/>
<p className="text-xs text-slate-400 mt-1">
Foto struk, foto lama barang, atau bukti kepemilikan lainnya.
</p>
</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 ? "Mengirim..." : "Ajukan Klaim"}
</button>
</form>
</Modal>
);
};
const ReportLostModalUser = ({
isOpen,
onClose,
onSubmit,
loading,
categories,
}) => {
if (!isOpen) return null;
return (
<Modal isOpen={isOpen} onClose={onClose} title="📢 Lapor Kehilangan Barang">
<form onSubmit={onSubmit} className="space-y-4">
{/* Nama Barang */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Nama Barang Hilang *
</label>
<input
type="text"
name="name"
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"
placeholder="Contoh: Dompet Hitam Merk X"
/>
</div>
{/* Kategori Dropdown */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Kategori *
</label>
<select
name="category_id"
required
className="w-full px-4 py-3 bg-slate-700 border-2 border-slate-600 rounded-xl text-white focus:border-blue-500 focus:outline-none"
>
<option value="">-- Pilih Kategori --</option>
{categories && categories.length > 0 ? (
categories.map((cat) => (
<option key={cat.id} value={cat.id}>
{cat.name}
</option>
))
) : (
<option value="" disabled>
Gagal memuat kategori (Cek Database)
</option>
)}
</select>
</div>
{/* Warna (Opsional) */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Warna Dominan
</label>
<input
type="text"
name="color"
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="Contoh: Hitam"
/>
</div>
{/* Lokasi */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Perkiraan Lokasi Hilang
</label>
<input
type="text"
name="location"
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="Contoh: Kantin, Lab Komputer"
/>
</div>
{/* Deskripsi */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Ciri-ciri Detail *
</label>
<textarea
name="description"
required
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="Jelaskan ciri-ciri unik, isi dompet, stiker laptop, dll..."
/>
</div>
{/* Tanggal Hilang */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Tanggal Hilang *
</label>
<input
type="date"
name="date_lost"
required
max={new Date().toISOString().split("T")[0]}
className="w-full px-4 py-3 bg-slate-700 border-2 border-slate-600 rounded-xl text-white focus:border-blue-500 focus:outline-none"
/>
</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 ? "Mengirim..." : "Submit Laporan"}
</button>
</form>
</Modal>
);
};
const ReportFoundModalUser = ({
isOpen,
onClose,
onSubmit,
loading,
photoPreview,
onPhotoChange,
user,
categories,
}) => (
<Modal isOpen={isOpen} onClose={onClose} title="Lapor Barang Temuan">
<form onSubmit={onSubmit} className="space-y-4">
{/* Input Nama Barang */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Nama Barang *
</label>
<input
type="text"
name="name"
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"
placeholder="Contoh: Botol Minum Biru"
/>
</div>
{/* Input Kategori - BAGIAN YANG DIPERBAIKI */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Kategori *
</label>
<select
name="category_id"
required
className="w-full px-4 py-3 bg-slate-700 border-2 border-slate-600 rounded-xl text-white focus:border-blue-500 focus:outline-none"
>
<option value="">-- Pilih Kategori --</option>
{categories &&
categories.map((cat) => (
<option key={cat.id} value={cat.id}>
{cat.name}
</option>
))}
</select>
</div>
{/* Input Foto Barang */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Foto Barang
</label>
<input
type="file"
name="photo"
accept="image/*"
onChange={onPhotoChange}
className="w-full text-slate-300 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-blue-600 file:text-white hover:file:bg-blue-700 transition"
/>
{photoPreview && (
<div className="mt-3">
<p className="text-xs text-slate-400 mb-1">Preview:</p>
<img
src={photoPreview}
alt="Preview"
className="w-full h-48 object-cover rounded-xl border-2 border-blue-500"
/>
</div>
)}
</div>
{/* Input Lokasi */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Lokasi Ditemukan *
</label>
<input
type="text"
name="location"
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"
placeholder="Contoh: Perpustakaan Lantai 2"
/>
</div>
{/* Input Deskripsi */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Deskripsi Umum *
</label>
<textarea
name="description"
required
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="Deskripsi umum barang yang akan ditampilkan..."
/>
</div>
{/* Input Ciri Rahasia */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Ciri Khusus Rahasia * 🔒
</label>
<textarea
name="secret_details"
required
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="Jelaskan ciri khusus yang HANYA pemilik asli yang tahu (contoh: ada goresan di bagian belakang, ada tulisan nama di dalam, dll)"
/>
<p className="text-xs text-yellow-400 mt-1">
Info ini RAHASIA dan hanya digunakan untuk verifikasi klaim
</p>
</div>
{/* Input Tanggal */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Tanggal Ditemukan *
</label>
<input
type="date"
name="date_found"
required
max={new Date().toISOString().split("T")[0]}
className="w-full px-4 py-3 bg-slate-700 border-2 border-slate-600 rounded-xl text-white focus:border-blue-500 focus:outline-none"
/>
</div>
{/* Input Pelapor (Read Only) */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Nama Pelapor *
</label>
<input
type="text"
name="reporter_name"
required
defaultValue={user?.name}
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"
readOnly
/>
</div>
{/* Input Kontak */}
<div>
<label className="block font-semibold mb-2 text-slate-300">
Kontak Pelapor *
</label>
<input
type="text"
name="reporter_contact"
required
defaultValue={user?.phone}
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="08123456789"
/>
</div>
{/* Tombol Submit */}
<button
type="submit"
disabled={loading}
className="w-full 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:from-slate-600 disabled:to-slate-700"
>
{loading ? "Mengirim..." : "Submit Laporan"}
</button>
</form>
</Modal>
);
// Export ke window
window.DetailModalUser = DetailModalUser;
window.ClaimModalUser = ClaimModalUser;
window.SelectLostItemModal = SelectLostItemModal;
window.ReportLostModalUser = ReportLostModalUser; // Pastikan ini ada
window.ReportFoundModalUser = ReportFoundModalUser;