import { create } from 'zustand'; import { persist, createJSONStorage } from 'zustand/middleware'; import { UserAccount, LeadData, AdminConfig, WeddingStyle, GeneratedResult, CompositionMode, Resolution, SubjectType, GenerationStatus, Language, PointHistory, FeedbackItem, GenerationLog } from './types'; import { TRANSLATIONS } from './constants/translations'; // --- Default Configuration --- const DEFAULT_CONFIG: AdminConfig = { promoText: "🎉 Spring Wedding Expo: Book online today and get a Free Makeup Trial + ¥500 Voucher!", promoEnds: new Date(Date.now() + 86400000).toISOString(), contactPhone: '0592-8888888', showBanner: true, footerAddress: "No. 188, Huandao Road, Siming District, Xiamen", logoUrl: "", // Default empty shareTitle: "Help me choose a wedding style!", shareDesc: "I found this amazing AI fitting room at Romantic Life.", shareImage: "", redPacketMax: 2000, slashDifficulty: 0.98, crmApiUrl: '', geminiApiKey: '', geminiApiUrl: '', // Default empty pointsShare: 10, pointsInvite: 50, pointsBook: 100, pointsVipCost: 100, // Updated to user's domain qrCodeUrl: "https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=https://xmlove520.dpdns.org" }; // --- USER STORE --- interface UserState { currentUser: UserAccount | undefined; allUsers: UserAccount[]; leads: LeadData[]; feedback: FeedbackItem[]; guestFavorites: string[]; // NEW: Favorites for non-logged in users logs: GenerationLog[]; // NEW: Analytics Logs // Actions login: (phone: string, password?: string) => { success: boolean; msg: string }; register: (phone: string, name: string, pass: string) => { success: boolean; msg: string }; logout: () => void; updateUser: (id: string, updates: Partial) => void; resetPassword: (phone: string, newPass: string) => boolean; addPoints: (amount: number, reason: string) => void; toggleFavorite: (styleId: string) => void; // Admin Actions addLead: (lead: LeadData) => void; updateLeadStatus: (id: string, status: LeadData['status']) => void; deleteLead: (id: string) => void; setLeads: (leads: LeadData[]) => void; // Feedback Actions addFeedback: (item: FeedbackItem) => void; // Analytics Actions addLog: (log: GenerationLog) => void; } export const useUserStore = create()( persist( (set, get) => ({ currentUser: undefined, allUsers: [], leads: [], feedback: [], guestFavorites: [], logs: [], login: (phone, password) => { const { allUsers } = get(); const user = allUsers.find(u => u.phone === phone); if (user) { if (user.password && password && user.password !== password) { return { success: false, msg: "Incorrect password" }; } set({ currentUser: user }); return { success: true, msg: `Welcome ${user.name}` }; } return { success: false, msg: "User not found" }; }, register: (phone, name, pass) => { const { allUsers } = get(); if (allUsers.find(u => u.phone === phone)) { return { success: false, msg: "Phone already registered" }; } const newUser: UserAccount = { id: 'user_' + Date.now(), name, phone, password: pass, points: 100, isVip: false, joinDate: Date.now(), history: [], role: 'user', redPacketBalance: 1980, slashProgress: {}, favorites: [] }; set({ allUsers: [...allUsers, newUser], currentUser: newUser }); return { success: true, msg: "Registration successful" }; }, logout: () => set({ currentUser: undefined }), updateUser: (id, updates) => { const { allUsers, currentUser } = get(); const newAllUsers = allUsers.map(u => u.id === id ? { ...u, ...updates } : u); let newCurrentUser = currentUser; if (currentUser && currentUser.id === id) { newCurrentUser = { ...currentUser, ...updates }; } set({ allUsers: newAllUsers, currentUser: newCurrentUser }); }, resetPassword: (phone, newPass) => { const { allUsers } = get(); const index = allUsers.findIndex(u => u.phone === phone); if (index !== -1) { const updatedUsers = [...allUsers]; updatedUsers[index] = { ...updatedUsers[index], password: newPass }; set({ allUsers: updatedUsers }); return true; } return false; }, addPoints: (amount, reason) => { const { currentUser, updateUser } = get(); if (!currentUser) return; const newHistory: PointHistory = { id: Date.now().toString(), action: 'share', points: amount, timestamp: Date.now(), desc: reason }; updateUser(currentUser.id, { points: currentUser.points + amount, history: [...currentUser.history, newHistory] }); }, toggleFavorite: (styleId) => { const { currentUser, updateUser, guestFavorites } = get(); if (currentUser) { // Update User Account const currentFavs = currentUser.favorites || []; const newFavs = currentFavs.includes(styleId) ? currentFavs.filter(id => id !== styleId) : [...currentFavs, styleId]; updateUser(currentUser.id, { favorites: newFavs }); } else { // Update Guest Favorites const newFavs = guestFavorites.includes(styleId) ? guestFavorites.filter(id => id !== styleId) : [...guestFavorites, styleId]; set({ guestFavorites: newFavs }); } }, // Lead Actions addLead: (lead) => set(state => ({ leads: [lead, ...state.leads] })), updateLeadStatus: (id, status) => set(state => ({ leads: state.leads.map(l => l.id === id ? { ...l, status } : l) })), deleteLead: (id) => set(state => ({ leads: state.leads.filter(l => l.id !== id) })), setLeads: (leads) => set({ leads }), // Feedback Actions addFeedback: (item) => set(state => ({ feedback: [item, ...state.feedback] })), // Analytics addLog: (log) => set(state => ({ logs: [log, ...state.logs].slice(0, 2000) })), // Keep last 2000 logs }), { name: 'rl_user_storage', partialize: (state) => ({ allUsers: state.allUsers, leads: state.leads, currentUser: state.currentUser, feedback: state.feedback, guestFavorites: state.guestFavorites, logs: state.logs }), } ) ); // --- UI STORE --- interface UIState { language: Language; adminConfig: AdminConfig; // Modals Visibility modals: { auth: boolean; userCenter: boolean; admin: boolean; about: boolean; feedback: boolean; share: boolean; consult: boolean; analysis: boolean; redPacket: boolean; slash: boolean; }; // Actions setLanguage: (lang: Language) => void; setAdminConfig: (config: AdminConfig) => void; toggleModal: (modal: keyof UIState['modals'], isOpen: boolean) => void; closeAllModals: () => void; // Toast toastMsg: string | null; showToast: (msg: string) => void; } export const useUIStore = create()( persist( (set) => ({ language: 'zh', adminConfig: DEFAULT_CONFIG, modals: { auth: false, userCenter: false, admin: false, about: false, feedback: false, share: false, consult: false, analysis: false, redPacket: false, slash: false, }, toastMsg: null, setLanguage: (lang) => set({ language: lang }), setAdminConfig: (config) => set({ adminConfig: config }), toggleModal: (modal, isOpen) => set(state => ({ modals: { ...state.modals, [modal]: isOpen } })), closeAllModals: () => set(state => { const closed = Object.keys(state.modals).reduce((acc, key) => ({...acc, [key]: false}), {} as any); return { modals: closed }; }), showToast: (msg) => { set({ toastMsg: msg }); setTimeout(() => set({ toastMsg: null }), 3000); } }), { name: 'rl_ui_storage', partialize: (state) => ({ language: state.language, adminConfig: state.adminConfig }), // Don't persist modal state } ) ); // --- GENERATION STORE --- interface GenerationState { uploadedImages: string[]; selectedStyle: WeddingStyle | null; customStyleImage: string | null; // Config filter: string; blurAmount: number; compositionMode: CompositionMode; resolution: Resolution; subjectType: SubjectType; customPrompt: string; // Results results: Record; status: GenerationStatus; progress: { current: number, total: number, statusMsg?: string } | null; errorMsg: string | null; // AI Analysis isScanning: boolean; scanStep: number; recommendedStyleIds: string[]; analysisResult: { faceShape: string; skinTone: string; bestVibe: string; }; // Actions setUploadedImages: (images: string[]) => void; setSelectedStyle: (style: WeddingStyle | null) => void; setCustomStyleImage: (img: string | null) => void; setGenerationConfig: (config: Partial<{ filter: string, blurAmount: number, compositionMode: CompositionMode, resolution: Resolution, subjectType: SubjectType, customPrompt: string }>) => void; setStatus: (status: GenerationStatus) => void; setProgress: (progress: GenerationState['progress']) => void; setErrorMsg: (msg: string | null) => void; addResult: (result: GeneratedResult) => void; setResults: (results: Record) => void; resetGeneration: () => void; // Analysis Actions startScanning: () => void; setScanStep: (step: number) => void; setAnalysisData: (recs: string[], result: { faceShape: string; skinTone: string; bestVibe: string; }) => void; stopScanning: () => void; } export const useGenerationStore = create()((set) => ({ uploadedImages: [], selectedStyle: null, customStyleImage: null, filter: 'none', blurAmount: 0, compositionMode: 'classic', resolution: 'standard', subjectType: 'female', customPrompt: '', results: {}, status: 'idle', progress: null, errorMsg: null, isScanning: false, scanStep: 0, recommendedStyleIds: [], analysisResult: { faceShape: '', skinTone: '', bestVibe: '' }, setUploadedImages: (images) => set({ uploadedImages: images }), setSelectedStyle: (style) => set({ selectedStyle: style }), setCustomStyleImage: (img) => set({ customStyleImage: img }), setGenerationConfig: (config) => set(state => ({ ...state, ...config })), setStatus: (status) => set({ status }), setProgress: (progress) => set({ progress }), setErrorMsg: (msg) => set({ errorMsg: msg }), addResult: (result) => set(state => ({ results: { ...state.results, [result.styleId]: result } })), setResults: (results) => set({ results }), resetGeneration: () => set({ status: 'idle', results: {}, uploadedImages: [], selectedStyle: null, customStyleImage: null, filter: 'none', blurAmount: 0, customPrompt: '', compositionMode: 'classic', resolution: 'standard', progress: null, recommendedStyleIds: [] }), startScanning: () => set({ isScanning: true, scanStep: 0 }), setScanStep: (step) => set({ scanStep: step }), setAnalysisData: (recs, result) => set({ recommendedStyleIds: recs, analysisResult: result }), stopScanning: () => set({ isScanning: false }) }));