309 lines
12 KiB
JavaScript
309 lines
12 KiB
JavaScript
const MyFoundItemsTab = ({ state, handlers }) => {
|
||
const { myFoundItems, loading, user } = state;
|
||
const { showToast, loadData } = handlers;
|
||
|
||
const handleApproveItem = async (item) => {
|
||
if (!item.direct_claim_id) {
|
||
showToast("⚠️ Tidak ada klaim untuk item ini", "error");
|
||
return;
|
||
}
|
||
|
||
const confirmMsg = `✅ Konfirmasi Penerimaan Barang
|
||
|
||
Apakah Anda yakin barang "${item.name}" ini adalah milik Anda?
|
||
|
||
Jika Ya:
|
||
- Status akan berubah menjadi "verified"
|
||
- Anda bisa koordinasi dengan penemu untuk pengambilan
|
||
- Kasus akan dilanjutkan
|
||
|
||
⚠️ Pastikan ini benar-benar barang Anda!`;
|
||
|
||
if (!confirm(confirmMsg)) return;
|
||
|
||
try {
|
||
state.setLoading(true);
|
||
|
||
// ✅ ENDPOINT YANG BENAR - menggunakan claim ID
|
||
await ApiUtils.post(`/api/user/claims/${item.direct_claim_id}/respond`, {
|
||
action: "approve",
|
||
});
|
||
|
||
showToast(
|
||
"✅ Berhasil! Silakan koordinasi pengambilan dengan penemu.",
|
||
"success"
|
||
);
|
||
loadData();
|
||
} catch (error) {
|
||
console.error("Error approving item:", error);
|
||
showToast("Gagal menerima: " + error.message, "error");
|
||
} finally {
|
||
state.setLoading(false);
|
||
}
|
||
};
|
||
|
||
const handleRejectItem = async (item) => {
|
||
if (!item.direct_claim_id) {
|
||
showToast("⚠️ Tidak ada klaim untuk item ini", "error");
|
||
return;
|
||
}
|
||
|
||
const reason = prompt(
|
||
"❌ Alasan Penolakan (opsional):\n\nContoh: Bukan barang saya, warna berbeda, dll."
|
||
);
|
||
|
||
if (reason === null) return; // User cancelled
|
||
|
||
const confirmMsg = `❌ Konfirmasi Penolakan
|
||
|
||
Yakin menolak barang "${item.name}"?
|
||
${reason ? `Alasan: ${reason}` : "(Tanpa alasan)"}
|
||
|
||
Barang akan kembali dalam status pencarian.`;
|
||
|
||
if (!confirm(confirmMsg)) return;
|
||
|
||
try {
|
||
state.setLoading(true);
|
||
|
||
// ✅ ENDPOINT YANG BENAR - menggunakan claim ID
|
||
await ApiUtils.post(`/api/user/claims/${item.direct_claim_id}/respond`, {
|
||
action: "reject",
|
||
});
|
||
|
||
showToast(
|
||
"❌ Barang ditolak. Status kembali dalam pencarian.",
|
||
"success"
|
||
);
|
||
loadData();
|
||
} catch (error) {
|
||
console.error("Error rejecting item:", error);
|
||
showToast("Gagal menolak: " + error.message, "error");
|
||
} finally {
|
||
state.setLoading(false);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className="bg-gradient-to-br from-slate-800 to-slate-900 rounded-xl p-6 shadow-xl border border-slate-700">
|
||
<div className="flex justify-between items-center mb-6">
|
||
<div>
|
||
<h2 className="text-xl font-semibold text-white">
|
||
📦 Barang yang Dilaporkan Orang Lain Menemukan
|
||
</h2>
|
||
<p className="text-slate-400 text-sm mt-1">
|
||
Barang hilang Anda yang dilaporkan orang lain menemukan - butuh
|
||
konfirmasi Anda
|
||
</p>
|
||
</div>
|
||
<button
|
||
onClick={() => loadData()}
|
||
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>
|
||
|
||
{/* Stats Cards */}
|
||
<div className="grid grid-cols-3 gap-4 mb-6">
|
||
<div className="bg-yellow-500/10 border border-yellow-500/30 p-4 rounded-lg text-center">
|
||
<div className="text-yellow-400 font-bold text-2xl">
|
||
{
|
||
myFoundItems.filter((i) => i.status === "pending_verification")
|
||
.length
|
||
}
|
||
</div>
|
||
<div className="text-slate-400 text-sm">Menunggu Konfirmasi</div>
|
||
</div>
|
||
<div className="bg-green-500/10 border border-green-500/30 p-4 rounded-lg text-center">
|
||
<div className="text-green-400 font-bold text-2xl">
|
||
{myFoundItems.filter((i) => i.status === "verified").length}
|
||
</div>
|
||
<div className="text-slate-400 text-sm">Diverifikasi</div>
|
||
</div>
|
||
<div className="bg-slate-500/10 border border-slate-500/30 p-4 rounded-lg text-center">
|
||
<div className="text-slate-400 font-bold text-2xl">
|
||
{myFoundItems.length}
|
||
</div>
|
||
<div className="text-slate-400 text-sm">Total</div>
|
||
</div>
|
||
</div>
|
||
|
||
{loading ? (
|
||
<div className="text-center py-12 text-slate-400">
|
||
<div className="text-6xl mb-4">⏳</div>
|
||
<p>Memuat data...</p>
|
||
</div>
|
||
) : myFoundItems.length > 0 ? (
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||
{myFoundItems.map((item) => {
|
||
const isPendingVerification =
|
||
item.status === "pending_verification";
|
||
const isVerified = item.status === "verified";
|
||
|
||
return (
|
||
<div
|
||
key={item.id}
|
||
className={`bg-gradient-to-br from-slate-700 to-slate-800 border-2 rounded-xl p-5 hover:shadow-xl transition-all ${
|
||
isPendingVerification
|
||
? "border-yellow-500/50 hover:border-yellow-500 shadow-yellow-500/20"
|
||
: isVerified
|
||
? "border-green-500/50 hover:border-green-500"
|
||
: "border-slate-600 hover:border-blue-500"
|
||
}`}
|
||
>
|
||
{/* 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>
|
||
{item.category_name && (
|
||
<p className="text-xs text-slate-400 mt-1">
|
||
🏷️ {item.category_name}
|
||
</p>
|
||
)}
|
||
</div>
|
||
<span
|
||
className={`px-3 py-1 rounded-full text-xs font-bold uppercase tracking-wider ${
|
||
isPendingVerification
|
||
? "bg-yellow-500/20 text-yellow-400 border border-yellow-500/50 animate-pulse"
|
||
: isVerified
|
||
? "bg-green-500/20 text-green-400 border border-green-500/50"
|
||
: Helpers.getStatusBadgeClass(item.status)
|
||
}`}
|
||
>
|
||
{isPendingVerification
|
||
? "⏳ Menunggu"
|
||
: isVerified
|
||
? "✅ Verified"
|
||
: item.status}
|
||
</span>
|
||
</div>
|
||
|
||
{/* Item Details */}
|
||
<div className="space-y-2 mb-4">
|
||
{item.color && (
|
||
<div className="flex items-center gap-2 text-sm text-slate-300">
|
||
<span className="text-blue-400">🎨</span>
|
||
<span>Warna: {item.color}</span>
|
||
</div>
|
||
)}
|
||
{item.location && (
|
||
<div className="flex items-center gap-2 text-sm text-slate-300">
|
||
<span className="text-blue-400">📍</span>
|
||
<span>{item.location}</span>
|
||
</div>
|
||
)}
|
||
{item.date_found && (
|
||
<div className="flex items-center gap-2 text-sm text-slate-300">
|
||
<span className="text-blue-400">📅</span>
|
||
<span>{Helpers.formatDate(item.date_found)}</span>
|
||
</div>
|
||
)}
|
||
{item.reporter_name && (
|
||
<div className="flex items-center gap-2 text-sm text-slate-300">
|
||
<span className="text-blue-400">👤</span>
|
||
<span>Ditemukan oleh: {item.reporter_name}</span>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* Description */}
|
||
{item.description && (
|
||
<div className="bg-slate-900/50 p-3 rounded-lg border border-slate-600 mb-4">
|
||
<strong className="text-xs text-slate-400 uppercase block mb-1">
|
||
Deskripsi:
|
||
</strong>
|
||
<p className="text-sm text-slate-300 line-clamp-3">
|
||
{item.description}
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
{/* Pending Verification Alert */}
|
||
{isPendingVerification && (
|
||
<div className="bg-yellow-500/10 border-2 border-yellow-500/30 p-3 rounded-lg mb-4">
|
||
<div className="flex items-center gap-2 mb-2">
|
||
<span className="text-xl">⚠️</span>
|
||
<strong className="text-yellow-400">
|
||
Konfirmasi Diperlukan
|
||
</strong>
|
||
</div>
|
||
<p className="text-xs text-slate-300">
|
||
Seseorang menemukan barang yang sesuai dengan laporan
|
||
Anda. Silakan konfirmasi apakah ini benar barang Anda.
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
{/* Verified Alert */}
|
||
{isVerified && (
|
||
<div className="bg-green-500/10 border-2 border-green-500/30 p-3 rounded-lg mb-4">
|
||
<div className="flex items-center gap-2 mb-2">
|
||
<span className="text-xl">✅</span>
|
||
<strong className="text-green-400">
|
||
Sudah Diverifikasi
|
||
</strong>
|
||
</div>
|
||
<p className="text-xs text-slate-300">
|
||
Anda telah mengonfirmasi ini barang Anda. Koordinasikan
|
||
pengambilan.
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
{/* Action Buttons */}
|
||
<div className="flex gap-2">
|
||
{isPendingVerification && (
|
||
<>
|
||
{/* Approve Button */}
|
||
<button
|
||
onClick={() => handleApproveItem(item)}
|
||
className="flex-1 px-3 py-2 bg-gradient-to-r from-green-600 to-green-700 text-white text-sm rounded-lg hover:from-green-700 hover:to-green-800 transition shadow-lg font-semibold flex items-center justify-center gap-1"
|
||
>
|
||
<span>✅</span> Terima
|
||
</button>
|
||
|
||
{/* Reject Button */}
|
||
<button
|
||
onClick={() => handleRejectItem(item)}
|
||
className="flex-1 px-3 py-2 bg-gradient-to-r from-red-600 to-red-700 text-white text-sm rounded-lg hover:from-red-700 hover:to-red-800 transition shadow-lg font-semibold flex items-center justify-center gap-1"
|
||
>
|
||
<span>❌</span> Tolak
|
||
</button>
|
||
</>
|
||
)}
|
||
|
||
{/* Detail Button */}
|
||
<button
|
||
onClick={() =>
|
||
handlers.handleViewDetail &&
|
||
handlers.handleViewDetail(item)
|
||
}
|
||
className={`${
|
||
isPendingVerification ? "px-3" : "flex-1"
|
||
} 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 flex items-center justify-center gap-1`}
|
||
>
|
||
<span>📋</span> {isPendingVerification ? "" : "Detail"}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
);
|
||
})}
|
||
</div>
|
||
) : (
|
||
<div className="text-center py-12 text-slate-400">
|
||
<div className="text-6xl mb-4">📭</div>
|
||
<p>Belum ada barang yang dilaporkan ditemukan</p>
|
||
<p className="text-sm mt-2">
|
||
Ketika seseorang menemukan barang Anda, akan muncul di sini
|
||
</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
};
|
||
|
||
window.MyFoundItemsTab = MyFoundItemsTab;
|