362 lines
12 KiB
TypeScript
362 lines
12 KiB
TypeScript
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 = <T>(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<CartItem, "quantity">; 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<number | string>) {
|
|
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<string>) {
|
|
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<string>) {
|
|
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<string>) {
|
|
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<string[]>) {
|
|
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<unknown>) {
|
|
state.tmp = action.payload;
|
|
},
|
|
updateLocation(state, action: PayloadAction<LocationData | null>) {
|
|
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<RoomDetailsType | null>) {
|
|
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<OfficeDetailsType | null>) {
|
|
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<GiftDetailsType | null>) {
|
|
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<string>) {
|
|
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<string>) {
|
|
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<string>) {
|
|
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<string>) {
|
|
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<boolean>) {
|
|
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;
|