import React, { createContext, useContext, useReducer, useEffect, ReactNode } from 'react'; export interface Bakery { id: string; name: string; logo?: string; role: 'owner' | 'manager' | 'baker' | 'staff'; status: 'active' | 'inactive'; address?: string; description?: string; settings?: { timezone: string; currency: string; language: string; }; permissions?: string[]; } interface BakeryState { bakeries: Bakery[]; currentBakery: Bakery | null; isLoading: boolean; error: string | null; } type BakeryAction = | { type: 'SET_LOADING'; payload: boolean } | { type: 'SET_ERROR'; payload: string | null } | { type: 'SET_BAKERIES'; payload: Bakery[] } | { type: 'SET_CURRENT_BAKERY'; payload: Bakery } | { type: 'ADD_BAKERY'; payload: Bakery } | { type: 'UPDATE_BAKERY'; payload: { id: string; updates: Partial } } | { type: 'REMOVE_BAKERY'; payload: string }; const initialState: BakeryState = { bakeries: [], currentBakery: null, isLoading: false, error: null, }; // Mock bakeries data const mockBakeries: Bakery[] = [ { id: '1', name: 'Panadería San Miguel', logo: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=100&h=100&fit=crop&crop=center', role: 'owner', status: 'active', address: 'Calle Mayor 123, Madrid, 28013', description: 'Panadería tradicional familiar con más de 30 años de experiencia.', settings: { timezone: 'Europe/Madrid', currency: 'EUR', language: 'es', }, permissions: ['*'], }, { id: '2', name: 'Panadería La Artesana', logo: 'https://images.unsplash.com/photo-1509440159596-0249088772ff?w=100&h=100&fit=crop&crop=center', role: 'manager', status: 'active', address: 'Avenida de la Paz 45, Barcelona, 08001', description: 'Panadería artesanal especializada en panes tradicionales catalanes.', settings: { timezone: 'Europe/Madrid', currency: 'EUR', language: 'ca', }, permissions: ['inventory:*', 'production:*', 'sales:*', 'reports:read'], }, { id: '3', name: 'Pan y Masa', logo: 'https://images.unsplash.com/photo-1524704654690-b56c05c78a00?w=100&h=100&fit=crop&crop=center', role: 'baker', status: 'active', address: 'Plaza Central 8, Valencia, 46001', description: 'Panadería moderna con enfoque en productos orgánicos.', settings: { timezone: 'Europe/Madrid', currency: 'EUR', language: 'es', }, permissions: ['production:*', 'inventory:read', 'inventory:update'], }, { id: '4', name: 'Horno Dorado', role: 'staff', status: 'inactive', address: 'Calle del Sol 67, Sevilla, 41001', description: 'Panadería tradicional andaluza.', settings: { timezone: 'Europe/Madrid', currency: 'EUR', language: 'es', }, permissions: ['inventory:read', 'sales:read'], }, ]; function bakeryReducer(state: BakeryState, action: BakeryAction): BakeryState { switch (action.type) { case 'SET_LOADING': return { ...state, isLoading: action.payload }; case 'SET_ERROR': return { ...state, error: action.payload, isLoading: false }; case 'SET_BAKERIES': return { ...state, bakeries: action.payload, currentBakery: state.currentBakery || action.payload[0] || null, isLoading: false, error: null }; case 'SET_CURRENT_BAKERY': // Save to localStorage for persistence localStorage.setItem('selectedBakery', action.payload.id); return { ...state, currentBakery: action.payload }; case 'ADD_BAKERY': return { ...state, bakeries: [...state.bakeries, action.payload] }; case 'UPDATE_BAKERY': return { ...state, bakeries: state.bakeries.map(bakery => bakery.id === action.payload.id ? { ...bakery, ...action.payload.updates } : bakery ), currentBakery: state.currentBakery?.id === action.payload.id ? { ...state.currentBakery, ...action.payload.updates } : state.currentBakery }; case 'REMOVE_BAKERY': const remainingBakeries = state.bakeries.filter(b => b.id !== action.payload); return { ...state, bakeries: remainingBakeries, currentBakery: state.currentBakery?.id === action.payload ? remainingBakeries[0] || null : state.currentBakery }; default: return state; } } interface BakeryContextType extends BakeryState { selectBakery: (bakery: Bakery) => void; addBakery: (bakery: Omit) => Promise; updateBakery: (id: string, updates: Partial) => Promise; removeBakery: (id: string) => Promise; refreshBakeries: () => Promise; hasPermission: (permission: string) => boolean; canAccess: (resource: string, action: string) => boolean; } const BakeryContext = createContext(undefined); interface BakeryProviderProps { children: ReactNode; } export function BakeryProvider({ children }: BakeryProviderProps) { const [state, dispatch] = useReducer(bakeryReducer, initialState); // Load bakeries on mount useEffect(() => { loadBakeries(); }, []); // Load saved bakery selection useEffect(() => { if (state.bakeries.length > 0 && !state.currentBakery) { const savedBakeryId = localStorage.getItem('selectedBakery'); const savedBakery = savedBakeryId ? state.bakeries.find(b => b.id === savedBakeryId) : null; if (savedBakery) { dispatch({ type: 'SET_CURRENT_BAKERY', payload: savedBakery }); } else if (state.bakeries[0]) { dispatch({ type: 'SET_CURRENT_BAKERY', payload: state.bakeries[0] }); } } }, [state.bakeries, state.currentBakery]); const loadBakeries = async () => { try { dispatch({ type: 'SET_LOADING', payload: true }); // Simulate API call delay await new Promise(resolve => setTimeout(resolve, 1000)); // In a real app, this would be an API call dispatch({ type: 'SET_BAKERIES', payload: mockBakeries }); } catch (error) { dispatch({ type: 'SET_ERROR', payload: error instanceof Error ? error.message : 'Error loading bakeries' }); } }; const selectBakery = (bakery: Bakery) => { dispatch({ type: 'SET_CURRENT_BAKERY', payload: bakery }); }; const addBakery = async (bakeryData: Omit) => { try { dispatch({ type: 'SET_LOADING', payload: true }); // Simulate API call await new Promise(resolve => setTimeout(resolve, 1000)); const newBakery: Bakery = { ...bakeryData, id: Date.now().toString(), // In real app, this would come from the API }; dispatch({ type: 'ADD_BAKERY', payload: newBakery }); dispatch({ type: 'SET_LOADING', payload: false }); } catch (error) { dispatch({ type: 'SET_ERROR', payload: error instanceof Error ? error.message : 'Error adding bakery' }); } }; const updateBakery = async (id: string, updates: Partial) => { try { dispatch({ type: 'SET_LOADING', payload: true }); // Simulate API call await new Promise(resolve => setTimeout(resolve, 1000)); dispatch({ type: 'UPDATE_BAKERY', payload: { id, updates } }); dispatch({ type: 'SET_LOADING', payload: false }); } catch (error) { dispatch({ type: 'SET_ERROR', payload: error instanceof Error ? error.message : 'Error updating bakery' }); } }; const removeBakery = async (id: string) => { try { dispatch({ type: 'SET_LOADING', payload: true }); // Simulate API call await new Promise(resolve => setTimeout(resolve, 1000)); dispatch({ type: 'REMOVE_BAKERY', payload: id }); dispatch({ type: 'SET_LOADING', payload: false }); } catch (error) { dispatch({ type: 'SET_ERROR', payload: error instanceof Error ? error.message : 'Error removing bakery' }); } }; const refreshBakeries = async () => { await loadBakeries(); }; const hasPermission = (permission: string): boolean => { if (!state.currentBakery) return false; const permissions = state.currentBakery.permissions || []; // Admin/owner has all permissions if (permissions.includes('*')) return true; return permissions.includes(permission); }; const canAccess = (resource: string, action: string): boolean => { if (!state.currentBakery) return false; // Check specific permission if (hasPermission(`${resource}:${action}`)) return true; // Check wildcard permissions if (hasPermission(`${resource}:*`)) return true; // Role-based access fallback switch (state.currentBakery.role) { case 'owner': 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; } }; const value: BakeryContextType = { ...state, selectBakery, addBakery, updateBakery, removeBakery, refreshBakeries, hasPermission, canAccess, }; return ( {children} ); } export function useBakery(): BakeryContextType { const context = useContext(BakeryContext); if (context === undefined) { throw new Error('useBakery must be used within a BakeryProvider'); } return context; } // Convenience hooks export const useCurrentBakery = () => { const { currentBakery } = useBakery(); return currentBakery; }; export const useBakeries = () => { const { bakeries } = useBakery(); return bakeries; }; export const useBakeryPermissions = () => { const { hasPermission, canAccess } = useBakery(); return { hasPermission, canAccess }; };