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

309 lines
12 KiB
JavaScript
Raw 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.

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;