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

238 lines
7.5 KiB
JavaScript

const { useState, useEffect } = React;
const UserApp = () => {
const state = useUserState();
const handlers = useUserHandlers(state);
const {
user,
setUser,
activeTab,
setActiveTab,
stats,
items,
setFilteredItems,
searchTerm,
categoryFilter,
showDetailModal,
setShowDetailModal,
selectedItem,
showClaimModal,
setShowClaimModal,
showReportLostModal,
setShowReportLostModal,
showReportFoundModal,
setShowReportFoundModal,
toast,
setToast,
loading,
photoPreview,
setPhotoPreview,
showSelectLostItemModal,
setShowSelectLostItemModal,
suggestedLostItems,
claimInitialData,
categories,
} = state;
useEffect(() => {
if (!AuthUtils.checkAuthAndRedirect("user")) return;
const currentUser = AuthUtils.getCurrentUser();
setUser(currentUser);
handlers.loadData();
}, []);
useEffect(() => {
filterItems();
}, [searchTerm, categoryFilter, items]);
const filterItems = () => {
let filtered = items.filter((item) => {
const matchesSearch =
item.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
item.location.toLowerCase().includes(searchTerm.toLowerCase());
const matchesCategory =
!categoryFilter ||
Helpers.getCategoryValue(item.category_id) === categoryFilter;
return matchesSearch && matchesCategory;
});
setFilteredItems(filtered);
};
return (
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-blue-900 to-slate-900">
<Navbar user={user} onLogout={handlers.handleLogout} userType="user" />
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div className="mb-8">
<h1 className="text-3xl font-bold text-white mb-2">Dashboard User</h1>
<p className="text-slate-400">
Selamat datang di Lost & Found System
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<StatCard
title="Barang Hilang Saya"
value={stats.lost_items || 0}
icon="😢"
/>
<StatCard
title="Barang yang Saya Temukan"
value={stats.found_items || 0}
icon="🎉"
/>
<StatCard title="Klaim Saya" value={stats.claims || 0} icon="🤝" />
</div>
<div className="flex gap-2 mb-6 flex-wrap">
<button
onClick={() => setActiveTab("browse")}
className={`px-6 py-3 rounded-xl font-semibold transition ${
activeTab === "browse"
? "bg-gradient-to-r from-blue-600 to-blue-700 text-white shadow-lg shadow-blue-500/50"
: "bg-slate-800 text-slate-300 hover:bg-slate-700 border border-slate-700"
}`}
>
📦 Barang Ditemukan
</button>
<button
onClick={() => setActiveTab("public-lost")}
className={`px-6 py-3 rounded-xl font-semibold transition ${
activeTab === "public-lost"
? "bg-gradient-to-r from-blue-600 to-blue-700 text-white shadow-lg shadow-blue-500/50"
: "bg-slate-800 text-slate-300 hover:bg-slate-700 border border-slate-700"
}`}
>
😢 Barang Hilang
</button>
<button
onClick={() => setActiveTab("lost")}
className={`px-6 py-3 rounded-xl font-semibold transition ${
activeTab === "lost"
? "bg-gradient-to-r from-blue-600 to-blue-700 text-white shadow-lg shadow-blue-500/50"
: "bg-slate-800 text-slate-300 hover:bg-slate-700 border border-slate-700"
}`}
>
😢 Barang Hilang Saya
</button>
<button
onClick={() => setActiveTab("found")}
className={`px-6 py-3 rounded-xl font-semibold transition ${
activeTab === "found"
? "bg-gradient-to-r from-blue-600 to-blue-700 text-white shadow-lg shadow-blue-500/50"
: "bg-slate-800 text-slate-300 hover:bg-slate-700 border border-slate-700"
}`}
>
🎉 Barang yang Saya Temukan
</button>
<button
onClick={() => setActiveTab("claims")}
className={`px-6 py-3 rounded-xl font-semibold transition ${
activeTab === "claims"
? "bg-gradient-to-r from-blue-600 to-blue-700 text-white shadow-lg shadow-blue-500/50"
: "bg-slate-800 text-slate-300 hover:bg-slate-700 border border-slate-700"
}`}
>
🤝 Klaim Saya
</button>
</div>
{activeTab === "browse" && (
<BrowseTab state={state} handlers={handlers} />
)}
{activeTab === "public-lost" && (
<PublicLostItemsTab state={state} handlers={handlers} />
)}
{activeTab === "lost" && (
<MyLostItemsTab
state={state}
handlers={handlers}
myClaims={state.myClaims}
/>
)}
{activeTab === "found" && (
<MyFoundItemsTab state={state} handlers={handlers} />
)}
{activeTab === "claims" && (
<MyClaimsTab state={state} handlers={handlers} />
)}
</div>
<SelectLostItemModal
isOpen={showSelectLostItemModal}
onClose={() => state.setShowSelectLostItemModal(false)}
lostItems={suggestedLostItems}
onSelect={handlers.handleSelectLostItemForClaim}
onManual={handlers.handleManualClaimEntry}
/>
<FoundOptionModal
isOpen={state.showFoundOptionModal}
onClose={() => state.setShowFoundOptionModal(false)}
onSelectOption={handlers.handleSelectFoundOption}
/>
<DirectClaimModal
isOpen={state.showDirectClaimModal}
onClose={() => state.setShowDirectClaimModal(false)}
onSubmit={handlers.handleDirectClaimSubmit}
loading={loading}
lostItem={state.selectedLostItemForFound}
/>
<DetailModalUser
isOpen={state.showDetailModal}
onClose={() => state.setShowDetailModal(false)}
item={state.selectedItem}
user={state.user}
onClaim={handlers.handleClaim}
/>
<ClaimModalUser
isOpen={showClaimModal}
onClose={() => state.setShowClaimModal(false)}
onSubmit={handlers.submitClaim}
loading={loading}
initialData={claimInitialData}
categories={categories}
/>
<ReportLostModalUser
isOpen={showReportLostModal}
onClose={() => state.setShowReportLostModal(false)}
onSubmit={handlers.submitReportLost}
loading={loading}
categories={categories}
/>
<ReportFoundModalUser
isOpen={showReportFoundModal}
onClose={() => state.setShowReportFoundModal(false)}
onSubmit={handlers.submitReportFound}
loading={loading}
photoPreview={photoPreview}
onPhotoChange={handlers.handlePhotoChange}
user={user}
categories={categories}
/>
{state.toast && (
<Toast
message={state.toast.message}
type={state.toast.type}
onClose={() => state.setToast(null)}
/>
)}
<AIChatbot />
</div>
);
};
ReactDOM.render(<UserApp />, document.getElementById("root"));