apply coupon discount

This commit is contained in:
2025-11-09 21:58:56 +03:00
parent b327d16260
commit 4389d267d4
8 changed files with 160 additions and 103 deletions

View File

@@ -35,6 +35,12 @@ export interface GiftDetailsType {
isSecret: boolean;
}
interface DiscountData {
value: number;
isGift: boolean;
isDiscount: boolean;
}
interface CartState {
restaurant: Partial<RestaurantDetails>;
items: CartItem[];
@@ -57,6 +63,7 @@ interface CartState {
useLoyaltyPoints: boolean;
loyaltyValidationError: string | null;
scheduledDate: string;
discount: DiscountData;
}
// localStorage keys
@@ -81,6 +88,7 @@ export const CART_STORAGE_KEYS = {
LOYALTY_VALIDATION_ERROR: "fascano_loyalty_validation_error",
RESTAURANT: "fascano_restaurant",
SCHEDULED_DATE: "fascano_scheduled_date",
DISCOUNT: "fascano_discount",
} as const;
// Utility functions for localStorage
@@ -97,11 +105,15 @@ const getFromLocalStorage = <T>(key: string, defaultValue: T): T => {
};
// Generate a unique identifier for cart items based on product ID, variant, extras, and comment
const generateUniqueId = (item: Omit<CartItem, "quantity" | "uniqueId">): string => {
const variantStr = item.variant || '';
const extrasStr = item.extras ? item.extras.sort().join(',') : '';
const extrasGroupStr = item.extrasgroup ? item.extrasgroup.sort().join(',') : '';
const commentStr = item.comment || '';
const generateUniqueId = (
item: Omit<CartItem, "quantity" | "uniqueId">,
): string => {
const variantStr = item.variant || "";
const extrasStr = item.extras ? item.extras.sort().join(",") : "";
const extrasGroupStr = item.extrasgroup
? item.extrasgroup.sort().join(",")
: "";
const commentStr = item.comment || "";
return `${item.id}-${variantStr}-${extrasStr}-${extrasGroupStr}-${commentStr}`;
};
@@ -153,6 +165,11 @@ const initialState: CartState = {
),
restaurant: getFromLocalStorage(CART_STORAGE_KEYS.RESTAURANT, { taxes: [] }),
scheduledDate: getFromLocalStorage(CART_STORAGE_KEYS.SCHEDULED_DATE, ""),
discount: getFromLocalStorage(CART_STORAGE_KEYS.DISCOUNT, {
value: 0,
isGift: false,
isDiscount: false,
}),
};
const orderSlice = createSlice({
@@ -189,7 +206,9 @@ const orderSlice = createSlice({
if (existingItem) {
// Update quantity of existing item with same configuration
state.items = state.items.map((i) =>
i.uniqueId === uniqueId ? { ...i, quantity: i.quantity + quantity } : i,
i.uniqueId === uniqueId
? { ...i, quantity: i.quantity + quantity }
: i,
);
} else {
// Add new item with its unique identifier
@@ -220,7 +239,11 @@ const orderSlice = createSlice({
},
updateQuantity(
state,
action: PayloadAction<{ id: number | string; uniqueId: string; quantity: number }>,
action: PayloadAction<{
id: number | string;
uniqueId: string;
quantity: number;
}>,
) {
const { uniqueId, quantity } = action.payload;
state.items = state.items.map((item) =>
@@ -236,7 +259,9 @@ const orderSlice = createSlice({
}
},
removeItem(state, action: PayloadAction<string>) {
state.items = state.items.filter((item) => item.uniqueId !== action.payload);
state.items = state.items.filter(
(item) => item.uniqueId !== action.payload,
);
// Validate loyalty points if enabled
if (state.useLoyaltyPoints) {
@@ -538,6 +563,17 @@ const orderSlice = createSlice({
);
}
},
updateDiscount(state, action: PayloadAction<DiscountData>) {
state.discount = action.payload;
// Sync to localStorage
if (typeof window !== "undefined") {
localStorage.setItem(
CART_STORAGE_KEYS.DISCOUNT,
JSON.stringify(state.discount),
);
}
},
},
});
@@ -569,6 +605,7 @@ export const {
reset,
updateRestaurant,
updateScheduledDate,
updateDiscount,
} = orderSlice.actions;
// Tax calculation helper functions
@@ -586,11 +623,13 @@ const calculateTotalTax = (subtotal: number, taxes: Tax[]): number => {
// 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 =
(uniqueId: string) => (state: RootState) => {
const item = state.order.items.find((i) => i.uniqueId === uniqueId);
@@ -617,6 +656,13 @@ export const selectHighestPricedLoyaltyItem = (state: RootState) => {
);
};
export const selectDiscountTotal = (state: RootState) =>
(state.order.discount.value / 100) * selectCartTotal(state) +
(state.order.useLoyaltyPoints &&
state.order.restaurant?.is_loyalty_enabled === 1
? selectHighestPricedLoyaltyItem(state)?.price || 0
: 0);
export const selectLoyaltyValidation = (state: RootState) => {
const useLoyaltyPoints = state.order.useLoyaltyPoints;
const loyaltyItems = selectLoyaltyItems(state);
@@ -636,13 +682,13 @@ export const selectLoyaltyValidation = (state: RootState) => {
export const selectTaxes = (state: RootState) => state.order.restaurant.taxes;
export const selectTaxAmount = (state: RootState) => {
const subtotal = selectCartTotal(state);
const subtotal = selectCartTotal(state) - selectDiscountTotal(state);
const taxes = selectTaxes(state);
return calculateTotalTax(subtotal, taxes || []);
};
export const selectGrandTotal = (state: RootState) => {
const loyaltyDiscount = selectHighestPricedLoyaltyItem(state)?.price || 0;
const totalDiscount = selectDiscountTotal(state);
const taxAmount = selectTaxAmount(state);
const subtotal = selectCartTotal(state);
const deliveryFee =
@@ -650,11 +696,7 @@ export const selectGrandTotal = (state: RootState) => {
? Number(state.order.restaurant?.delivery_fees) || 0
: 0;
return (
subtotal +
taxAmount -
(state.order.useLoyaltyPoints && state.order.restaurant?.is_loyalty_enabled === 1 ? loyaltyDiscount : 0) +
deliveryFee
);};
return subtotal + taxAmount - totalDiscount + deliveryFee;
};
export default orderSlice.reducer;