321 lines
11 KiB
JavaScript
321 lines
11 KiB
JavaScript
const ManagerReportFoundModal = ({
|
||
isOpen,
|
||
onClose,
|
||
onSubmit,
|
||
loading,
|
||
photoPreview,
|
||
onPhotoChange,
|
||
categories,
|
||
}) => {
|
||
const [users, setUsers] = React.useState([]);
|
||
const [loadingUsers, setLoadingUsers] = React.useState(false);
|
||
|
||
// ✅ ADD: State untuk menyimpan user yang dipilih
|
||
const [selectedUser, setSelectedUser] = React.useState(null);
|
||
|
||
// ✅ ADD: State untuk input manual
|
||
const [reporterName, setReporterName] = React.useState("");
|
||
const [reporterContact, setReporterContact] = React.useState("");
|
||
|
||
// Load users when modal opens
|
||
React.useEffect(() => {
|
||
if (isOpen) {
|
||
loadUsers();
|
||
// Reset form saat modal dibuka
|
||
setSelectedUser(null);
|
||
setReporterName("");
|
||
setReporterContact("");
|
||
}
|
||
}, [isOpen]);
|
||
|
||
const loadUsers = async () => {
|
||
try {
|
||
setLoadingUsers(true);
|
||
const response = await fetch(
|
||
`${CONFIG.API_URL}/api/manager/users?page=1&limit=1000`,
|
||
{
|
||
headers: {
|
||
Authorization: `Bearer ${AuthUtils.getToken()}`,
|
||
},
|
||
}
|
||
);
|
||
|
||
if (response.ok) {
|
||
const data = await response.json();
|
||
setUsers(data.data || []);
|
||
}
|
||
} catch (error) {
|
||
console.error("Failed to load users:", error);
|
||
} finally {
|
||
setLoadingUsers(false);
|
||
}
|
||
};
|
||
|
||
// ✅ UPDATE: Handle user selection
|
||
const handleUserSelect = (e) => {
|
||
const userId = e.target.value;
|
||
if (!userId) {
|
||
setSelectedUser(null);
|
||
return;
|
||
}
|
||
|
||
const user = users.find((u) => u.id === parseInt(userId));
|
||
if (user) {
|
||
setSelectedUser(user);
|
||
setReporterName(user.name);
|
||
setReporterContact(user.phone || "");
|
||
}
|
||
};
|
||
|
||
return (
|
||
<Modal
|
||
isOpen={isOpen}
|
||
onClose={onClose}
|
||
title="📦 Laporan Barang Ditemukan (Offline)"
|
||
size="large"
|
||
>
|
||
<form onSubmit={onSubmit} className="space-y-4">
|
||
{/* Info Box */}
|
||
<div className="bg-blue-500/10 border-2 border-blue-500/30 p-4 rounded-xl">
|
||
<div className="flex items-start gap-3">
|
||
<span className="text-2xl">ℹ️</span>
|
||
<div className="flex-1">
|
||
<strong className="text-blue-400 block mb-1">
|
||
Laporan Offline
|
||
</strong>
|
||
<p className="text-sm text-slate-300">
|
||
Fitur ini untuk mencatat barang yang diserahkan langsung kepada
|
||
manager. Jika pelapor memiliki akun, silakan pilih di bawah.
|
||
Jika tidak, cukup isi nama manual.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* User Selection */}
|
||
<div>
|
||
<label className="block font-semibold mb-2 text-slate-300">
|
||
Pilih User (Penemu Barang){" "}
|
||
<span className="text-slate-500 font-normal text-sm">
|
||
(Opsional)
|
||
</span>
|
||
</label>
|
||
<select
|
||
name="reporter_user_id"
|
||
onChange={handleUserSelect}
|
||
disabled={loadingUsers}
|
||
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="">-- Tamu / Tidak Terdaftar --</option>
|
||
{users.map((user) => (
|
||
<option key={user.id} value={user.id}>
|
||
{user.name} - {user.email} ({user.nrp})
|
||
</option>
|
||
))}
|
||
</select>
|
||
<p className="text-xs text-slate-400 mt-1">
|
||
Pilih jika pelapor sudah punya akun. Jika belum, biarkan kosong.
|
||
</p>
|
||
</div>
|
||
|
||
{/* ✅ FIXED: Selected User Info - sekarang selectedUser sudah didefinisikan */}
|
||
{selectedUser && (
|
||
<div className="bg-green-500/10 border border-green-500/30 p-4 rounded-xl">
|
||
<strong className="text-green-400 block mb-2">
|
||
✅ User Terpilih:
|
||
</strong>
|
||
<div className="grid grid-cols-2 gap-3 text-sm text-slate-300">
|
||
<div>
|
||
<strong className="text-slate-200">Nama:</strong>{" "}
|
||
{selectedUser.name}
|
||
</div>
|
||
<div>
|
||
<strong className="text-slate-200">Email:</strong>{" "}
|
||
{selectedUser.email}
|
||
</div>
|
||
<div>
|
||
<strong className="text-slate-200">NRP:</strong>{" "}
|
||
{selectedUser.nrp}
|
||
</div>
|
||
<div>
|
||
<strong className="text-slate-200">Telepon:</strong>{" "}
|
||
{selectedUser.phone || "-"}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
<div className="border-t border-slate-700 pt-4">
|
||
<h3 className="text-lg font-semibold text-white mb-4">
|
||
Detail Barang Ditemukan
|
||
</h3>
|
||
</div>
|
||
|
||
{/* Item Details */}
|
||
<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: Dompet Kulit Coklat"
|
||
/>
|
||
</div>
|
||
|
||
<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 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"
|
||
/>
|
||
{photoPreview && (
|
||
<div className="mt-3">
|
||
<img
|
||
src={photoPreview}
|
||
alt="Preview"
|
||
className="w-full h-48 object-cover rounded-xl border-2 border-blue-500"
|
||
/>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
<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>
|
||
{/* PERBAIKAN: Gunakan 'categories' langsung, bukan 'state.categories' */}
|
||
{categories &&
|
||
categories.map((cat) => (
|
||
<option key={cat.id} value={cat.id}>
|
||
{cat.name}
|
||
</option>
|
||
))}
|
||
</select>
|
||
</div>
|
||
|
||
<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>
|
||
|
||
<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>
|
||
|
||
<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>
|
||
|
||
<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 MANUAL dengan controlled state */}
|
||
<div>
|
||
<label className="block font-semibold mb-2 text-slate-300">
|
||
Nama Pelapor *
|
||
</label>
|
||
<input
|
||
type="text"
|
||
name="reporter_name"
|
||
required
|
||
value={reporterName}
|
||
onChange={(e) => setReporterName(e.target.value)}
|
||
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="Nama lengkap penemu barang"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block font-semibold mb-2 text-slate-300">
|
||
Kontak Pelapor *
|
||
</label>
|
||
<input
|
||
type="text"
|
||
name="reporter_contact"
|
||
required
|
||
value={reporterContact}
|
||
onChange={(e) => setReporterContact(e.target.value)}
|
||
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>
|
||
|
||
<div>
|
||
<label className="block font-semibold mb-2 text-slate-300">
|
||
Catatan Manager (Opsional)
|
||
</label>
|
||
<textarea
|
||
name="manager_notes"
|
||
rows="2"
|
||
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 internal dari manager..."
|
||
/>
|
||
</div>
|
||
|
||
<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 ? "⏳ Menyimpan..." : "✅ Submit Laporan"}
|
||
</button>
|
||
</form>
|
||
</Modal>
|
||
);
|
||
};
|
||
|
||
window.ManagerReportFoundModal = ManagerReportFoundModal;
|