"use client"; import { create } from "zustand"; import { persist } from "zustand/middleware"; import { authService } from "../services/authService"; import api from "../services/api"; import { useCartStore } from "./cartStore"; import { usePetStore } from "./usePetStore"; export type UserRole = "User_Guest" | "User_PetOwner" | "User_Partner"; export interface Address { id: string; title: string; receptorName: string; phone: string; province: string; city: string; detail: string; zipCode: string; isDefault: boolean; } export interface Transaction { id: string; type: 'top_up' | 'purchase'; amount: number; date: string; status: 'success' | 'failed' | 'pending'; } interface UserProfile { firstName: string; lastName: string; email: string; mobile: string; walletBalance: number; charityDonationTotal: number; addresses: Address[]; transactions: Transaction[]; } interface UserStore { role: UserRole; isLoggedIn: boolean; profile: UserProfile; setRole: (role: UserRole) => void; setLoggedIn: (isLoggedIn: boolean) => void; updateProfile: (profile: Partial) => Promise; addAddress: (address: Address) => Promise; updateAddress: (id: string, address: Address) => Promise; deleteAddress: (id: string) => Promise; setDefaultAddress: (id: string) => Promise; topUpWallet: (amount: number) => Promise; logout: () => void; fetchProfile: () => Promise; } export const useUserStore = create()( persist( (set) => ({ role: "User_Guest", isLoggedIn: false, profile: { firstName: "", lastName: "", email: "", mobile: "", walletBalance: 0, charityDonationTotal: 0, addresses: [], transactions: [], }, setRole: (role) => set({ role }), setLoggedIn: (isLoggedIn) => set({ isLoggedIn }), updateProfile: async (updates) => { try { const profileData = await authService.updateProfile(updates); set((state) => ({ profile: { ...state.profile, firstName: profileData.firstName, lastName: profileData.lastName, email: profileData.email, mobile: profileData.mobile || "", } })); } catch (error) { console.error("Failed to update profile:", error); throw error; } }, addAddress: async (address) => { try { // Remove ID so backend generates UUID const { id, ...addressData } = address; await api.post('/users/addresses', addressData); await useUserStore.getState().fetchProfile(); } catch (error) { console.error("Failed to add address:", error); throw error; } }, updateAddress: async (id, updated) => { try { const { id: _, ...addressData } = updated; await api.patch(`/users/addresses/${id}`, addressData); await useUserStore.getState().fetchProfile(); } catch (error) { console.error("Failed to update address:", error); throw error; } }, deleteAddress: async (id) => { try { await api.delete(`/users/addresses/${id}`); await useUserStore.getState().fetchProfile(); } catch (error) { console.error("Failed to delete address:", error); throw error; } }, setDefaultAddress: async (id) => { try { await api.patch(`/users/addresses/${id}/default`); await useUserStore.getState().fetchProfile(); } catch (error) { console.error("Failed to set default address:", error); throw error; } }, topUpWallet: async (amount) => { try { await api.post('/users/wallet/top-up', { amount }); await useUserStore.getState().fetchProfile(); } catch (error) { console.error("Failed to top-up wallet:", error); throw error; } }, logout: () => { authService.logout(); set({ role: "User_Guest", isLoggedIn: false, profile: { firstName: "", lastName: "", email: "", mobile: "", walletBalance: 0, charityDonationTotal: 0, addresses: [], transactions: [] }}); }, fetchProfile: async () => { try { const profileData = await authService.getProfile(); set((state) => { const backendWallet = Number(profileData.walletBalance || 0); const backendCharity = Number(profileData.charityDonationTotal || 0); const backendTransactions = (profileData as any).walletTransactions?.map((t: any) => ({ id: t.id, type: t.type === 'deposit' ? 'top_up' : 'purchase', amount: Number(t.amount), date: t.createdAt, status: t.status === 'completed' ? 'success' : t.status === 'failed' ? 'failed' : 'pending' })) || []; return { isLoggedIn: true, role: (profileData.role as UserRole) || "User_PetOwner", profile: { firstName: profileData.firstName, lastName: profileData.lastName, email: profileData.email, mobile: profileData.mobile || "", // Keep local wallet balance if backend returns 0 and local has a non-zero balance walletBalance: backendWallet > 0 ? backendWallet : (state.profile.walletBalance || 0), charityDonationTotal: backendCharity > 0 ? backendCharity : (state.profile.charityDonationTotal || 0), addresses: (profileData as any).addresses?.length > 0 ? (profileData as any).addresses : state.profile.addresses, transactions: backendTransactions.length > 0 ? backendTransactions : state.profile.transactions } }; }); // Sync orders list to CartStore while preserving local petId & address mappings if (profileData.orders) { const currentLocalOrders = useCartStore.getState().orders; const mergedOrders = profileData.orders.map((bo: any) => { const localMatch = currentLocalOrders.find(lo => lo.id === bo.id); return { ...bo, petId: bo.petId || bo.pet?.id || localMatch?.petId, shippingAddress: bo.shippingAddress || localMatch?.shippingAddress }; }); useCartStore.getState().setOrders(mergedOrders); } // Sync pets list to PetStore if (profileData.pets) { usePetStore.getState().setPets(profileData.pets); } } catch (error) { console.error("Failed to fetch user profile:", error); authService.logout(); set({ isLoggedIn: false, role: "User_Guest" }); } }, }), { name: "canina-user" } ) );