canina/frontend/application/lib/store/userStore.ts
parsa aghaei 7615aa0e51 fix: resolve seed encoding, search param, and wiki data source issues
- Fix seed-products.ts TS error (implicit any) and BOM handling
- Re-run full seed to restore correct Persian encoding in DB
- Fix productService query→search param mismatch
- Fix IngredientWiki hardcoded port 4000→use settingsStore
- Restore seed-products-data.json from git after accidental corruption
2026-07-11 15:40:49 +03:30

197 lines
5.9 KiB
TypeScript

"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<UserProfile>) => Promise<void>;
addAddress: (address: Address) => Promise<void>;
updateAddress: (id: string, address: Address) => Promise<void>;
deleteAddress: (id: string) => Promise<void>;
setDefaultAddress: (id: string) => Promise<void>;
topUpWallet: (amount: number) => Promise<void>;
logout: () => void;
fetchProfile: () => Promise<void>;
}
export const useUserStore = create<UserStore>()(
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({
isLoggedIn: true,
role: (profileData.role as UserRole) || "User_PetOwner",
profile: {
firstName: profileData.firstName,
lastName: profileData.lastName,
email: profileData.email,
mobile: profileData.mobile || "",
walletBalance: Number(profileData.walletBalance),
charityDonationTotal: Number(profileData.charityDonationTotal),
addresses: (profileData as any).addresses || [],
transactions: (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'
})) || []
}
});
// Sync orders list to CartStore
if (profileData.orders) {
useCartStore.getState().setOrders(profileData.orders);
}
// 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" }
)
);