import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { RootState } from "redux/store"; import { CartItem } from "utils/types/appTypes"; interface LocationData { lat: number; lng: number; address: string; } export interface RoomDetailsType { roomNo: string; floorNo: string; guestName: string; note: string; } export interface OfficeDetailsType { officeNo: string; floorNo: string; note: string; company: string; contactPerson: string; phone: string; } export interface GiftDetailsType { receiverName: string; receiverPhone: string; message: string; senderName: string; senderPhone: string; senderEmail: string; isSecret: boolean; } interface CartState { items: CartItem[]; tmp: any; specialRequest: string; location: LocationData | null; roomDetails: RoomDetailsType | null; officeDetails: OfficeDetailsType | null; giftDetails: GiftDetailsType | null; coupon: string; tip: string; tables: string[]; estimateTime: Date; estimateTimeDate: Date; estimateTimeTime: string; collectionMethod: string; phone: string; paymentMethod: string; orderType: string; useLoyaltyPoints: boolean; } // localStorage keys export const CART_STORAGE_KEYS = { ITEMS: 'fascano_cart_items', SPECIAL_REQUEST: 'fascano_special_request', COUPON: 'fascano_coupon', TIP: 'fascano_tip', TABLES: 'fascano_tables', LOCATION: 'fascano_location', ROOM_DETAILS: 'fascano_room_details', OFFICE_DETAILS: 'fascano_office_details', GIFT_DETAILS: 'fascano_gift_details', ESTIMATE_TIME: 'fascano_estimate_time', ESTIMATE_TIME_DATE: 'fascano_estimate_time_date', ESTIMATE_TIME_TIME: 'fascano_estimate_time_time', COLLECTION_METHOD: 'fascano_collection_method', PHONE: 'fascano_phone', PAYMENT_METHOD: 'fascano_payment_method', ORDER_TYPE: 'fascano_order_type', USE_LOYALTY_POINTS: 'fascano_use_loyalty_points', } as const; // Utility functions for localStorage const getFromLocalStorage = (key: string, defaultValue: T): T => { if (typeof window === 'undefined') return defaultValue; try { const item = localStorage.getItem(key); return item ? JSON.parse(item) : defaultValue; } catch (error) { console.warn(`Error reading ${key} from localStorage:`, error); return defaultValue; } }; const initialState: CartState = { items: getFromLocalStorage(CART_STORAGE_KEYS.ITEMS, []), tmp: null, specialRequest: getFromLocalStorage(CART_STORAGE_KEYS.SPECIAL_REQUEST, ""), location: getFromLocalStorage(CART_STORAGE_KEYS.LOCATION, null), roomDetails: getFromLocalStorage(CART_STORAGE_KEYS.ROOM_DETAILS, null), officeDetails: getFromLocalStorage(CART_STORAGE_KEYS.OFFICE_DETAILS, null), giftDetails: getFromLocalStorage(CART_STORAGE_KEYS.GIFT_DETAILS, null), coupon: getFromLocalStorage(CART_STORAGE_KEYS.COUPON, ""), tip: getFromLocalStorage(CART_STORAGE_KEYS.TIP, ""), tables: getFromLocalStorage(CART_STORAGE_KEYS.TABLES, []), estimateTime: new Date(getFromLocalStorage(CART_STORAGE_KEYS.ESTIMATE_TIME, new Date().toISOString())), estimateTimeDate: new Date(getFromLocalStorage(CART_STORAGE_KEYS.ESTIMATE_TIME_DATE, new Date().toISOString())), estimateTimeTime: getFromLocalStorage(CART_STORAGE_KEYS.ESTIMATE_TIME_TIME, ""), collectionMethod: getFromLocalStorage(CART_STORAGE_KEYS.COLLECTION_METHOD, ""), phone: getFromLocalStorage(CART_STORAGE_KEYS.PHONE, ""), paymentMethod: getFromLocalStorage(CART_STORAGE_KEYS.PAYMENT_METHOD, ""), orderType: getFromLocalStorage(CART_STORAGE_KEYS.ORDER_TYPE, ""), useLoyaltyPoints: getFromLocalStorage(CART_STORAGE_KEYS.USE_LOYALTY_POINTS, false), }; const orderSlice = createSlice({ name: "order", initialState, reducers: { reset() { return initialState; }, addItem(state, action: PayloadAction<{ item: Omit; quantity: number }>) { const { item, quantity } = action.payload; const existingItem = state.items.find((i) => i.id === item.id); if (existingItem) { state.items = state.items.map((i) => i.id === item.id ? { ...i, quantity: i.quantity + quantity } : i ); } else { state.items = [...state.items, { ...item, quantity }]; } // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.ITEMS, JSON.stringify(state.items)); } }, updateQuantity(state, action: PayloadAction<{ id: number | string; quantity: number }>) { const { id, quantity } = action.payload; state.items = state.items.map((item) => item.id === id ? { ...item, quantity } : item ); // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.ITEMS, JSON.stringify(state.items)); } }, removeItem(state, action: PayloadAction) { state.items = state.items.filter((item) => item.id !== action.payload); // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.ITEMS, JSON.stringify(state.items)); } }, clearCart(state) { state.items = []; state.specialRequest = ""; state.phone = ""; state.coupon = ""; state.tip = ""; state.tables = []; state.location = null; state.roomDetails = null; state.officeDetails = null; state.giftDetails = null; state.estimateTime = new Date(); state.estimateTimeDate = new Date(); state.estimateTimeTime = ""; state.collectionMethod = ""; state.paymentMethod = ""; // Clear all cart data from localStorage if (typeof window !== 'undefined') { Object.values(CART_STORAGE_KEYS).filter(key => key !== CART_STORAGE_KEYS.ORDER_TYPE).forEach(key => { localStorage.removeItem(key); }); } }, updateSpecialRequest(state, action: PayloadAction) { state.specialRequest = action.payload; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.SPECIAL_REQUEST, JSON.stringify(state.specialRequest)); } }, clearSpecialRequest(state) { state.specialRequest = ""; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.removeItem(CART_STORAGE_KEYS.SPECIAL_REQUEST); } }, updateCoupon(state, action: PayloadAction) { state.coupon = action.payload; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.COUPON, JSON.stringify(state.coupon)); } }, updateTip(state, action: PayloadAction) { state.tip = action.payload; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.TIP, JSON.stringify(state.tip)); } }, updateTables(state, action: PayloadAction) { state.tables = action.payload; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.TABLES, JSON.stringify(state.tables)); } }, removeTable(state) { state.tables = []; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.removeItem(CART_STORAGE_KEYS.TABLES); } }, setTmp(state, action: PayloadAction) { state.tmp = action.payload; }, updateLocation(state, action: PayloadAction) { state.location = action.payload; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.LOCATION, JSON.stringify(state.location)); } }, clearLocation(state) { state.location = null; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.removeItem(CART_STORAGE_KEYS.LOCATION); } }, updateRoomDetails(state, action: PayloadAction) { state.roomDetails = action.payload; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.ROOM_DETAILS, JSON.stringify(state.roomDetails)); } }, updateOfficeDetails(state, action: PayloadAction) { state.officeDetails = action.payload; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.OFFICE_DETAILS, JSON.stringify(state.officeDetails)); } }, updateGiftDetails(state, action: PayloadAction) { state.giftDetails = action.payload; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.GIFT_DETAILS, JSON.stringify(state.giftDetails)); } }, updateEstimateTime(state, action: PayloadAction<{ date: Date; time: string }>) { state.estimateTime = action.payload.date; state.estimateTimeDate = action.payload.date; state.estimateTimeTime = action.payload.time; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.ESTIMATE_TIME, JSON.stringify(state.estimateTime.toISOString())); localStorage.setItem(CART_STORAGE_KEYS.ESTIMATE_TIME_DATE, JSON.stringify(state.estimateTimeDate.toISOString())); localStorage.setItem(CART_STORAGE_KEYS.ESTIMATE_TIME_TIME, JSON.stringify(state.estimateTimeTime)); } }, updateCollectionMethod(state, action: PayloadAction) { state.collectionMethod = action.payload; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.COLLECTION_METHOD, JSON.stringify(state.collectionMethod)); } }, updatePhone(state, action: PayloadAction) { state.phone = action.payload; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.PHONE, JSON.stringify(state.phone)); } }, updatePaymentMethod(state, action: PayloadAction) { state.paymentMethod = action.payload; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.PAYMENT_METHOD, JSON.stringify(state.paymentMethod)); } }, updateOrderType(state, action: PayloadAction) { state.orderType = action.payload; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.ORDER_TYPE, JSON.stringify(state.orderType)); } }, updateUseLoyaltyPoints(state, action: PayloadAction) { state.useLoyaltyPoints = action.payload; // Sync to localStorage if (typeof window !== 'undefined') { localStorage.setItem(CART_STORAGE_KEYS.USE_LOYALTY_POINTS, JSON.stringify(state.useLoyaltyPoints)); } }, }, }); export const { addItem, updateQuantity, removeItem, clearCart, updateSpecialRequest, clearSpecialRequest, updateCoupon, updateTip, updateTables, removeTable, setTmp, updateLocation, clearLocation, updateRoomDetails, updateOfficeDetails, updateGiftDetails, updateEstimateTime, updateCollectionMethod, updatePhone, updatePaymentMethod, updateOrderType, updateUseLoyaltyPoints, reset, } = orderSlice.actions; // Selectors export const selectCart = (state: RootState) => state.order; export const selectCartItems = (state: RootState) => state.order.items; export const selectCartTotal = (state: RootState) => state.order.items.reduce((total, item) => total + item.price * item.quantity, 0); export const selectCartItemsQuantity = (id: number | string) => (state: RootState) => { const item = state.order.items.find((i) => i.id === id); return item ? item.quantity : 0; }; export default orderSlice.reducer;