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

351 lines
14 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.

// web/js/pages/user/UserTabsBrowse.js
// ✅ 1. Komponen BrowseTab (Barang Ditemukan)
const BrowseTab = ({ state, handlers }) => {
const {
filteredItems,
loading,
searchTerm,
setSearchTerm,
categoryFilter,
setCategoryFilter,
categories,
user,
} = state;
const { handleViewDetail, handleClaim } = handlers;
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="p-6 border-b border-slate-700">
<h2 className="text-xl font-semibold mb-4 text-white">
📦 Barang Ditemukan
</h2>
<div className="flex gap-3 flex-wrap">
<input
type="text"
placeholder="Cari barang (nama/lokasi)..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="flex-1 min-w-[200px] px-4 py-2 bg-slate-700 border-2 border-slate-600 rounded-xl text-white placeholder-slate-400 focus:border-blue-500 focus:outline-none"
/>
<select
value={categoryFilter}
onChange={(e) => setCategoryFilter(e.target.value)}
className="px-4 py-2 bg-slate-700 border-2 border-slate-600 rounded-xl text-white focus:border-blue-500 focus:outline-none"
>
<option value="">Semua Kategori</option>
{categories &&
categories.map((cat) => (
<option key={cat.id} value={cat.slug || cat.id}>
{cat.name}
</option>
))}
</select>
</div>
</div>
<div className="p-6">
{loading ? (
<div className="text-center py-12 text-slate-400">
<div className="text-6xl mb-4 animate-pulse"></div>
<p>Memuat data...</p>
</div>
) : (
<>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{filteredItems.map((item) => (
<ItemCard
key={item.id}
item={item}
currentUserId={user?.id}
onViewDetail={handleViewDetail}
onClaim={handleClaim}
showActions={true}
/>
))}
</div>
{filteredItems.length === 0 && (
<div className="text-center py-12 text-slate-400">
<div className="text-6xl mb-4">📦</div>
<p>Tidak ada barang ditemukan sesuai pencarian.</p>
</div>
)}
</>
)}
</div>
</div>
);
};
// ✅ 2. Komponen PublicLostItemsTab (Barang Hilang Publik)
const PublicLostItemsTab = ({ state, handlers }) => {
const { publicLostItems, loading, user } = state;
const [showContactModal, setShowContactModal] = React.useState(false);
const [selectedLostItem, setSelectedLostItem] = React.useState(null);
const [showDetailModal, setShowDetailModal] = React.useState(false);
const [selectedDetailItem, setSelectedDetailItem] = React.useState(null);
const handleShowContact = (item) => {
setSelectedLostItem(item);
setShowContactModal(true);
};
const handleShowDetail = (item) => {
setSelectedDetailItem(item);
setShowDetailModal(true);
};
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-4">
<h2 className="text-xl font-semibold text-white">
Semua Laporan Barang Hilang
</h2>
<div className="text-slate-400 text-sm">
{publicLostItems.length} laporan
</div>
</div>
{loading ? (
<div className="text-center py-12 text-slate-400">
<div className="text-6xl mb-4"></div>
<p>Memuat data...</p>
</div>
) : publicLostItems.length > 0 ? (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{publicLostItems.map((item) => {
const isMine = user && user.id === item.user_id;
return (
<div
key={item.id}
className="bg-gradient-to-br from-slate-700 to-slate-800 border-2 border-slate-600 rounded-xl p-5 hover:border-blue-500 hover:shadow-xl hover:shadow-blue-500/20 transition-all"
>
{/* Header */}
<div className="flex justify-between items-start mb-3">
<h3 className="text-lg font-semibold text-white flex-1">
{item.name}
</h3>
{/* ✅ Tampilkan Badge jika barang sendiri */}
{isMine ? (
<span className="px-2 py-1 rounded text-[10px] font-bold bg-blue-500/20 text-blue-400 border border-blue-500/50">
BARANG SAYA
</span>
) : (
<span
className={`px-3 py-1 rounded-full text-xs font-semibold ${Helpers.getStatusBadgeClass(
item.status
)}`}
>
{item.status}
</span>
)}
</div>
<div className="space-y-2 mb-4">
<div className="flex items-center gap-2 text-sm text-slate-300">
<span className="text-blue-400">🏷</span>
<span>{item.category || item.category_name}</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>
)}
<div className="flex items-center gap-2 text-sm text-slate-300">
<span className="text-blue-400">👤</span>
<span>{item.user_name}</span>
</div>
</div>
<div className="bg-slate-900/50 p-3 rounded-lg border border-slate-700 mb-4">
<p className="text-sm text-slate-300 line-clamp-3">
{item.description}
</p>
</div>
<div className="flex gap-2">
<button
onClick={() => handleShowDetail(item)}
className="flex-1 px-3 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"
>
📋 Detail
</button>
{item.status === "active" && !isMine && (
<button
onClick={() => handlers.handleOpenFoundOption(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"
>
Saya Menemukan
</button>
)}
{isMine && (
<div className="flex-1 px-3 py-2 text-center text-xs text-slate-400 border border-slate-600 rounded-lg">
Kelola di tab "Barang Hilang Saya"
</div>
)}
</div>
</div>
);
})}
</div>
) : (
<div className="text-center py-12 text-slate-400">
<div className="text-6xl mb-4">😢</div>
<p>Belum ada laporan barang hilang</p>
</div>
)}
{/* Modal Detail Barang Hilang */}
<Modal
isOpen={showDetailModal}
onClose={() => setShowDetailModal(false)}
title="📋 Detail Barang Hilang"
>
{selectedDetailItem && (
<div className="space-y-4">
<div className="bg-gradient-to-r from-slate-700 to-slate-800 p-4 rounded-xl border border-slate-600">
<h3 className="text-xl font-bold text-white mb-1">
{selectedDetailItem.name}
</h3>
<div className="flex flex-wrap gap-2 text-sm">
<span className="text-blue-400 font-medium">
🏷{" "}
{selectedDetailItem.category ||
selectedDetailItem.category_name ||
"-"}
</span>
<span className="text-slate-500"></span>
<span className="text-slate-300">
📅 {Helpers.formatDate(selectedDetailItem.date_lost)}
</span>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="bg-slate-700/30 p-3 rounded-lg border border-slate-600">
<p className="text-xs text-slate-400 uppercase font-bold mb-1">
📍 Lokasi Hilang
</p>
<p className="text-white text-sm">
{selectedDetailItem.location || "-"}
</p>
</div>
<div className="bg-slate-700/30 p-3 rounded-lg border border-slate-600">
<p className="text-xs text-slate-400 uppercase font-bold mb-1">
🎨 Warna/Ciri
</p>
<p className="text-white text-sm">
{selectedDetailItem.color || "-"}
</p>
</div>
</div>
<div className="bg-slate-900/50 p-4 rounded-xl border border-slate-600">
<p className="text-xs text-slate-400 uppercase font-bold mb-2">
📝 Deskripsi Lengkap
</p>
<p className="text-slate-300 text-sm leading-relaxed italic">
"{selectedDetailItem.description}"
</p>
</div>
<div className="bg-blue-500/10 p-3 rounded-lg border border-blue-500/20 flex items-center gap-3">
<div className="bg-blue-600 w-10 h-10 rounded-full flex items-center justify-center text-lg shadow">
👤
</div>
<div>
<p className="text-xs text-blue-300 font-bold uppercase">
Dilaporkan Oleh
</p>
<p className="text-white font-medium">
{selectedDetailItem.user_name}
</p>
</div>
</div>
<button
onClick={() => setShowDetailModal(false)}
className="w-full py-3 bg-slate-700 hover:bg-slate-600 text-white rounded-xl font-semibold transition"
>
Tutup
</button>
</div>
)}
</Modal>
{/* Modal Kontak (Jika diperlukan) */}
<Modal
isOpen={showContactModal}
onClose={() => setShowContactModal(false)}
title="👋 Anda Menemukan Barang Ini?"
>
{selectedLostItem && (
<div className="text-center space-y-6">
<div className="bg-slate-700/50 p-6 rounded-2xl border border-slate-600">
<div className="w-20 h-20 bg-gradient-to-br from-blue-500 to-blue-600 rounded-full mx-auto flex items-center justify-center text-3xl shadow-lg mb-4">
👤
</div>
<p className="text-slate-400 mb-1">Silakan hubungi pemilik:</p>
<h3 className="text-2xl font-bold text-white mb-2">
{selectedLostItem.user_name}
</h3>
{selectedLostItem.user_contact ? (
<a
href={`https://wa.me/${selectedLostItem.user_contact
.replace(/^0/, "62")
.replace(/\D/g, "")}`}
target="_blank"
className="inline-flex items-center gap-2 px-6 py-2 bg-green-600 hover:bg-green-700 text-white rounded-full font-semibold transition shadow-lg"
>
<span>📞</span> Hubungi via WhatsApp
</a>
) : (
<div className="text-yellow-400 text-sm bg-yellow-400/10 py-2 px-4 rounded-lg inline-block">
Kontak tidak ditampilkan secara publik
</div>
)}
</div>
<div className="relative">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-slate-700"></div>
</div>
<div className="relative flex justify-center text-sm">
<span className="px-2 bg-slate-800 text-slate-400">Atau</span>
</div>
</div>
<div className="bg-blue-500/10 border border-blue-500/30 p-4 rounded-xl text-left flex gap-4">
<div className="text-3xl">📝</div>
<div>
<h4 className="font-bold text-blue-400 mb-1">
Laporkan Temuan
</h4>
<p className="text-sm text-slate-300 mb-2">
Agar lebih aman, Anda bisa melaporkan barang ini sebagai
"Ditemukan" di sistem kami.
</p>
<button
onClick={() => {
setShowContactModal(false);
}}
className="text-xs text-white bg-blue-600 hover:bg-blue-700 px-3 py-1 rounded transition"
>
Buka Menu "Barang yang Saya Temukan"
</button>
</div>
</div>
</div>
)}
</Modal>
</div>
);
};
// Export ke window agar bisa diakses oleh UserApp
window.BrowseTab = BrowseTab;
window.PublicLostItemsTab = PublicLostItemsTab;