apply loyalty discount logic
This commit is contained in:
@@ -228,7 +228,10 @@
|
||||
"pleaseSelectEstimateTime": "يرجى اختيار وقت التقديم",
|
||||
"pleaseSelectTable": "يرجى اختيار رقم الطاولة",
|
||||
"pleaseSelectCollectionMethod": "يرجى اختيار طريقة الاستلام",
|
||||
"useLoyaltyPoints": "استخدام نقاط الولاء"
|
||||
"useLoyaltyPoints": "استخدام نقاط الولاء",
|
||||
"noLoyaltyItemsInCart": "لا توجد عناصر ولاء في سلة المشتريات",
|
||||
"pleaseAddLoyaltyItems": "يرجى إضافة عناصر ولاء إلى سلة المشتريات لاستخدام نقاط الولاء",
|
||||
"loyaltyDiscountApplied": "تم تطبيق خصم الولاء: {{itemName}} (خصم {{amount}})"
|
||||
},
|
||||
"checkout": {
|
||||
"title": "الدفع",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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() {
|
||||
</div>
|
||||
<div className={styles.summaryRow}>
|
||||
<ProText type="secondary">{t("cart.discount")}</ProText>
|
||||
<ArabicPrice price={0} />
|
||||
<ArabicPrice price={loyaltyDiscountAmount} />
|
||||
</div>
|
||||
<div className={styles.summaryRow}>
|
||||
<ProText type="secondary">{t("cart.riderTip")}</ProText>
|
||||
@@ -45,16 +62,36 @@ export default function OrderSummary() {
|
||||
<ArabicPrice price={total} strong />
|
||||
</div>
|
||||
</Space>
|
||||
<br />
|
||||
<br />
|
||||
<Checkbox
|
||||
checked={useLoyaltyPoints}
|
||||
onChange={(value) => {
|
||||
dispatch(updateUseLoyaltyPoints(value.target.checked));
|
||||
}}
|
||||
>
|
||||
{t("cart.useLoyaltyPoints")}
|
||||
</Checkbox>
|
||||
|
||||
{isHasLoyaltyGift && (
|
||||
<>
|
||||
<br />
|
||||
<br />
|
||||
<Checkbox
|
||||
checked={useLoyaltyPoints}
|
||||
onChange={(value) => {
|
||||
dispatch(updateUseLoyaltyPoints(value.target.checked));
|
||||
}}
|
||||
>
|
||||
{t("cart.useLoyaltyPoints")}
|
||||
</Checkbox>
|
||||
</>
|
||||
)}
|
||||
|
||||
{isHasLoyaltyGift && loyaltyValidation.errorMessage && (
|
||||
<div style={{ marginTop: 8, color: "red", fontSize: "12px" }}>
|
||||
{t(loyaltyValidation.errorMessage)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isHasLoyaltyGift && useLoyaltyPoints && highestLoyaltyItem && (
|
||||
<div style={{ marginTop: 8, color: "green", fontSize: "12px" }}>
|
||||
{t("cart.loyaltyDiscountApplied", {
|
||||
itemName: highestLoyaltyItem.name,
|
||||
amount: Math.round(loyaltyDiscountAmount).toFixed(2),
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -53,32 +53,34 @@ 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 = <T>(key: string, defaultValue: T): T => {
|
||||
if (typeof window === 'undefined') return defaultValue;
|
||||
if (typeof window === "undefined") return defaultValue;
|
||||
|
||||
try {
|
||||
const item = localStorage.getItem(key);
|
||||
@@ -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<CartItem, "quantity">; quantity: number }>) {
|
||||
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
|
||||
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<number | string>) {
|
||||
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,26 +240,32 @@ 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<string>) {
|
||||
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);
|
||||
}
|
||||
},
|
||||
@@ -196,15 +273,18 @@ const orderSlice = createSlice({
|
||||
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<string>) {
|
||||
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));
|
||||
}
|
||||
},
|
||||
@@ -212,15 +292,18 @@ const orderSlice = createSlice({
|
||||
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);
|
||||
}
|
||||
},
|
||||
@@ -231,15 +314,18 @@ const orderSlice = createSlice({
|
||||
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);
|
||||
}
|
||||
},
|
||||
@@ -247,76 +333,162 @@ const orderSlice = createSlice({
|
||||
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<OfficeDetailsType | null>) {
|
||||
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));
|
||||
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));
|
||||
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<string>) {
|
||||
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<string>) {
|
||||
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<string>) {
|
||||
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<string>) {
|
||||
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<boolean>) {
|
||||
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,6 +517,8 @@ export const {
|
||||
updatePaymentMethod,
|
||||
updateOrderType,
|
||||
updateUseLoyaltyPoints,
|
||||
validateLoyaltyPoints,
|
||||
clearLoyaltyValidationError,
|
||||
reset,
|
||||
} = orderSlice.actions;
|
||||
|
||||
@@ -352,10 +526,54 @@ export const {
|
||||
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;
|
||||
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;
|
||||
|
||||
@@ -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,
|
||||
}),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
}),
|
||||
|
||||
@@ -331,6 +331,8 @@ export interface CartItem {
|
||||
variant?: string;
|
||||
extras?: string[];
|
||||
extrasgroup?: string[];
|
||||
isHasLoyalty?: boolean;
|
||||
no_of_stamps_give?: number;
|
||||
}
|
||||
|
||||
export interface User {
|
||||
|
||||
Reference in New Issue
Block a user