import { create } from 'zustand'; import { persist, createJSONStorage } from 'zustand/middleware'; export interface User { id: string; email: string; name: string; role: 'admin' | 'manager' | 'baker' | 'staff'; permissions: string[]; tenantId: string; tenantName: string; avatar?: string; lastLogin?: string; preferences?: { language: string; timezone: string; theme: 'light' | 'dark'; notifications: boolean; }; } export interface AuthState { // State user: User | null; token: string | null; refreshToken: string | null; isAuthenticated: boolean; isLoading: boolean; error: string | null; // Actions login: (email: string, password: string) => Promise; logout: () => void; refreshAuth: () => Promise; updateUser: (updates: Partial) => void; clearError: () => void; setLoading: (loading: boolean) => void; // Permission helpers hasPermission: (permission: string) => boolean; hasRole: (role: string) => boolean; canAccess: (resource: string, action: string) => boolean; } // Mock API functions (replace with actual API calls) const mockLogin = async (email: string, password: string): Promise<{ user: User; token: string; refreshToken: string }> => { // Simulate API delay await new Promise(resolve => setTimeout(resolve, 1000)); if (email === 'admin@bakery.com' && password === 'admin12345') { return { user: { id: '1', email: 'admin@bakery.com', name: 'Admin User', role: 'admin', permissions: ['*'], tenantId: 'tenant-1', tenantName: 'Panadería San Miguel', avatar: undefined, lastLogin: new Date().toISOString(), preferences: { language: 'es', timezone: 'Europe/Madrid', theme: 'light', notifications: true, }, }, token: 'mock-jwt-token', refreshToken: 'mock-refresh-token', }; } throw new Error('Credenciales inválidas'); }; const mockRefreshToken = async (refreshToken: string): Promise<{ token: string; refreshToken: string }> => { await new Promise(resolve => setTimeout(resolve, 500)); if (refreshToken === 'mock-refresh-token') { return { token: 'new-mock-jwt-token', refreshToken: 'new-mock-refresh-token', }; } throw new Error('Invalid refresh token'); }; export const useAuthStore = create()( persist( (set, get) => ({ // Initial state user: null, token: null, refreshToken: null, isAuthenticated: false, isLoading: false, error: null, // Actions login: async (email: string, password: string) => { try { set({ isLoading: true, error: null }); const response = await mockLogin(email, password); set({ user: response.user, token: response.token, refreshToken: response.refreshToken, isAuthenticated: true, isLoading: false, error: null, }); } catch (error) { set({ user: null, token: null, refreshToken: null, isAuthenticated: false, isLoading: false, error: error instanceof Error ? error.message : 'Error de autenticación', }); throw error; } }, logout: () => { set({ user: null, token: null, refreshToken: null, isAuthenticated: false, isLoading: false, error: null, }); }, refreshAuth: async () => { try { const { refreshToken } = get(); if (!refreshToken) { throw new Error('No refresh token available'); } set({ isLoading: true }); const response = await mockRefreshToken(refreshToken); set({ token: response.token, refreshToken: response.refreshToken, isLoading: false, error: null, }); } catch (error) { set({ user: null, token: null, refreshToken: null, isAuthenticated: false, isLoading: false, error: error instanceof Error ? error.message : 'Error al renovar sesión', }); throw error; } }, updateUser: (updates: Partial) => { const { user } = get(); if (user) { set({ user: { ...user, ...updates }, }); } }, clearError: () => { set({ error: null }); }, setLoading: (loading: boolean) => { set({ isLoading: loading }); }, // Permission helpers hasPermission: (permission: string): boolean => { const { user } = get(); if (!user) return false; // Admin has all permissions if (user.permissions.includes('*')) return true; return user.permissions.includes(permission); }, hasRole: (role: string): boolean => { const { user } = get(); return user?.role === role; }, canAccess: (resource: string, action: string): boolean => { const { user, hasPermission } = get(); if (!user) return false; // Check specific permission if (hasPermission(`${resource}:${action}`)) return true; // Check wildcard permissions if (hasPermission(`${resource}:*`)) return true; if (hasPermission('*')) return true; // Role-based access fallback switch (user.role) { case 'admin': return true; case 'manager': return ['inventory', 'production', 'sales', 'reports'].includes(resource); case 'baker': return ['production', 'inventory'].includes(resource) && ['read', 'update'].includes(action); case 'staff': return ['inventory', 'sales'].includes(resource) && action === 'read'; default: return false; } }, }), { name: 'auth-storage', storage: createJSONStorage(() => localStorage), partialize: (state) => ({ user: state.user, token: state.token, refreshToken: state.refreshToken, isAuthenticated: state.isAuthenticated, }), } ) ); // Selectors for common use cases export const useAuthUser = () => useAuthStore((state) => state.user); export const useIsAuthenticated = () => useAuthStore((state) => state.isAuthenticated); export const useAuthLoading = () => useAuthStore((state) => state.isLoading); export const useAuthError = () => useAuthStore((state) => state.error); export const usePermissions = () => useAuthStore((state) => ({ hasPermission: state.hasPermission, hasRole: state.hasRole, canAccess: state.canAccess, })); // Hook for auth actions export const useAuthActions = () => useAuthStore((state) => ({ login: state.login, logout: state.logout, refreshAuth: state.refreshAuth, updateUser: state.updateUser, clearError: state.clearError, setLoading: state.setLoading, }));