From 37a7c28c563ab32cb5f1fcea67f43dfbf627d996 Mon Sep 17 00:00:00 2001 From: Mohammed Al-yaseen Date: Tue, 21 Oct 2025 23:42:10 +0300 Subject: [PATCH] apply loyalty discount logic --- src/assets/locals/ar.json | 5 +- src/assets/locals/en.json | 5 +- src/components/OrderSummary/OrderSummary.tsx | 63 ++- src/features/order/orderSlice.ts | 412 +++++++++++++----- .../youMayLike/YouMightAlsoLike.tsx | 2 + src/pages/checkout/hooks/useOrder.ts | 20 +- .../product/components/ProductFooter.tsx | 2 + src/utils/types/appTypes.ts | 2 + 8 files changed, 393 insertions(+), 118 deletions(-) diff --git a/src/assets/locals/ar.json b/src/assets/locals/ar.json index fedf940..4693aaf 100644 --- a/src/assets/locals/ar.json +++ b/src/assets/locals/ar.json @@ -228,7 +228,10 @@ "pleaseSelectEstimateTime": "يرجى اختيار وقت التقديم", "pleaseSelectTable": "يرجى اختيار رقم الطاولة", "pleaseSelectCollectionMethod": "يرجى اختيار طريقة الاستلام", - "useLoyaltyPoints": "استخدام نقاط الولاء" + "useLoyaltyPoints": "استخدام نقاط الولاء", + "noLoyaltyItemsInCart": "لا توجد عناصر ولاء في سلة المشتريات", + "pleaseAddLoyaltyItems": "يرجى إضافة عناصر ولاء إلى سلة المشتريات لاستخدام نقاط الولاء", + "loyaltyDiscountApplied": "تم تطبيق خصم الولاء: {{itemName}} (خصم {{amount}})" }, "checkout": { "title": "الدفع", diff --git a/src/assets/locals/en.json b/src/assets/locals/en.json index 5c6fbbe..41835e2 100644 --- a/src/assets/locals/en.json +++ b/src/assets/locals/en.json @@ -238,7 +238,10 @@ "pleaseSelectEstimateTime": "Please select estimate time", "pleaseSelectTable": "Please select table", "pleaseSelectCollectionMethod": "Please select collection method", - "useLoyaltyPoints": "Use Loyalty Points" + "useLoyaltyPoints": "Use Loyalty Points", + "noLoyaltyItemsInCart": "No loyalty items found in your cart", + "pleaseAddLoyaltyItems": "Please add loyalty items to your cart to use loyalty points", + "loyaltyDiscountApplied": "Loyalty discount applied: {{itemName}} ({{amount}} off)" }, "checkout": { "title": "Checkout", diff --git a/src/components/OrderSummary/OrderSummary.tsx b/src/components/OrderSummary/OrderSummary.tsx index ebb8039..15e3ff2 100644 --- a/src/components/OrderSummary/OrderSummary.tsx +++ b/src/components/OrderSummary/OrderSummary.tsx @@ -3,9 +3,13 @@ import ArabicPrice from "components/ArabicPrice"; import { selectCart, selectCartTotal, + selectCartTotalWithLoyaltyDiscount, + selectHighestPricedLoyaltyItem, + selectLoyaltyValidation, updateUseLoyaltyPoints, } from "features/order/orderSlice"; import { useTranslation } from "react-i18next"; +import { useGetRestaurantDetailsQuery } from "redux/api/others"; import { useAppDispatch, useAppSelector } from "redux/hooks"; import ProText from "../ProText"; import ProTitle from "../ProTitle"; @@ -16,8 +20,21 @@ export default function OrderSummary() { const { useLoyaltyPoints } = useAppSelector(selectCart); const dispatch = useAppDispatch(); const subtotal = useAppSelector(selectCartTotal); - const tax = subtotal * 0.1; // 10% tax - const total = subtotal + tax; + const subtotalWithLoyaltyDiscount = useAppSelector( + selectCartTotalWithLoyaltyDiscount, + ); + const loyaltyValidation = useAppSelector(selectLoyaltyValidation); + const highestLoyaltyItem = useAppSelector(selectHighestPricedLoyaltyItem); + + const tax = subtotalWithLoyaltyDiscount * 0.1; // 10% tax on discounted amount + const total = subtotalWithLoyaltyDiscount + tax; + const loyaltyDiscountAmount = subtotal - subtotalWithLoyaltyDiscount; + + const { data: restaurant } = useGetRestaurantDetailsQuery("595"); + const isHasLoyaltyGift = + (restaurant?.loyalty_stamps ?? 0) - + (restaurant?.customer_loyalty_points ?? 0) === + 0; return ( <> @@ -31,7 +48,7 @@ export default function OrderSummary() {
{t("cart.discount")} - +
{t("cart.riderTip")} @@ -45,16 +62,36 @@ export default function OrderSummary() {
-
-
- { - dispatch(updateUseLoyaltyPoints(value.target.checked)); - }} - > - {t("cart.useLoyaltyPoints")} - + + {isHasLoyaltyGift && ( + <> +
+
+ { + dispatch(updateUseLoyaltyPoints(value.target.checked)); + }} + > + {t("cart.useLoyaltyPoints")} + + + )} + + {isHasLoyaltyGift && loyaltyValidation.errorMessage && ( +
+ {t(loyaltyValidation.errorMessage)} +
+ )} + + {isHasLoyaltyGift && useLoyaltyPoints && highestLoyaltyItem && ( +
+ {t("cart.loyaltyDiscountApplied", { + itemName: highestLoyaltyItem.name, + amount: Math.round(loyaltyDiscountAmount).toFixed(2), + })} +
+ )} ); diff --git a/src/features/order/orderSlice.ts b/src/features/order/orderSlice.ts index 3bc2492..2d93772 100644 --- a/src/features/order/orderSlice.ts +++ b/src/features/order/orderSlice.ts @@ -53,33 +53,35 @@ interface CartState { paymentMethod: string; orderType: string; useLoyaltyPoints: boolean; + loyaltyValidationError: string | null; } // 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', + 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", + LOYALTY_VALIDATION_ERROR: "fascano_loyalty_validation_error", } as const; // Utility functions for localStorage const getFromLocalStorage = (key: string, defaultValue: T): T => { - if (typeof window === 'undefined') return defaultValue; - + if (typeof window === "undefined") return defaultValue; + try { const item = localStorage.getItem(key); return item ? JSON.parse(item) : defaultValue; @@ -100,14 +102,37 @@ const initialState: CartState = { 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, ""), + 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), + useLoyaltyPoints: getFromLocalStorage( + CART_STORAGE_KEYS.USE_LOYALTY_POINTS, + false, + ), + loyaltyValidationError: getFromLocalStorage( + CART_STORAGE_KEYS.LOYALTY_VALIDATION_ERROR, + null, + ), }; const orderSlice = createSlice({ @@ -117,40 +142,86 @@ const orderSlice = createSlice({ reset() { return initialState; }, - addItem(state, action: PayloadAction<{ item: Omit; quantity: number }>) { + 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 + i.id === item.id ? { ...i, quantity: i.quantity + quantity } : i, ); } else { state.items = [...state.items, { ...item, quantity }]; } - + + // Validate loyalty points if enabled + if (state.useLoyaltyPoints) { + const loyaltyItems = state.items.filter((item) => item.isHasLoyalty); + if (loyaltyItems.length === 0) { + state.loyaltyValidationError = "cart.noLoyaltyItemsInCart"; + } else { + state.loyaltyValidationError = null; + } + } + // Sync to localStorage - if (typeof window !== 'undefined') { - localStorage.setItem(CART_STORAGE_KEYS.ITEMS, JSON.stringify(state.items)); + if (typeof window !== "undefined") { + localStorage.setItem( + CART_STORAGE_KEYS.ITEMS, + JSON.stringify(state.items), + ); + localStorage.setItem( + CART_STORAGE_KEYS.LOYALTY_VALIDATION_ERROR, + JSON.stringify(state.loyaltyValidationError), + ); } }, - updateQuantity(state, action: PayloadAction<{ id: number | string; quantity: number }>) { + 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 + item.id === id ? { ...item, quantity } : item, ); - + // Sync to localStorage - if (typeof window !== 'undefined') { - localStorage.setItem(CART_STORAGE_KEYS.ITEMS, JSON.stringify(state.items)); + 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); - + + // Validate loyalty points if enabled + if (state.useLoyaltyPoints) { + const loyaltyItems = state.items.filter((item) => item.isHasLoyalty); + if (loyaltyItems.length === 0) { + state.loyaltyValidationError = "cart.noLoyaltyItemsInCart"; + } else { + state.loyaltyValidationError = null; + } + } + // Sync to localStorage - if (typeof window !== 'undefined') { - localStorage.setItem(CART_STORAGE_KEYS.ITEMS, JSON.stringify(state.items)); + if (typeof window !== "undefined") { + localStorage.setItem( + CART_STORAGE_KEYS.ITEMS, + JSON.stringify(state.items), + ); + localStorage.setItem( + CART_STORAGE_KEYS.LOYALTY_VALIDATION_ERROR, + JSON.stringify(state.loyaltyValidationError), + ); } }, clearCart(state) { @@ -169,58 +240,70 @@ const orderSlice = createSlice({ state.estimateTimeTime = ""; state.collectionMethod = ""; state.paymentMethod = ""; + state.loyaltyValidationError = null; // 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); - }); + 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)); + 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') { + 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)); + 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') { + 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)); + 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') { + if (typeof window !== "undefined") { localStorage.removeItem(CART_STORAGE_KEYS.TABLES); } }, @@ -229,94 +312,183 @@ const orderSlice = createSlice({ }, 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)); + 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') { + 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)); + if (typeof window !== "undefined") { + localStorage.setItem( + CART_STORAGE_KEYS.ROOM_DETAILS, + JSON.stringify(state.roomDetails), + ); } }, - updateOfficeDetails(state, action: PayloadAction) { + 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)); + 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)); + if (typeof window !== "undefined") { + localStorage.setItem( + CART_STORAGE_KEYS.GIFT_DETAILS, + JSON.stringify(state.giftDetails), + ); } }, - updateEstimateTime(state, action: PayloadAction<{ date: Date; time: string }>) { + 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)); + 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)); + 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)); + 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)); + 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)); + if (typeof window !== "undefined") { + localStorage.setItem( + CART_STORAGE_KEYS.ORDER_TYPE, + JSON.stringify(state.orderType), + ); } }, updateUseLoyaltyPoints(state, action: PayloadAction) { state.useLoyaltyPoints = action.payload; - + + // Validate loyalty points usage + if (action.payload) { + const loyaltyItems = state.items.filter((item) => item.isHasLoyalty); + if (loyaltyItems.length === 0) { + state.loyaltyValidationError = "cart.noLoyaltyItemsInCart"; + } else { + state.loyaltyValidationError = null; + } + } else { + state.loyaltyValidationError = null; + } + // Sync to localStorage - if (typeof window !== 'undefined') { - localStorage.setItem(CART_STORAGE_KEYS.USE_LOYALTY_POINTS, JSON.stringify(state.useLoyaltyPoints)); + if (typeof window !== "undefined") { + localStorage.setItem( + CART_STORAGE_KEYS.USE_LOYALTY_POINTS, + JSON.stringify(state.useLoyaltyPoints), + ); + localStorage.setItem( + CART_STORAGE_KEYS.LOYALTY_VALIDATION_ERROR, + JSON.stringify(state.loyaltyValidationError), + ); + } + }, + validateLoyaltyPoints(state) { + if (state.useLoyaltyPoints) { + const loyaltyItems = state.items.filter((item) => item.isHasLoyalty); + if (loyaltyItems.length === 0) { + state.loyaltyValidationError = "cart.noLoyaltyItemsInCart"; + } else { + state.loyaltyValidationError = null; + } + } else { + state.loyaltyValidationError = null; + } + + // Sync to localStorage + if (typeof window !== "undefined") { + localStorage.setItem( + CART_STORAGE_KEYS.LOYALTY_VALIDATION_ERROR, + JSON.stringify(state.loyaltyValidationError), + ); + } + }, + clearLoyaltyValidationError(state) { + state.loyaltyValidationError = null; + + // Sync to localStorage + if (typeof window !== "undefined") { + localStorage.setItem( + CART_STORAGE_KEYS.LOYALTY_VALIDATION_ERROR, + JSON.stringify(state.loyaltyValidationError), + ); } }, }, @@ -345,17 +517,63 @@ export const { updatePaymentMethod, updateOrderType, updateUseLoyaltyPoints, + validateLoyaltyPoints, + clearLoyaltyValidationError, 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 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; + }; + +// Loyalty selectors +export const selectLoyaltyItems = (state: RootState) => + state.order.items.filter((item) => item.isHasLoyalty); + +export const selectHighestPricedLoyaltyItem = (state: RootState) => { + const loyaltyItems = selectLoyaltyItems(state); + if (loyaltyItems.length === 0) return null; + + return loyaltyItems.reduce((highest, current) => + current.price > highest.price ? current : highest, + ); +}; + +export const selectCartTotalWithLoyaltyDiscount = (state: RootState) => { + const total = selectCartTotal(state); + const useLoyaltyPoints = state.order.useLoyaltyPoints; + const highestLoyaltyItem = selectHighestPricedLoyaltyItem(state); + + if (useLoyaltyPoints && highestLoyaltyItem) { + return total - highestLoyaltyItem.price; + } + + return total; +}; + +export const selectLoyaltyValidation = (state: RootState) => { + const useLoyaltyPoints = state.order.useLoyaltyPoints; + const loyaltyItems = selectLoyaltyItems(state); + + return { + canUseLoyaltyPoints: loyaltyItems.length > 0, + hasLoyaltyItems: loyaltyItems.length > 0, + loyaltyItemsCount: loyaltyItems.length, + errorMessage: + useLoyaltyPoints && loyaltyItems.length === 0 + ? "cart.noLoyaltyItemsInCart" + : null, + }; }; export default orderSlice.reducer; diff --git a/src/pages/cart/components/youMayLike/YouMightAlsoLike.tsx b/src/pages/cart/components/youMayLike/YouMightAlsoLike.tsx index 3ab7bb3..9a84863 100644 --- a/src/pages/cart/components/youMayLike/YouMightAlsoLike.tsx +++ b/src/pages/cart/components/youMayLike/YouMightAlsoLike.tsx @@ -109,6 +109,8 @@ export default function YouMightAlsoLike() { image: item.image, description: item.description, variant: "None", + isHasLoyalty: item.isHasLoyalty, + no_of_stamps_give: item.no_of_stamps_give, }, quantity: 1, }), diff --git a/src/pages/checkout/hooks/useOrder.ts b/src/pages/checkout/hooks/useOrder.ts index 14260d7..e152323 100644 --- a/src/pages/checkout/hooks/useOrder.ts +++ b/src/pages/checkout/hooks/useOrder.ts @@ -1,5 +1,10 @@ import { message } from "antd"; -import { clearCart, selectCart } from "features/order/orderSlice"; +import { + clearCart, + selectCart, + selectCartTotalWithLoyaltyDiscount, + selectHighestPricedLoyaltyItem, +} from "features/order/orderSlice"; import { useCallback } from "react"; import { useTranslation } from "react-i18next"; import { useNavigate, useParams } from "react-router-dom"; @@ -29,6 +34,10 @@ export default function useOrder() { orderType, giftDetails, } = useAppSelector(selectCart); + const highestLoyaltyItem = useAppSelector(selectHighestPricedLoyaltyItem); + const { useLoyaltyPoints } = useAppSelector(selectCart); + + const orderPrice = useAppSelector(selectCartTotalWithLoyaltyDiscount); const [createOrder] = useCreateOrderMutation(); @@ -59,10 +68,8 @@ export default function useOrder() { pickup_comments: "", pickup_time: estimateTime, delivery_pickup_interval: "", - orderPrice: items.reduce( - (acc, item) => acc + item.price * item.quantity, - 0, - ), + orderPrice: orderPrice, + use_loylaty: useLoyaltyPoints && highestLoyaltyItem ? 1 : 0, useWallet: 0, tip, ...(orderType === "gift" @@ -74,7 +81,7 @@ export default function useOrder() { senderEmail: giftDetails?.senderEmail, senderPhone: giftDetails?.senderPhone, senderName: giftDetails?.senderName, - dineType: orderType + dineType: orderType, } : {}), }) @@ -120,6 +127,7 @@ export default function useOrder() { user_uuid, estimateTime, tip, + orderPrice, t, navigate, dispatch, diff --git a/src/pages/product/components/ProductFooter.tsx b/src/pages/product/components/ProductFooter.tsx index e0f28a3..0c69fa7 100644 --- a/src/pages/product/components/ProductFooter.tsx +++ b/src/pages/product/components/ProductFooter.tsx @@ -69,6 +69,8 @@ export default function ProductFooter({ variant: variantId, extras: selectedExtras, extrasgroup: selectedGroups, + isHasLoyalty: product?.isHasLoyalty, + no_of_stamps_give: product?.no_of_stamps_give, }, quantity: quantity, }), diff --git a/src/utils/types/appTypes.ts b/src/utils/types/appTypes.ts index f2ff901..7fac6e8 100644 --- a/src/utils/types/appTypes.ts +++ b/src/utils/types/appTypes.ts @@ -331,6 +331,8 @@ export interface CartItem { variant?: string; extras?: string[]; extrasgroup?: string[]; + isHasLoyalty?: boolean; + no_of_stamps_give?: number; } export interface User {