import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { RootState } from '../store'; // Define the type for a box item export interface BoxItem { id: string; name: string; price: number; image: string; quantity: number; variantId?: string; color?: string; compositeKey?: string; } // Define the type for the box state interface BoxState { items: BoxItem[]; total: number; editingBoxGroupId?: string; isInitialized: boolean; } // Helper function to load state from localStorage const loadState = (): BoxState | undefined => { try { // Check if we're in a browser environment if (typeof window === 'undefined') { return undefined; } const serializedState = localStorage.getItem('boxState'); if (serializedState === null) { return undefined; } return JSON.parse(serializedState); } catch (err) { console.error('Error loading box state from localStorage', err); return undefined; } }; // Helper function to save state to localStorage const saveState = (state: BoxState) => { if (typeof window === 'undefined') { return; } try { const serializedState = JSON.stringify(state); localStorage.setItem('boxState', serializedState); } catch (err) { console.error('Error saving box state to localStorage', err); } }; // Initial state without loading from localStorage to avoid hydration mismatch const initialState: BoxState = { items: [], total: 0, editingBoxGroupId: undefined, isInitialized: false }; // Helper to generate a unique key for an item based on ID and color const generateItemKey = (item: { id: string; color?: string }): string => { return `${item.id}-${item.color || 'no-color'}`; }; export const boxSlice = createSlice({ name: 'box', initialState, reducers: { // Initialize state from localStorage (to be called in useEffect) initializeState: (state) => { // Skip if already initialized if (state.isInitialized) return; try { const savedState = loadState(); if (savedState) { state.items = savedState.items || []; state.total = savedState.total || 0; state.editingBoxGroupId = savedState.editingBoxGroupId; } } catch (error) { console.error('Error initializing state from localStorage', error); } state.isInitialized = true; }, // Add an item to the box addToBox: (state, action: PayloadAction) => { const newItem = { ...action.payload }; // Check if the variantId should be used as a color if (newItem.variantId && !newItem.color) { newItem.color = newItem.variantId; } // Generate composite key const compositeKey = generateItemKey(newItem); newItem.compositeKey = compositeKey; const existingItemIndex = state.items.findIndex( item => generateItemKey(item) === compositeKey ); if (existingItemIndex >= 0 && state.items[existingItemIndex]) { // If item with the same key exists, increment quantity const quantity = newItem.quantity || 1; state.items[existingItemIndex].quantity += quantity; } else { // Otherwise add the new item (or item with a different color) state.items.push({ ...newItem, quantity: newItem.quantity || 1, compositeKey }); } // Recalculate total state.total = state.items.reduce( (sum, item) => sum + item.price * item.quantity, 0 ); // Save to localStorage saveState(state); }, // Update item quantity updateQuantity: (state, action: PayloadAction<{ id: string; color?: string; quantity: number }>) => { const { id, color, quantity } = action.payload; const itemKey = generateItemKey({ id, color }); const item = state.items.find(item => generateItemKey(item) === itemKey); if (item) { item.quantity = quantity; // Recalculate total state.total = state.items.reduce( (sum, item) => sum + item.price * item.quantity, 0 ); } // Save to localStorage saveState(state); }, // Remove an item from the box removeFromBox: (state, action: PayloadAction<{ id: string; color?: string }>) => { const { id, color } = action.payload; const itemKeyToRemove = generateItemKey({ id, color }); state.items = state.items.filter(item => generateItemKey(item) !== itemKeyToRemove); // Recalculate total state.total = state.items.reduce( (sum, item) => sum + item.price * item.quantity, 0 ); // Save to localStorage saveState(state); }, // Clear the entire box clearBox: (state) => { state.items = []; state.total = 0; state.editingBoxGroupId = undefined; // Save to localStorage saveState(state); }, // Load a box for editing loadBoxForEditing: (state) => { try { if (typeof window === 'undefined') { return; } const boxStateString = localStorage.getItem('lastBoxState'); if (!boxStateString) { return; } const boxState = JSON.parse(boxStateString); // Spremi originalni boxGroupId ako postoji if (boxState && boxState.originalBoxGroupId) { state.editingBoxGroupId = boxState.originalBoxGroupId; } if (boxState && boxState.boxItems && boxState.productItems) { // Reset current state state.items = []; // Add box items boxState.boxItems.forEach((item: BoxItem) => { state.items.push(item); }); // Add product items boxState.productItems.forEach((item: BoxItem) => { state.items.push(item); }); // Recalculate total state.total = state.items.reduce( (sum, item) => sum + item.price * item.quantity, 0 ); // Save to localStorage saveState(state); } } catch (error) { console.error('Error loading box for editing', error); } }, }, }); // Export actions export const { initializeState, addToBox, updateQuantity, removeFromBox, clearBox, loadBoxForEditing } = boxSlice.actions; // Selectors export const selectBoxItems = (state: RootState) => state.box.items; export const selectBoxTotal = (state: RootState) => state.box.total; export const selectBoxItemsCount = (state: RootState) => state.box.items.reduce((total, item) => total + item.quantity, 0); export const selectEditingBoxGroupId = (state: RootState) => state.box.editingBoxGroupId; export default boxSlice.reducer;