Compare commits
9 Commits
167b26e0b9
...
5c7e64b17c
| Author | SHA1 | Date | |
|---|---|---|---|
| 5c7e64b17c | |||
| 2c7a8d369a | |||
| eb6ca34162 | |||
| 1d9ae7190e | |||
| a06147dfa4 | |||
| 69bc9d4dee | |||
| 2b0516ad0d | |||
| eed10e8faf | |||
| f988fd3a4e |
@@ -76,7 +76,8 @@
|
||||
"room": "الغرفة",
|
||||
"office": "المكتب",
|
||||
"booking": "الحجز",
|
||||
"scheduledOrder": "الطلب المجدول"
|
||||
"scheduledOrder": "الطلب المجدول",
|
||||
"rewardsAndLoyalty": "المكافأة واللايفور"
|
||||
},
|
||||
"home": {
|
||||
"title": "العنوان",
|
||||
@@ -91,7 +92,7 @@
|
||||
"scheduledOrder": "طلب مجدول"
|
||||
},
|
||||
"promotion": {
|
||||
"title": "الترويجات",
|
||||
"title": "عرض التفاصيل",
|
||||
"description": "احصل على خصم 10% على طلبك الأول"
|
||||
}
|
||||
},
|
||||
@@ -129,7 +130,7 @@
|
||||
"payDescription": "الدفع",
|
||||
"rating": "التقييم ",
|
||||
"loyaltyPoints": "نقاط الولاء",
|
||||
"loyaltyDescription": "اشترى {{value}} وجبات واحصل على وجبة مجانية",
|
||||
"loyaltyDescription": "اشترى {{value}} وجبات واحصل على وجبة مجانية!",
|
||||
"youMightAlsoLike": "قد تعجبك أيضاً..",
|
||||
"choose1": "اختر 1",
|
||||
"specialRequest": "طلب خاص",
|
||||
@@ -164,7 +165,10 @@
|
||||
"restaurantIsClosed": "المطعم مغلق",
|
||||
"address": "العنوان",
|
||||
"openingTimes": "ساعات العمل",
|
||||
"customizable": "قابل للتخصيص"
|
||||
"customizable": "قابل للتخصيص",
|
||||
"youHaveXEarnedRewardsReadyToRedeem": "🎉 لديك {{rewards}} مكافأة مستحقة للاستخدام!",
|
||||
"justXMorePurchasesToUnlockYourFREEItem": "فقط {{cups}} أكثر للفتح الوجبة المجانية!",
|
||||
"youreJustXCupsAwayFromYourNextReward": "🎉 أنت فقط {{cups}} أكثر للحصول على المكافأة التالية!"
|
||||
},
|
||||
"cart": {
|
||||
"addSpecialRequestOptional": "إضافة طلب خاص (اختياري)",
|
||||
@@ -566,5 +570,30 @@
|
||||
"viewAll": "عرض الكل",
|
||||
"voucherCodeCopied": "تم نسخ رمز القسيمة",
|
||||
"copyFailed": "فشل نسخ رمز القسيمة"
|
||||
},
|
||||
"rewardsAndLoyalty": {
|
||||
"title": "المكافأة واللايفور",
|
||||
"description": "المكافأة واللايفور",
|
||||
"rewardsAndLoyalty": "المكافأة واللايفور",
|
||||
"rewardsAndLoyaltyDescription": "المكافأة واللايفور",
|
||||
"rewardsAndLoyaltyButton": "المكافأة واللايفور",
|
||||
"rewardsAndLoyaltyButtonDescription": "المكافأة واللايفور",
|
||||
"completedPurchases": "المشتريات المكتملة",
|
||||
"totalPurchased": "المشتريات الكلية",
|
||||
"saved": "المحفوظ",
|
||||
"almosthere": "قريب جدا!",
|
||||
"youreJustXCupsAwayFromYourNextReward": "أنت فقط {{cups}} أكواب بعيد عن المكافأة التالية!",
|
||||
"youCanRedeemDuringTheCheckout": "يمكنك استخدام المكافأة أثناء الدفع",
|
||||
"youCurrentlyHave": "لديك",
|
||||
"freeItems": "عناصر مجانية",
|
||||
"redeemNow": "استخدم الآن",
|
||||
"yourAvailableRewards": "المكافأات المتاحة",
|
||||
"loyaltyHistory": "سجل الولاء",
|
||||
"loyaltyHistoryDescription": "سجل الولاء",
|
||||
"earnedPoints": "حصل على {{points}} نقطة",
|
||||
"order": "الطلب",
|
||||
"yourOrderFrom": "طلبك من {{restaurantName}}",
|
||||
"earned": "حصل على",
|
||||
"xPoints": "{{points}} نقطة"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,8 @@
|
||||
"noMenuItemsAvailable": "No menu items available",
|
||||
"restaurantCover": "Restaurant Cover",
|
||||
"restaurantLogo": "Restaurant Logo",
|
||||
"scheduledOrder": "Scheduled Order"
|
||||
"scheduledOrder": "Scheduled Order",
|
||||
"rewardsAndLoyalty": "Rewards And Loyalty"
|
||||
},
|
||||
"home": {
|
||||
"title": "title",
|
||||
@@ -107,7 +108,7 @@
|
||||
"scheduledOrder": "Scheduled Order"
|
||||
},
|
||||
"promotion": {
|
||||
"title": "Promotions",
|
||||
"title": "Show details",
|
||||
"description": "Get 10% off your first order"
|
||||
}
|
||||
},
|
||||
@@ -143,7 +144,7 @@
|
||||
"close": "Close",
|
||||
"rating": "Rating ",
|
||||
"loyaltyPoints": "Loyalty Points",
|
||||
"loyaltyDescription": "Buy {{value}} meals and get 1 FREE",
|
||||
"loyaltyDescription": "Buy {{value}} meals and get 1 FREE!",
|
||||
"choose1": "Choose 1",
|
||||
"youMightAlsoLike": "You might also like..",
|
||||
"specialRequest": "Special Request",
|
||||
@@ -176,7 +177,10 @@
|
||||
"payDescription": "Pay for your order",
|
||||
"address": "Address",
|
||||
"openingTimes": "Opening Times",
|
||||
"customizable": "Customizable"
|
||||
"customizable": "Customizable",
|
||||
"youHaveXEarnedRewardsReadyToRedeem": "🎉 You have {{rewards}} rewards ready to redeem!",
|
||||
"justXMorePurchasesToUnlockYourFREEItem": "Just {{cups}} more purchases to unlock your FREE item!",
|
||||
"youreJustXCupsAwayFromYourNextReward": "🎉 You're just {{cups}} stamps away from your next reward!"
|
||||
},
|
||||
"cart": {
|
||||
"remainingToPay": "Remaining to Pay",
|
||||
@@ -281,7 +285,9 @@
|
||||
"am": "AM",
|
||||
"pm": "PM",
|
||||
"cannotSelectPastDate": "You cannot select a past date. Please select today or a future date.",
|
||||
"checkRequiredFields": "Please check required fields"
|
||||
"checkRequiredFields": "Please check required fields",
|
||||
"applyYourAvailableRewardsToGetDiscountsOnItemsInYourCart": "Apply your available rewards to get discounts on items in your cart",
|
||||
"loyalty": "Loyalty"
|
||||
},
|
||||
"checkout": {
|
||||
"addCarDetails": "Add Car Details",
|
||||
@@ -586,5 +592,30 @@
|
||||
"copyFailed": "Failed to copy voucher code",
|
||||
"hiX": "Hi {{name}}!",
|
||||
"youHaveReceivedAGiftCarFromX": "You have received a gift car from {{name}}!"
|
||||
},
|
||||
"rewardsAndLoyalty": {
|
||||
"title": "Rewards And Loyalty",
|
||||
"description": "Rewards And Loyalty",
|
||||
"rewardsAndLoyalty": "Rewards And Loyalty",
|
||||
"rewardsAndLoyaltyDescription": "Rewards And Loyalty",
|
||||
"rewardsAndLoyaltyButton": "Rewards And Loyalty",
|
||||
"rewardsAndLoyaltyButtonDescription": "Rewards And Loyalty",
|
||||
"completedPurchases": "Completed Purchases",
|
||||
"totalPurchased": "Total Purchased",
|
||||
"saved": "Saved",
|
||||
"almosthere": "Almost here!",
|
||||
"youreJustXCupsAwayFromYourNextReward": "You're just {{cups}} cups away from your next reward!",
|
||||
"youCanRedeemDuringTheCheckout": "You can redeem during the checkout",
|
||||
"youCurrentlyHave": "You currently have",
|
||||
"freeItems": "free items",
|
||||
"redeemNow": "Redeem Now",
|
||||
"yourAvailableRewards": "Your available rewards",
|
||||
"loyaltyHistory": "Loyalty History",
|
||||
"loyaltyHistoryDescription": "Loyalty History",
|
||||
"earnedPoints": "Earned {{points}} points",
|
||||
"order": "Order",
|
||||
"yourOrderFrom": "Your order from {{restaurantName}}",
|
||||
"earned": "Earned",
|
||||
"xPoints": "{{points}} points"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import GiftItemsBtnIcon from "components/Icons/GiftItemsBtnIcon";
|
||||
import GiftBalanceBtnIcon from "components/Icons/GiftBalanceBtnIcon";
|
||||
import GiftItemsAndBalanceBtnIcon from "components/Icons/GiftItemsAndBalanceBtnIcon";
|
||||
import ProText from "components/ProText";
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
|
||||
interface GiftTypeBottomSheetProps {
|
||||
isOpen: boolean;
|
||||
@@ -13,6 +14,12 @@ interface GiftTypeBottomSheetProps {
|
||||
onSave?: () => void;
|
||||
}
|
||||
|
||||
export enum GiftType {
|
||||
Items = "items",
|
||||
Vouchers = "vouchers",
|
||||
ItemsAndVouchers = "itemsAndVouchers",
|
||||
}
|
||||
|
||||
export function GiftTypeBottomSheet({
|
||||
isOpen,
|
||||
onClose,
|
||||
@@ -20,11 +27,15 @@ export function GiftTypeBottomSheet({
|
||||
}: GiftTypeBottomSheetProps) {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleSave = (giftType: string) => {
|
||||
dispatch(updateGiftDetails({ giftType: giftType }));
|
||||
const { subdomain } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const handleSave = (giftType: GiftType) => {
|
||||
dispatch(updateGiftDetails({ giftType }));
|
||||
onClose();
|
||||
onSave?.();
|
||||
if (giftType !== GiftType.Vouchers)
|
||||
navigate(`/${subdomain}/menu?orderType=gift`);
|
||||
else navigate(`/${subdomain}/e-gift-cards`);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@@ -40,6 +51,7 @@ export function GiftTypeBottomSheet({
|
||||
textAlign: "center",
|
||||
color: "#86858E",
|
||||
};
|
||||
|
||||
return (
|
||||
<ProBottomSheet
|
||||
isOpen={isOpen}
|
||||
@@ -59,19 +71,22 @@ export function GiftTypeBottomSheet({
|
||||
padding: 24,
|
||||
}}
|
||||
>
|
||||
<div style={{ width: 60 }} onClick={() => handleSave("items")}>
|
||||
<div style={{ width: 60 }} onClick={() => handleSave(GiftType.Items)}>
|
||||
<GiftItemsBtnIcon />
|
||||
<br />
|
||||
<ProText style={textStyle}>{t("gift.items")}</ProText>
|
||||
</div>
|
||||
<div style={{ width: 60 }} onClick={() => handleSave("vouchers")}>
|
||||
<div
|
||||
style={{ width: 60 }}
|
||||
onClick={() => handleSave(GiftType.Vouchers)}
|
||||
>
|
||||
<GiftBalanceBtnIcon />
|
||||
<br />
|
||||
<ProText style={textStyle}>{t("gift.balance")}</ProText>
|
||||
</div>
|
||||
<div
|
||||
style={{ width: 60 }}
|
||||
onClick={() => handleSave("itemsAndVouchers")}
|
||||
onClick={() => handleSave(GiftType.ItemsAndVouchers)}
|
||||
>
|
||||
<GiftItemsAndBalanceBtnIcon />
|
||||
<br />
|
||||
|
||||
63
src/components/Icons/BranchesIcon.tsx
Normal file
63
src/components/Icons/BranchesIcon.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
interface BranchesIconType {
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const BranchesIcon = ({ className, onClick }: BranchesIconType) => {
|
||||
return (
|
||||
<svg
|
||||
width="15"
|
||||
height="16"
|
||||
viewBox="0 0 15 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
onClick={onClick}
|
||||
>
|
||||
<path
|
||||
d="M5.40234 3.18555C5.54014 2.593 6.04569 1.00063 7.49875 1.00063C8.95667 1.00063 9.4607 2.60361 9.59656 3.19141"
|
||||
stroke="#333333"
|
||||
strokeMiterlimit="10"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M12.7224 15H2.27935C1.70007 15 1.23047 14.5305 1.23047 13.9512V4.23958C1.23047 3.66035 1.70007 3.19075 2.27935 3.19075H12.7224C13.3017 3.19075 13.7713 3.66035 13.7713 4.23958V13.9512C13.7713 14.5305 13.3017 15 12.7224 15Z"
|
||||
stroke="#333333"
|
||||
strokeMiterlimit="10"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M10.4466 8.39983C10.7649 8.92011 10.9482 9.53128 10.9482 10.1851V10.6016H4.05078V10.1851C4.05078 8.2877 5.59476 6.74955 7.4995 6.74955C8.09085 6.74955 8.64745 6.8978 9.13388 7.15906"
|
||||
stroke="#333333"
|
||||
strokeMiterlimit="10"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M2.90234 10.6016H12.0989"
|
||||
stroke="#333333"
|
||||
strokeMiterlimit="10"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M7.5 6.75V5.94196"
|
||||
stroke="#333333"
|
||||
strokeMiterlimit="10"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M10.6209 12.0625H4.37929C4.18146 12.0625 4.0038 11.9419 3.93143 11.7585L3.47656 10.605H11.5236L11.0687 11.7585C10.9964 11.9419 10.8187 12.0625 10.6209 12.0625Z"
|
||||
stroke="#333333"
|
||||
strokeMiterlimit="10"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default BranchesIcon;
|
||||
47
src/components/Icons/CoinsIcon.tsx
Normal file
47
src/components/Icons/CoinsIcon.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
interface CoinsIconType {
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const CoinsIcon = ({ className, onClick }: CoinsIconType) => {
|
||||
return (
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
onClick={onClick}
|
||||
>
|
||||
<path
|
||||
d="M15.8555 9.85547V12.4269C15.8555 13.5412 13.1692 14.9983 9.85547 14.9983C6.54175 14.9983 3.85547 13.5412 3.85547 12.4269V10.284"
|
||||
stroke="#FFC600"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M4.10938 10.5083C4.8508 11.4923 7.14366 12.4154 9.85737 12.4154C13.1711 12.4154 15.8574 11.0388 15.8574 9.85598C15.8574 9.1917 15.0114 8.46398 13.6837 7.95312"
|
||||
stroke="#FFC600"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M13.2852 5.57031V8.14174C13.2852 9.25603 10.5989 10.7132 7.28516 10.7132C3.97144 10.7132 1.28516 9.25603 1.28516 8.14174V5.57031"
|
||||
stroke="#FFC600"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M7.28516 8.12914C10.5989 8.12914 13.2852 6.75257 13.2852 5.56971C13.2852 4.38686 10.5989 3 7.28516 3C3.97144 3 1.28516 4.386 1.28516 5.56971C1.28516 6.75257 3.97144 8.12914 7.28516 8.12914Z"
|
||||
stroke="#FFC600"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default CoinsIcon;
|
||||
25
src/components/Icons/CupIcon.tsx
Normal file
25
src/components/Icons/CupIcon.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
interface CupIconType {
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const CupIcon = ({ className, onClick }: CupIconType) => {
|
||||
return (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
onClick={onClick}
|
||||
>
|
||||
<path
|
||||
d="M4.16797 2.5H16.668C17.11 2.5 17.5339 2.67559 17.8465 2.98816C18.159 3.30072 18.3346 3.72464 18.3346 4.16667V6.66667C18.3346 7.10869 18.159 7.53262 17.8465 7.84518C17.5339 8.15774 17.11 8.33333 16.668 8.33333H15.0013V10.8333C15.0013 11.7174 14.6501 12.5652 14.025 13.1904C13.3999 13.8155 12.552 14.1667 11.668 14.1667H6.66797C5.78391 14.1667 4.93607 13.8155 4.31095 13.1904C3.68582 12.5652 3.33464 11.7174 3.33464 10.8333V3.33333C3.33464 3.11232 3.42243 2.90036 3.57871 2.74408C3.73499 2.5878 3.94695 2.5 4.16797 2.5ZM15.0013 4.16667V6.66667H16.668V4.16667H15.0013ZM1.66797 15.8333H16.668V17.5H1.66797V15.8333Z"
|
||||
fill="#FFB700"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default CupIcon;
|
||||
27
src/components/Icons/LoginIcon.tsx
Normal file
27
src/components/Icons/LoginIcon.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
interface LoginIconType {
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const LoginIcon = ({ className, onClick }: LoginIconType) => {
|
||||
return (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
onClick={onClick}
|
||||
>
|
||||
<path
|
||||
d="M10 2H10.8C11.9201 2 12.4802 2 12.908 2.21799C13.2843 2.40973 13.5903 2.71569 13.782 3.09202C14 3.51984 14 4.0799 14 5.2V10.8C14 11.9201 14 12.4802 13.782 12.908C13.5903 13.2843 13.2843 13.5903 12.908 13.782C12.4802 14 11.9201 14 10.8 14H10M6.66667 4.66667L10 8M10 8L6.66667 11.3333M10 8L2 8"
|
||||
stroke="#333333"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginIcon;
|
||||
37
src/components/Icons/LoyaltyAndRewardIcon.tsx
Normal file
37
src/components/Icons/LoyaltyAndRewardIcon.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
interface LoyaltyAndRewardIconType {
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
color?: string
|
||||
}
|
||||
|
||||
const LoyaltyAndRewardIcon = ({ className, onClick, color }: LoyaltyAndRewardIconType) => {
|
||||
return (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
onClick={onClick}
|
||||
>
|
||||
<path
|
||||
d="M1.33203 7.9987C1.33203 5.32736 1.33203 3.99203 2.11336 3.16203C2.8947 2.33203 4.15136 2.33203 6.66536 2.33203H9.33203C11.846 2.33203 13.1034 2.33203 13.884 3.16203C14.6647 3.99203 14.6654 5.32736 14.6654 7.9987C14.6654 10.67 14.6654 12.0054 13.884 12.8354C13.1027 13.6654 11.846 13.6654 9.33203 13.6654H6.66536C4.15136 13.6654 2.89403 13.6654 2.11336 12.8354C1.3327 12.0054 1.33203 10.67 1.33203 7.9987Z"
|
||||
stroke={color || "#333333"}
|
||||
/>
|
||||
<path
|
||||
d="M4.59189 7.22074C5.21789 6.85541 5.76389 7.00274 6.09189 7.23741C6.22655 7.33341 6.29389 7.38141 6.33322 7.38141C6.37322 7.38141 6.43989 7.33341 6.57455 7.23741C6.90255 7.00274 7.44855 6.85541 8.07455 7.22074C8.89589 7.70074 9.08122 9.28341 7.18789 10.6187C6.82655 10.8727 6.64589 11.0001 6.33322 11.0001C6.02055 11.0001 5.83989 10.8734 5.47922 10.6187C3.58522 9.28341 3.76989 7.70074 4.59189 7.22074Z"
|
||||
stroke={color || "#333333"}
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M12 11H10"
|
||||
stroke={color || "#333333"}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoyaltyAndRewardIcon;
|
||||
27
src/components/Icons/MyOrderIcon.tsx
Normal file
27
src/components/Icons/MyOrderIcon.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
interface MyOrderIconType {
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const MyOrderIcon = ({ className, onClick }: MyOrderIconType) => {
|
||||
return (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
onClick={onClick}
|
||||
>
|
||||
<path
|
||||
d="M10.6656 5.9987V3.9987C10.6656 2.52594 9.4717 1.33203 7.99894 1.33203C6.52618 1.33203 5.33228 2.52594 5.33228 3.9987V5.9987M2.39361 6.90001L1.99361 11.1667C1.87988 12.3798 1.82302 12.9864 2.02431 13.4549C2.20114 13.8665 2.51102 14.2067 2.90429 14.4212C3.35196 14.6654 3.96119 14.6654 5.17964 14.6654H10.8182C12.0367 14.6654 12.6459 14.6654 13.0936 14.4212C13.4869 14.2067 13.7967 13.8665 13.9736 13.4549C14.1749 12.9864 14.118 12.3798 14.0043 11.1667L13.6043 6.90001C13.5082 5.8756 13.4602 5.36339 13.2298 4.97614C13.0269 4.63509 12.7272 4.36211 12.3687 4.19193C11.9616 3.9987 11.4472 3.9987 10.4182 3.9987L5.57964 3.9987C4.55074 3.9987 4.03628 3.9987 3.62922 4.19193C3.27072 4.3621 2.97095 4.63509 2.76805 4.97614C2.53767 5.36339 2.48965 5.87559 2.39361 6.90001Z"
|
||||
stroke="#333333"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default MyOrderIcon;
|
||||
51
src/components/Icons/PopularIcon.tsx
Normal file
51
src/components/Icons/PopularIcon.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
interface PopularIconType {
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const PopularIcon = ({ className, onClick }: PopularIconType) => {
|
||||
return (
|
||||
<svg
|
||||
fill="#FFC600"
|
||||
height="30"
|
||||
width="30"
|
||||
version="1.1"
|
||||
id="Icons"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 32 32"
|
||||
xmlSpace="preserve"
|
||||
className={className}
|
||||
onClick={onClick}
|
||||
>
|
||||
<g>
|
||||
<path
|
||||
d="M12,17c0.8-4.2,1.9-5.3,6.1-6.1c0.5-0.1,0.8-0.5,0.8-1s-0.3-0.9-0.8-1C13.9,8.1,12.8,7,12,2.8C11.9,2.3,11.5,2,11,2
|
||||
c-0.5,0-0.9,0.3-1,0.8C9.2,7,8.1,8.1,3.9,8.9C3.5,9,3.1,9.4,3.1,9.9s0.3,0.9,0.8,1c4.2,0.8,5.3,1.9,6.1,6.1c0.1,0.5,0.5,0.8,1,0.8
|
||||
S11.9,17.4,12,17z"
|
||||
/>
|
||||
<path
|
||||
d="M22,24c-2.8-0.6-3.4-1.2-4-4c-0.1-0.5-0.5-0.8-1-0.8s-0.9,0.3-1,0.8c-0.6,2.8-1.2,3.4-4,4c-0.5,0.1-0.8,0.5-0.8,1
|
||||
s0.3,0.9,0.8,1c2.8,0.6,3.4,1.2,4,4c0.1,0.5,0.5,0.8,1,0.8s0.9-0.3,1-0.8c0.6-2.8,1.2-3.4,4-4c0.5-0.1,0.8-0.5,0.8-1
|
||||
S22.4,24.1,22,24z"
|
||||
/>
|
||||
<path
|
||||
d="M29.2,14c-2.2-0.4-2.7-0.9-3.1-3.1c-0.1-0.5-0.5-0.8-1-0.8c-0.5,0-0.9,0.3-1,0.8c-0.4,2.2-0.9,2.7-3.1,3.1
|
||||
c-0.5,0.1-0.8,0.5-0.8,1s0.3,0.9,0.8,1c2.2,0.4,2.7,0.9,3.1,3.1c0.1,0.5,0.5,0.8,1,0.8c0.5,0,0.9-0.3,1-0.8
|
||||
c0.4-2.2,0.9-2.7,3.1-3.1c0.5-0.1,0.8-0.5,0.8-1S29.7,14.1,29.2,14z"
|
||||
/>
|
||||
<path
|
||||
d="M5.7,22.3C5.4,22,5,21.9,4.6,22.1c-0.1,0-0.2,0.1-0.3,0.2c-0.1,0.1-0.2,0.2-0.2,0.3C4,22.7,4,22.9,4,23s0,0.3,0.1,0.4
|
||||
c0.1,0.1,0.1,0.2,0.2,0.3c0.1,0.1,0.2,0.2,0.3,0.2C4.7,24,4.9,24,5,24c0.1,0,0.3,0,0.4-0.1s0.2-0.1,0.3-0.2
|
||||
c0.1-0.1,0.2-0.2,0.2-0.3C6,23.3,6,23.1,6,23s0-0.3-0.1-0.4C5.9,22.5,5.8,22.4,5.7,22.3z"
|
||||
/>
|
||||
<path
|
||||
d="M28,7c0.3,0,0.5-0.1,0.7-0.3C28.9,6.5,29,6.3,29,6s-0.1-0.5-0.3-0.7c-0.1-0.1-0.2-0.2-0.3-0.2c-0.2-0.1-0.5-0.1-0.8,0
|
||||
c-0.1,0-0.2,0.1-0.3,0.2C27.1,5.5,27,5.7,27,6c0,0.3,0.1,0.5,0.3,0.7C27.5,6.9,27.7,7,28,7z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default PopularIcon;
|
||||
33
src/components/Icons/RaiseIcon.tsx
Normal file
33
src/components/Icons/RaiseIcon.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
interface RaiseIconType {
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const RaiseIcon = ({ className, onClick }: RaiseIconType) => {
|
||||
return (
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
onClick={onClick}
|
||||
>
|
||||
<path
|
||||
d="M2.25 12.75L6.75 8.25L9.75 11.25L15.75 5.25"
|
||||
stroke="#FFC600"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M12.75 5.25H15.75V8.25"
|
||||
stroke="#FFC600"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default RaiseIcon;
|
||||
@@ -1,4 +1,4 @@
|
||||
import { GlobalOutlined, ShakeOutlined } from "@ant-design/icons";
|
||||
import { GlobalOutlined } from "@ant-design/icons";
|
||||
import { setLocale, setLocalesThunk } from "features/locale/localeSlice";
|
||||
import i18n from "i18n/i18n";
|
||||
import { useTransition } from "react";
|
||||
|
||||
@@ -15,10 +15,10 @@ const LoyaltyCard = () => {
|
||||
const { data: restaurant } = useGetRestaurantDetailsQuery(subdomain);
|
||||
const { isRTL } = useAppSelector((state) => state.locale);
|
||||
const token = localStorage.getItem(ACCESS_TOKEN);
|
||||
const isHasLoyaltyGift =
|
||||
(restaurant?.loyalty_stamps || 0) -
|
||||
(restaurant?.customer_loyalty_points || 0) <=
|
||||
0;
|
||||
const loyaltyStamps = restaurant?.loyalty_stamps ?? 0;
|
||||
const customerLoyaltyPoints = restaurant?.customer_loyalty_points ?? 0;
|
||||
const remainingToNextReward =
|
||||
loyaltyStamps - (customerLoyaltyPoints % loyaltyStamps);
|
||||
|
||||
return (
|
||||
<div className={styles.loyaltyContainer}>
|
||||
@@ -62,8 +62,14 @@ const LoyaltyCard = () => {
|
||||
}}
|
||||
>
|
||||
{token &&
|
||||
customerLoyaltyPoints < loyaltyStamps &&
|
||||
t("menu.loyaltyDescription", {
|
||||
value: restaurant?.loyalty_stamps ?? 0,
|
||||
value: loyaltyStamps,
|
||||
})}
|
||||
{token &&
|
||||
customerLoyaltyPoints >= loyaltyStamps &&
|
||||
t("menu.youHaveXEarnedRewardsReadyToRedeem", {
|
||||
rewards: Math.floor(customerLoyaltyPoints / loyaltyStamps),
|
||||
})}
|
||||
{!token && (
|
||||
<div style={{ paddingTop: 4 }}>
|
||||
@@ -95,21 +101,22 @@ const LoyaltyCard = () => {
|
||||
)}
|
||||
</ProText>
|
||||
</Col>
|
||||
<Col> {isHasLoyaltyGift && <PresentIcon />}</Col>
|
||||
{/* <Col> {isHasLoyaltyGift && <PresentIcon />}</Col> */}
|
||||
</Row>
|
||||
{token && (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
gap: 12,
|
||||
overflow: "hidden",
|
||||
scrollbarWidth: "none",
|
||||
}}
|
||||
>
|
||||
{Array.from({ length: restaurant?.loyalty_stamps || 0 }).map(
|
||||
(_, index) => {
|
||||
const currentPoints = restaurant?.customer_loyalty_points || 0;
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
gap: 12,
|
||||
overflow: "auto",
|
||||
scrollbarWidth: "none",
|
||||
paddingBottom: 12,
|
||||
}}
|
||||
>
|
||||
{Array.from({ length: loyaltyStamps }).map((_, index) => {
|
||||
const currentPoints = customerLoyaltyPoints % loyaltyStamps;
|
||||
const isCollected = index < currentPoints;
|
||||
return (
|
||||
<Col key={index}>
|
||||
@@ -126,9 +133,30 @@ const LoyaltyCard = () => {
|
||||
/>
|
||||
</Col>
|
||||
);
|
||||
},
|
||||
)}
|
||||
</div>
|
||||
})}
|
||||
</div>
|
||||
<ProText
|
||||
strong
|
||||
style={{
|
||||
fontWeight: 400,
|
||||
fontStyle: "Regular",
|
||||
fontSize: "12px",
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color:
|
||||
customerLoyaltyPoints < loyaltyStamps ? "#777580" : "#32AD6D",
|
||||
}}
|
||||
>
|
||||
{customerLoyaltyPoints < loyaltyStamps &&
|
||||
t("menu.justXMorePurchasesToUnlockYourFREEItem", {
|
||||
cups: remainingToNextReward,
|
||||
})}
|
||||
{customerLoyaltyPoints >= loyaltyStamps &&
|
||||
t("menu.youreJustXCupsAwayFromYourNextReward", {
|
||||
cups: remainingToNextReward,
|
||||
})}
|
||||
</ProText>
|
||||
</>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
.summaryDivider {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Card, Checkbox, Divider, Space } from "antd";
|
||||
import { Card, Checkbox, Divider, Space, Tag } from "antd";
|
||||
import ArabicPrice from "components/ArabicPrice";
|
||||
import {
|
||||
selectCart,
|
||||
@@ -69,7 +69,7 @@ export default function OrderSummary() {
|
||||
<ProText type="secondary" style={titlesStyle}>
|
||||
{t("cart.basketTotal")}
|
||||
</ProText>
|
||||
<ArabicPrice price={subtotal} style={titlesStyle} />
|
||||
<ArabicPrice price={subtotal} textStyle={titlesStyle} />
|
||||
</div>
|
||||
{orderType === OrderType.Delivery && (
|
||||
<div className={styles.summaryRow}>
|
||||
@@ -78,7 +78,7 @@ export default function OrderSummary() {
|
||||
</ProText>
|
||||
<ArabicPrice
|
||||
price={Number(restaurant?.delivery_fees || 0)}
|
||||
style={{ ...titlesStyle, color: "#434E5C" }}
|
||||
textStyle={{ ...titlesStyle, color: "#434E5C" }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -87,10 +87,42 @@ export default function OrderSummary() {
|
||||
<ProText type="secondary" style={titlesStyle}>
|
||||
{t("cart.discount")}
|
||||
</ProText>
|
||||
<ArabicPrice
|
||||
price={discountAmount}
|
||||
style={{ ...titlesStyle, color: "#434E5C" }}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
minHeight: "24px",
|
||||
}}
|
||||
>
|
||||
{isHasLoyaltyGift &&
|
||||
useLoyaltyPoints &&
|
||||
highestLoyaltyItem &&
|
||||
restaurant?.is_loyalty_enabled === 1 ? (
|
||||
<Tag
|
||||
color="green"
|
||||
style={{
|
||||
backgroundColor: "#EDFEF5",
|
||||
borderRadius: "4px",
|
||||
padding: "3px 10px",
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 12,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
placeItems: "center",
|
||||
margin: "0 10px",
|
||||
position: "relative",
|
||||
top: -1,
|
||||
}}
|
||||
>
|
||||
{t("cart.loyalty")}
|
||||
</Tag>
|
||||
) : null}
|
||||
<ArabicPrice
|
||||
price={discountAmount}
|
||||
textStyle={{ ...titlesStyle, color: "#434E5C" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{orderType !== OrderType.Redeem && (
|
||||
@@ -100,7 +132,7 @@ export default function OrderSummary() {
|
||||
</ProText>
|
||||
<ArabicPrice
|
||||
price={tip || 0}
|
||||
style={{ ...titlesStyle, color: "#434E5C" }}
|
||||
textStyle={{ ...titlesStyle, color: "#434E5C" }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -111,7 +143,7 @@ export default function OrderSummary() {
|
||||
</ProText>
|
||||
<ArabicPrice
|
||||
price={0}
|
||||
style={{ ...titlesStyle, color: "#434E5C" }}
|
||||
textStyle={{ ...titlesStyle, color: "#434E5C" }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -122,7 +154,7 @@ export default function OrderSummary() {
|
||||
</ProText>
|
||||
<ArabicPrice
|
||||
price={0}
|
||||
style={{ ...titlesStyle, color: "#32AD6D" }}
|
||||
textStyle={{ ...titlesStyle, color: "#32AD6D" }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -133,7 +165,7 @@ export default function OrderSummary() {
|
||||
</ProText>
|
||||
<ArabicPrice
|
||||
price={taxAmount || 0}
|
||||
style={{ ...titlesStyle, color: "#434E5C" }}
|
||||
textStyle={{ ...titlesStyle, color: "#434E5C" }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -144,7 +176,7 @@ export default function OrderSummary() {
|
||||
</ProText>
|
||||
<ArabicPrice
|
||||
price={splitBillAmount}
|
||||
style={{ ...titlesStyle, color: "#434E5C" }}
|
||||
textStyle={{ ...titlesStyle, color: "#434E5C" }}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -167,7 +199,7 @@ export default function OrderSummary() {
|
||||
</ProText>
|
||||
<ArabicPrice
|
||||
price={grandTotal}
|
||||
style={{
|
||||
textStyle={{
|
||||
fontWeight: 600,
|
||||
fontStyle: "SemiBold",
|
||||
fontSize: 18,
|
||||
@@ -178,43 +210,6 @@ export default function OrderSummary() {
|
||||
/>
|
||||
</div>
|
||||
</Space>
|
||||
|
||||
{isHasLoyaltyGift &&
|
||||
restaurant?.is_loyalty_enabled === 1 &&
|
||||
orderType !== OrderType.Redeem && (
|
||||
<>
|
||||
<Checkbox
|
||||
checked={useLoyaltyPoints}
|
||||
onChange={(value) => {
|
||||
dispatch(updateUseLoyaltyPoints(value.target.checked));
|
||||
}}
|
||||
style={{ marginTop: 8 }}
|
||||
>
|
||||
{t("cart.useLoyaltyPoints")}
|
||||
</Checkbox>
|
||||
</>
|
||||
)}
|
||||
|
||||
{isHasLoyaltyGift &&
|
||||
loyaltyValidation.errorMessage &&
|
||||
orderType !== OrderType.Redeem && (
|
||||
<div style={{ marginTop: 8, color: "red", fontSize: "12px" }}>
|
||||
{t(loyaltyValidation.errorMessage)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isHasLoyaltyGift &&
|
||||
orderType !== OrderType.Redeem &&
|
||||
useLoyaltyPoints &&
|
||||
highestLoyaltyItem &&
|
||||
restaurant?.is_loyalty_enabled === 1 && (
|
||||
<div style={{ marginTop: 8, color: "green", fontSize: "12px" }}>
|
||||
{t("cart.loyaltyDiscountApplied", {
|
||||
itemName: highestLoyaltyItem.name,
|
||||
amount: Math.round(highestLoyaltyItem.price || 0).toFixed(2),
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -873,7 +873,7 @@ export const selectGrandTotal = (state: RootState) => {
|
||||
taxAmount -
|
||||
totalDiscount +
|
||||
deliveryFee -
|
||||
state.order.splitBillAmount -
|
||||
state.order.splitBillAmount +
|
||||
Number(state.order.tip)
|
||||
);
|
||||
};
|
||||
|
||||
@@ -71,7 +71,7 @@ export default function HeaderMenuDrawer() {
|
||||
open={mobileMenuOpen}
|
||||
styles={{
|
||||
body: {
|
||||
padding: 0,
|
||||
padding: 0,
|
||||
},
|
||||
header: {
|
||||
padding: "5px 24px",
|
||||
@@ -122,7 +122,18 @@ export default function HeaderMenuDrawer() {
|
||||
style={mobileMenuLinkStyle(locale === item.key)}
|
||||
>
|
||||
{item.icon}
|
||||
<ProText>{item.label.props.children}</ProText>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 12,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: 0,
|
||||
color: "#333333",
|
||||
}}
|
||||
>
|
||||
{item.label.props.children}
|
||||
</ProText>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import {
|
||||
BgColorsOutlined,
|
||||
HomeOutlined,
|
||||
LoginOutlined,
|
||||
LogoutOutlined,
|
||||
MenuOutlined,
|
||||
TranslationOutlined,
|
||||
BgColorsOutlined,
|
||||
GlobalOutlined,
|
||||
LogoutOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import BranchesIcon from "components/Icons/BranchesIcon";
|
||||
import LoginIcon from "components/Icons/LoginIcon";
|
||||
import LoyaltyAndRewardIcon from "components/Icons/LoyaltyAndRewardIcon";
|
||||
import MyOrderIcon from "components/Icons/MyOrderIcon";
|
||||
import { logoutThunk } from "features/auth/authSlice";
|
||||
import { setLocale, setLocalesThunk } from "features/locale/localeSlice";
|
||||
import { toggleTheme } from "features/theme/themeSlice";
|
||||
@@ -28,7 +29,7 @@ export default function useHeaderMenu() {
|
||||
{
|
||||
key: "language",
|
||||
icon: (
|
||||
<TranslationOutlined
|
||||
<GlobalOutlined
|
||||
style={{ color: themeName === "dark" ? "white" : "#1f2937" }}
|
||||
/>
|
||||
),
|
||||
@@ -58,49 +59,57 @@ export default function useHeaderMenu() {
|
||||
},
|
||||
{
|
||||
key: "orders",
|
||||
icon: (
|
||||
<HomeOutlined
|
||||
style={{ color: themeName === "dark" ? "white" : "#1f2937" }}
|
||||
/>
|
||||
),
|
||||
icon: <MyOrderIcon />,
|
||||
label: <Link to={`/${subdomain}/orders`}>{t("common.myOrder")}</Link>,
|
||||
onClick: () => {
|
||||
navigate(`/${subdomain}/orders`);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "branches",
|
||||
icon: (
|
||||
<MenuOutlined
|
||||
style={{ color: themeName === "dark" ? "white" : "#1f2937" }}
|
||||
/>
|
||||
key: "rewardsAndLoyalty",
|
||||
icon: <LoyaltyAndRewardIcon />,
|
||||
label: (
|
||||
<Link to={`/${subdomain}/rewards-and-loyalty`}>
|
||||
{t("common.rewardsAndLoyalty")}
|
||||
</Link>
|
||||
),
|
||||
onClick: () => {
|
||||
navigate(`/${subdomain}/rewards-and-loyalty`);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "branches",
|
||||
icon: <BranchesIcon />,
|
||||
label: <Link to={`/${subdomain}/menu`}>{t("common.branches")}</Link>,
|
||||
},
|
||||
...(!token ? [{
|
||||
key: "login",
|
||||
icon: (
|
||||
<LoginOutlined
|
||||
style={{ color: themeName === "dark" ? "white" : "#1f2937" }}
|
||||
/>
|
||||
),
|
||||
label: <Link to={`/${subdomain}/login`}>{t("common.login")}</Link>,
|
||||
onClick: () => {
|
||||
navigate(`/${subdomain}/login`);
|
||||
},
|
||||
}] : []),
|
||||
...(token ? [{
|
||||
key: "logout",
|
||||
icon: (
|
||||
<LogoutOutlined
|
||||
style={{ color: themeName === "dark" ? "white" : "#1f2937" }}
|
||||
/>
|
||||
),
|
||||
label: <div>{t("common.logout")}</div>,
|
||||
onClick: () => {
|
||||
dispatch(logoutThunk());
|
||||
},
|
||||
}] : []),
|
||||
...(!token
|
||||
? [
|
||||
{
|
||||
key: "login",
|
||||
icon: <LoginIcon />,
|
||||
label: <Link to={`/${subdomain}/login`}>{t("common.login")}</Link>,
|
||||
onClick: () => {
|
||||
navigate(`/${subdomain}/login`);
|
||||
},
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(token
|
||||
? [
|
||||
{
|
||||
key: "logout",
|
||||
icon: (
|
||||
<LogoutOutlined
|
||||
style={{ color: themeName === "dark" ? "white" : "#1f2937" }}
|
||||
/>
|
||||
),
|
||||
label: <div>{t("common.logout")}</div>,
|
||||
onClick: () => {
|
||||
dispatch(logoutThunk());
|
||||
},
|
||||
},
|
||||
]
|
||||
: []),
|
||||
];
|
||||
return { menuItems };
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import TimeEstimateCard from "pages/cart/components/timeEstimate/TimeEstimateCar
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import GiftAmountCard from "./components/GiftAmountCard/GiftAmountCard";
|
||||
import { GiftAmountBottomSheet } from "./components/GiftAmountBottomSheet";
|
||||
import PickupTimeCard from "pages/checkout/components/pickupEstimate/TimeEstimateCard";
|
||||
|
||||
export default function CardDetailsPage() {
|
||||
const { t } = useTranslation();
|
||||
@@ -168,7 +169,7 @@ export default function CardDetailsPage() {
|
||||
)}
|
||||
<ReceivernformationCard />
|
||||
<SenderformationCard />
|
||||
<TimeEstimateCard />
|
||||
<PickupTimeCard />
|
||||
</Form>
|
||||
</Layout.Content>
|
||||
<Layout.Footer className={styles.checkoutButtonContainer}>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
.useLoyaltyPointsContainer {
|
||||
gap: 20px;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: var(--secondary-background);
|
||||
width: 100%;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { Button, Form, Switch } from "antd";
|
||||
import ProInputCard from "components/ProInputCard/ProInputCard.tsx";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAppDispatch, useAppSelector } from "redux/hooks.ts";
|
||||
import { selectCart, updateUseLoyaltyPoints } from "features/order/orderSlice";
|
||||
import ProText from "components/ProText";
|
||||
import styles from "./EarnLoyaltyPointsCard.module.css";
|
||||
|
||||
export default function EarnLoyaltyPointsCard() {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const { useLoyaltyPoints } = useAppSelector(selectCart);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProInputCard title={t("cart.loyalty")}>
|
||||
<Form.Item name="useLoyaltyPoints">
|
||||
<div className={styles.useLoyaltyPointsContainer}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 4,
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#333333",
|
||||
}}
|
||||
>
|
||||
{t("cart.useLoyaltyPoints")}
|
||||
</ProText>
|
||||
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 400,
|
||||
fontStyle: "Regular",
|
||||
fontSize: 12,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#777580",
|
||||
}}
|
||||
>
|
||||
{t(
|
||||
"cart.applyYourAvailableRewardsToGetDiscountsOnItemsInYourCart",
|
||||
)}
|
||||
</ProText>
|
||||
</div>
|
||||
<Switch
|
||||
autoFocus={false}
|
||||
checked={useLoyaltyPoints}
|
||||
onClick={() => {
|
||||
dispatch(updateUseLoyaltyPoints(!useLoyaltyPoints));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Form.Item>
|
||||
</ProInputCard>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import { useMemo, useState } from "react";
|
||||
import CardAmountIcon from "components/Icons/CardAmountIcon";
|
||||
import ArabicPrice from "components/ArabicPrice";
|
||||
import { GiftAmountBottomSheet } from "pages/CardDetails/components/GiftAmountBottomSheet";
|
||||
import { GiftType } from "components/CustomBottomSheet/GiftTypeBottomSheet";
|
||||
|
||||
export function GiftCard() {
|
||||
const { t } = useTranslation();
|
||||
@@ -32,6 +33,8 @@ export function GiftCard() {
|
||||
const [isGiftAmountBottomSheetOpen, setIsGiftAmountBottomSheetOpen] =
|
||||
useState(false);
|
||||
|
||||
console.log(giftDetails?.giftType);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProInputCard title={t("address.giftDetails")}>
|
||||
@@ -108,10 +111,12 @@ export function GiftCard() {
|
||||
</div>
|
||||
{isRTL ? <BackIcon iconSize={24} /> : <NextIcon iconSize={24} />}
|
||||
</div>
|
||||
|
||||
<Divider style={{ margin: "10px 0" }} />
|
||||
|
||||
{giftDetails?.giftType === "vouchers" ||
|
||||
(giftDetails?.giftType === "itemsAndVouchers" && (
|
||||
{(giftDetails?.giftType === GiftType.Vouchers ||
|
||||
giftDetails?.giftType === GiftType.ItemsAndVouchers) && (
|
||||
<>
|
||||
<div
|
||||
className={styles.orderNotes}
|
||||
onClick={() => {
|
||||
@@ -164,46 +169,49 @@ export function GiftCard() {
|
||||
</div>
|
||||
{isRTL ? <BackIcon iconSize={24} /> : <NextIcon iconSize={24} />}
|
||||
</div>
|
||||
))}
|
||||
{giftDetails?.giftType === GiftType.ItemsAndVouchers && (
|
||||
<Divider style={{ margin: "10px 0" }} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<Divider style={{ margin: "10px 0" }} />
|
||||
{giftDetails?.giftType === "items" ||
|
||||
(giftDetails?.giftType === "itemsAndVouchers" && (
|
||||
<div
|
||||
{(giftDetails?.giftType === GiftType.Items ||
|
||||
giftDetails?.giftType === GiftType.ItemsAndVouchers) && (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
onClick={() => {
|
||||
navigate(`/${subdomain}/cart`);
|
||||
}}
|
||||
>
|
||||
<ProText
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
onClick={() => {
|
||||
navigate(`/${subdomain}/cart`);
|
||||
fontWeight: 400,
|
||||
fontStyle: "Regular",
|
||||
fontSize: 12,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#777580",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
<ProText
|
||||
<span
|
||||
style={{
|
||||
fontWeight: 400,
|
||||
fontStyle: "Regular",
|
||||
fontSize: 12,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#777580",
|
||||
cursor: "pointer",
|
||||
[isRTL ? "marginLeft" : "marginRight"]: 5,
|
||||
position: "relative",
|
||||
top: 3.5,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
[isRTL ? "marginLeft" : "marginRight"]: 5,
|
||||
position: "relative",
|
||||
top: 3.5,
|
||||
}}
|
||||
>
|
||||
<InvoiceIcon />
|
||||
</span>
|
||||
{t("checkout.viewOrder")} ( {totalItems} {t("cart.items")} )
|
||||
</ProText>
|
||||
{isRTL ? <BackIcon /> : <NextIcon />}
|
||||
</div>
|
||||
))}
|
||||
<InvoiceIcon />
|
||||
</span>
|
||||
{t("checkout.viewOrder")} ( {totalItems} {t("cart.items")} )
|
||||
</ProText>
|
||||
{isRTL ? <BackIcon /> : <NextIcon />}
|
||||
</div>
|
||||
)}
|
||||
</ProInputCard>
|
||||
<GiftAmountBottomSheet
|
||||
isOpen={isGiftAmountBottomSheetOpen}
|
||||
|
||||
@@ -23,6 +23,7 @@ import { CarCard } from "./components/CarCard";
|
||||
import { CollectWay } from "./components/CollectWay/CollectWay";
|
||||
import PickupTimeCard from "./components/pickupEstimate/TimeEstimateCard";
|
||||
import VoucherSummary from "pages/redeem/components/VoucherSummary/VoucherSummary";
|
||||
import EarnLoyaltyPointsCard from "pages/cart/components/earnLoyaltyPointsCard/EarnLoyaltyPointsCard";
|
||||
|
||||
export default function CheckoutPage() {
|
||||
const { t } = useTranslation();
|
||||
@@ -85,7 +86,9 @@ export default function CheckoutPage() {
|
||||
<OfficeDetails /> */}
|
||||
{/* <GiftDetails /> */}
|
||||
{/* <BriefMenu /> */}
|
||||
{orderType !== OrderType.Redeem && <CouponCard />}
|
||||
{orderType !== OrderType.Redeem && orderType !== OrderType.Gift && (
|
||||
<CouponCard />
|
||||
)}
|
||||
|
||||
{/* Collection Method */}
|
||||
{orderType === OrderType.Pickup && (
|
||||
@@ -123,7 +126,12 @@ export default function CheckoutPage() {
|
||||
)}
|
||||
|
||||
{/* Reward Your Waiter */}
|
||||
{orderType !== OrderType.Redeem && <RewardWaiterCard />}
|
||||
{orderType !== OrderType.Redeem && orderType !== OrderType.Gift && (
|
||||
<RewardWaiterCard />
|
||||
)}
|
||||
{orderType !== OrderType.Redeem && orderType !== OrderType.Gift && (
|
||||
<EarnLoyaltyPointsCard />
|
||||
)}
|
||||
<BriefMenuCard />
|
||||
<Ads1 />
|
||||
<OrderSummary />
|
||||
|
||||
@@ -44,13 +44,7 @@ export function MenuFooter() {
|
||||
}}
|
||||
>
|
||||
<Link
|
||||
to={
|
||||
totalItems === 0
|
||||
? "#"
|
||||
: orderType === OrderType.Pay
|
||||
? `/${subdomain}/pay`
|
||||
: `/${subdomain}/cart`
|
||||
}
|
||||
to={totalItems === 0 ? "#" : `/${subdomain}/cart`}
|
||||
onClick={(e) => {
|
||||
if (totalItems === 0) {
|
||||
e.preventDefault();
|
||||
@@ -106,9 +100,7 @@ export function MenuFooter() {
|
||||
margin: "0 10px",
|
||||
}}
|
||||
>
|
||||
{orderType === OrderType.Pay
|
||||
? t("menu.pay")
|
||||
: t("menu.viewCart")}
|
||||
{t("menu.viewCart")}
|
||||
</ProText>
|
||||
</Button>
|
||||
<div
|
||||
|
||||
@@ -844,3 +844,21 @@
|
||||
white-space: nowrap;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.frameSelect {
|
||||
align-items: flex-start;
|
||||
background-color: #aaa7a733;
|
||||
border-radius: 60px;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.divSelect {
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
gap: 4px;
|
||||
position: relative;
|
||||
}
|
||||
@@ -97,21 +97,27 @@ function MenuPage() {
|
||||
className={`${styles.headerFloatingBtn} ${styles.orderTypeSelectContainer} order-type-select-container`}
|
||||
>
|
||||
{orderType !== OrderType.Redeem && (
|
||||
<Select
|
||||
value={orderType}
|
||||
options={orderTypeOptions}
|
||||
open={false}
|
||||
onOpenChange={() => false}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsOrderTypesOpen(true);
|
||||
}}
|
||||
variant="borderless"
|
||||
size="small"
|
||||
className={styles.orderTypeSelect}
|
||||
classNames={{ popup: { root: "order-type-select-dropdown" } }}
|
||||
listHeight={150}
|
||||
/>
|
||||
<div className={styles.frameSelect}>
|
||||
<div className={styles.divSelect}>
|
||||
<Select
|
||||
value={orderType}
|
||||
options={orderTypeOptions}
|
||||
open={false}
|
||||
onOpenChange={() => false}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setIsOrderTypesOpen(true);
|
||||
}}
|
||||
variant="borderless"
|
||||
size="small"
|
||||
className={styles.orderTypeSelect}
|
||||
classNames={{
|
||||
popup: { root: "order-type-select-dropdown" },
|
||||
}}
|
||||
listHeight={150}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{orderType === OrderType.Redeem && (
|
||||
<div className={styles.frame}>
|
||||
|
||||
@@ -260,7 +260,6 @@ export default function RestaurantServices() {
|
||||
onClose={() => setIsGiftTypeBottomSheetOpen(false)}
|
||||
onSave={() => {
|
||||
setIsGiftTypeBottomSheetOpen(false);
|
||||
navigate(`/${subdomain}/menu?orderType=${OrderType.Gift}`);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
469
src/pages/rewardsAndLoyalty/page.tsx
Normal file
469
src/pages/rewardsAndLoyalty/page.tsx
Normal file
@@ -0,0 +1,469 @@
|
||||
import { Button, Card, Flex, Layout, Progress, Timeline, Tooltip } from "antd";
|
||||
|
||||
import ProHeader from "components/ProHeader/ProHeader";
|
||||
import ProText from "components/ProText";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import styles from "./rewardsAndLoyalty.module.css";
|
||||
|
||||
import { OrderType } from "pages/checkout/hooks/types.ts";
|
||||
import { useAppDispatch, useAppSelector } from "redux/hooks";
|
||||
import { selectCart, updateUseLoyaltyPoints } from "features/order/orderSlice";
|
||||
import CoinsIcon from "components/Icons/CoinsIcon";
|
||||
import ArabicPrice from "components/ArabicPrice";
|
||||
import RaiseIcon from "components/Icons/RaiseIcon";
|
||||
import CupIcon from "components/Icons/CupIcon";
|
||||
import ProInputCard from "components/ProInputCard/ProInputCard";
|
||||
import { useGetLoyaltyHistoryQuery } from "redux/api/others";
|
||||
import dayjs from "dayjs";
|
||||
import PopularIcon from "components/Icons/PopularIcon";
|
||||
|
||||
export default function RewardsAndLoyalityPage() {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const { subdomain } = useParams();
|
||||
|
||||
const { restaurant } = useAppSelector(selectCart);
|
||||
const loyaltyStamps = restaurant?.loyalty_stamps ?? 0;
|
||||
const customerLoyaltyPoints = restaurant?.customer_loyalty_points ?? 0;
|
||||
const { data: loyaltyHistory } = useGetLoyaltyHistoryQuery();
|
||||
const loyaltyHistories = loyaltyHistory?.filter(
|
||||
(LH) => Number(LH.restaurant_id) === Number(restaurant.restautantId),
|
||||
);
|
||||
|
||||
const handleRedeem = () => {
|
||||
navigate(`/${subdomain}/menu?orderType=${OrderType.DineIn}`);
|
||||
dispatch(updateUseLoyaltyPoints(true));
|
||||
};
|
||||
|
||||
const currentStampRound = customerLoyaltyPoints % loyaltyStamps;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Layout>
|
||||
<ProHeader>{t("rewardsAndLoyalty.title")}</ProHeader>
|
||||
<Layout.Content className={styles.redeemContainer}>
|
||||
<Flex gap="small" wrap justify="center">
|
||||
<Tooltip title="3 done / 3 in progress / 4 to do">
|
||||
<div style={{ margin: "47px 47px 20px 47px" }}>
|
||||
<Progress
|
||||
percent={(currentStampRound / loyaltyStamps) * 100}
|
||||
format={() => (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 4,
|
||||
}}
|
||||
>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 600,
|
||||
fontStyle: "SemiBold",
|
||||
fontSize: 48,
|
||||
lineHeight: "100%",
|
||||
letterSpacing: "0%",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{currentStampRound} / {loyaltyStamps}
|
||||
</ProText>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 400,
|
||||
fontStyle: "Regular",
|
||||
fontSize: 16,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
textAlign: "center",
|
||||
color: "#E8B400",
|
||||
marginTop: 4,
|
||||
}}
|
||||
>
|
||||
{t("rewardsAndLoyalty.completedPurchases")}
|
||||
</ProText>
|
||||
</div>
|
||||
)}
|
||||
strokeColor="#FFB700"
|
||||
size={250}
|
||||
type="circle"
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
|
||||
<Flex
|
||||
gap="small"
|
||||
wrap={false}
|
||||
justify="center"
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
<div className={styles.orderNotes}>
|
||||
<div
|
||||
style={{
|
||||
height: 32,
|
||||
width: 32,
|
||||
minHeight: 32,
|
||||
minWidth: 32,
|
||||
backgroundColor: "var(--background)",
|
||||
borderRadius: "50%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<CoinsIcon />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 4,
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 400,
|
||||
fontStyle: "Regular",
|
||||
fontSize: 12,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#777580",
|
||||
}}
|
||||
>
|
||||
{t("rewardsAndLoyalty.saved")}
|
||||
</ProText>
|
||||
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#333333",
|
||||
}}
|
||||
>
|
||||
<ArabicPrice price={customerLoyaltyPoints || 0} />
|
||||
</ProText>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.orderNotes}>
|
||||
<div
|
||||
style={{
|
||||
height: 32,
|
||||
width: 32,
|
||||
minHeight: 32,
|
||||
minWidth: 32,
|
||||
backgroundColor: "var(--background)",
|
||||
borderRadius: "50%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<RaiseIcon />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 4,
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 400,
|
||||
fontStyle: "Regular",
|
||||
fontSize: 12,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#777580",
|
||||
}}
|
||||
>
|
||||
{t("rewardsAndLoyalty.totalPurchased")}
|
||||
</ProText>
|
||||
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#333333",
|
||||
}}
|
||||
>
|
||||
{loyaltyStamps}
|
||||
</ProText>
|
||||
</div>
|
||||
</div>
|
||||
</Flex>
|
||||
|
||||
<div className={styles.nextRewards}>
|
||||
<div
|
||||
style={{
|
||||
height: 42,
|
||||
width: 42,
|
||||
minHeight: 42,
|
||||
minWidth: 42,
|
||||
backgroundColor: "#FFF5D4",
|
||||
borderRadius: "50%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<CupIcon />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 4,
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 16,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
}}
|
||||
>
|
||||
{t("rewardsAndLoyalty.almosthere")}
|
||||
</ProText>
|
||||
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 400,
|
||||
fontStyle: "Regular",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#777580",
|
||||
}}
|
||||
>
|
||||
{t("rewardsAndLoyalty.youreJustXCupsAwayFromYourNextReward", {
|
||||
cups: loyaltyStamps - (customerLoyaltyPoints % loyaltyStamps),
|
||||
})}
|
||||
</ProText>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ProInputCard title={t("rewardsAndLoyalty.yourAvailableRewards")}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 10,
|
||||
alignItems: "center",
|
||||
placeItems: "center",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
height: 42,
|
||||
width: 42,
|
||||
minHeight: 42,
|
||||
minWidth: 42,
|
||||
backgroundColor: "#FFF5D4",
|
||||
borderRadius: "50%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<CupIcon />
|
||||
</div>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 600,
|
||||
fontStyle: "SemiBold",
|
||||
fontSize: 18,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{t("rewardsAndLoyalty.youCurrentlyHave")}
|
||||
</ProText>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 600,
|
||||
fontStyle: "SemiBold",
|
||||
fontSize: 20,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
textAlign: "center",
|
||||
color: "#E8B400",
|
||||
}}
|
||||
>
|
||||
<span style={{ padding: "0 4px" }}>
|
||||
{Math.floor(customerLoyaltyPoints / loyaltyStamps)}
|
||||
</span>
|
||||
{t("rewardsAndLoyalty.freeItems")}
|
||||
</ProText>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 400,
|
||||
fontStyle: "Regular",
|
||||
fontSize: 12,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
textAlign: "center",
|
||||
color: "#777580",
|
||||
}}
|
||||
>
|
||||
{t("rewardsAndLoyalty.youCanRedeemDuringTheCheckout")}
|
||||
</ProText>
|
||||
<Button
|
||||
type="primary"
|
||||
shape="round"
|
||||
className={styles.checkoutButton}
|
||||
onClick={handleRedeem}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: 40,
|
||||
borderRadius: 888,
|
||||
backgroundColor: "#FFB700",
|
||||
color: "white",
|
||||
}}
|
||||
>
|
||||
{t("rewardsAndLoyalty.redeemNow")}
|
||||
</Button>
|
||||
</div>
|
||||
</ProInputCard>
|
||||
|
||||
<ProInputCard title={t("rewardsAndLoyalty.loyaltyHistory")}>
|
||||
<Timeline
|
||||
items={
|
||||
loyaltyHistories && loyaltyHistories.length > 0
|
||||
? loyaltyHistories.map((item: any, index: number) => ({
|
||||
content: (
|
||||
<div key={index}>
|
||||
{/* <ProText
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#333333",
|
||||
}}
|
||||
>
|
||||
{item.restaurant_name ||
|
||||
item.name ||
|
||||
item.restaurantName ||
|
||||
t("rewardsAndLoyalty.order")}
|
||||
</ProText> */}
|
||||
{(item.created_at ||
|
||||
item.date ||
|
||||
item.order_date ||
|
||||
true) && (
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 600,
|
||||
fontStyle: "SemiBold",
|
||||
fontSize: 16,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#777580",
|
||||
}}
|
||||
>
|
||||
{dayjs(
|
||||
item.created_at || item.date || item.order_date,
|
||||
).format("DD MMMM YYYY")}
|
||||
</ProText>
|
||||
)}
|
||||
<div className={styles.loyaltyHistoryItem}>
|
||||
<div
|
||||
style={{
|
||||
height: 30,
|
||||
width: 20,
|
||||
minHeight: 30,
|
||||
minWidth: 20,
|
||||
borderRadius: "50%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<PopularIcon />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 4,
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 16,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
}}
|
||||
>
|
||||
{t("rewardsAndLoyalty.earned")}{" "}
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 16,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#E8B400",
|
||||
}}
|
||||
>
|
||||
{t("rewardsAndLoyalty.xPoints", {
|
||||
points:
|
||||
item.total_points ||
|
||||
item.points ||
|
||||
item.loyalty_stamps,
|
||||
})}
|
||||
</ProText>
|
||||
</ProText>
|
||||
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 400,
|
||||
fontStyle: "Regular",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#777580",
|
||||
}}
|
||||
>
|
||||
{t("rewardsAndLoyalty.yourOrderFrom", {
|
||||
restaurantName:
|
||||
item.restaurant_name ||
|
||||
item.name ||
|
||||
item.restaurantName,
|
||||
})}
|
||||
</ProText>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
: []
|
||||
}
|
||||
/>
|
||||
</ProInputCard>
|
||||
</Layout.Content>
|
||||
</Layout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
51
src/pages/rewardsAndLoyalty/rewardsAndLoyalty.module.css
Normal file
51
src/pages/rewardsAndLoyalty/rewardsAndLoyalty.module.css
Normal file
@@ -0,0 +1,51 @@
|
||||
.redeemContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
gap: 16px;
|
||||
overflow: auto;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.orderNotes {
|
||||
gap: 20px;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: var(--secondary-background);
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nextRewards {
|
||||
gap: 20px;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: #fefbf2;
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
border: 1px solid #ffedb0;
|
||||
}
|
||||
|
||||
.loyaltyHistoryItem {
|
||||
gap: 20px;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: var(--background);
|
||||
width: 100%;
|
||||
width: 275;
|
||||
opacity: 1;
|
||||
padding-top: 14px;
|
||||
padding-right: 12px;
|
||||
padding-bottom: 14px;
|
||||
padding-left: 12px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
94
src/pages/rewardsAndLoyalty/types.ts
Normal file
94
src/pages/rewardsAndLoyalty/types.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
export interface RedeemResponse {
|
||||
gift: Gift
|
||||
working_hours: WorkingHours
|
||||
notes: Notes
|
||||
is_restaurant_closed: boolean
|
||||
}
|
||||
|
||||
export interface Gift {
|
||||
id: number
|
||||
voucher_amount: string
|
||||
amount: string
|
||||
restorant_id: number
|
||||
voucher_code: string
|
||||
used_amount: string
|
||||
show_sender_info: number
|
||||
remaining_amount: string
|
||||
is_used: number
|
||||
sender_phone: string
|
||||
gift_type: string
|
||||
sender_name: string
|
||||
recipient_phone: string
|
||||
recipient_name: string
|
||||
message: any
|
||||
created_at: string
|
||||
card_url: string
|
||||
gr_url: string
|
||||
restaurant: string
|
||||
global_currency: string
|
||||
lat: string
|
||||
lng: string
|
||||
local_currency: string
|
||||
restaurant_iimage: string
|
||||
order_id: number
|
||||
items: Item[]
|
||||
itemsImagePrefix: string
|
||||
itemsImagePrefixOld: string
|
||||
}
|
||||
|
||||
export interface Item {
|
||||
id: number
|
||||
is_loyalty_used: number
|
||||
no_of_stamps_give: number
|
||||
isHasLoyalty: boolean
|
||||
is_vat_disabled: number
|
||||
name: string
|
||||
price: number
|
||||
qty: number
|
||||
variant_price: string
|
||||
image: string
|
||||
imageName: string
|
||||
variantName: string
|
||||
variantLocalName: string
|
||||
extras: any[]
|
||||
descriptionEN: string
|
||||
descriptionAR: string
|
||||
itemline: string
|
||||
itemlineAR: string
|
||||
itemlineAREN: string
|
||||
extrasgroups: any[]
|
||||
extragroupnew: any[]
|
||||
itemComment: string
|
||||
variant: any
|
||||
itemExtras: any[]
|
||||
AvaiilableVariantExtras: any[]
|
||||
isPrinted: number
|
||||
category_id: number
|
||||
pos_order_id: string
|
||||
updated_at: string
|
||||
created_at: string
|
||||
old_qty: number
|
||||
new_qty: number
|
||||
last_printed_qty: number
|
||||
deleted_qty: number
|
||||
discount_value: any
|
||||
discount_type_id: any
|
||||
original_price: number
|
||||
pricing_method: string
|
||||
is_already_paid: number
|
||||
hash_item: string
|
||||
}
|
||||
|
||||
export interface WorkingHours {
|
||||
opening_time: string
|
||||
closing_time: string
|
||||
opening_time_2: any
|
||||
closing_time_2: any
|
||||
is_open: boolean
|
||||
}
|
||||
|
||||
export interface Notes {
|
||||
en: string
|
||||
ar: string
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
USER_DETAILS_URL,
|
||||
EGIFT_CARDS_URL,
|
||||
REDEEM_DETAILS_URL,
|
||||
LOYALTY_HISTORY_URL,
|
||||
} from "utils/constants";
|
||||
|
||||
import { OrderDetails } from "pages/checkout/hooks/types";
|
||||
@@ -182,6 +183,25 @@ export const branchApi = baseApi.injectEndpoints({
|
||||
return response.result;
|
||||
},
|
||||
}),
|
||||
getLoyaltyHistory: builder.query<
|
||||
{
|
||||
restaurant_id: number;
|
||||
restaurant_name: string;
|
||||
restaurant_icon: string;
|
||||
total_points: string;
|
||||
loyalty_stamp_image: string;
|
||||
loyalty_stamps: number;
|
||||
}[],
|
||||
void
|
||||
>({
|
||||
query: () => ({
|
||||
url: LOYALTY_HISTORY_URL,
|
||||
method: "GET",
|
||||
}),
|
||||
transformResponse: (response: any) => {
|
||||
return response.result.data.orders;
|
||||
},
|
||||
}),
|
||||
}),
|
||||
});
|
||||
export const {
|
||||
@@ -197,4 +217,5 @@ export const {
|
||||
useGetUserDetailsQuery,
|
||||
useGetEGiftCardsQuery,
|
||||
useGetRedeemDetailsQuery,
|
||||
useGetLoyaltyHistoryQuery,
|
||||
} = branchApi;
|
||||
|
||||
@@ -18,6 +18,7 @@ import OtpPage from "pages/otp/page";
|
||||
import ProductDetailPage from "pages/product/page";
|
||||
import RedeemPage from "pages/redeem/page";
|
||||
import RestaurantPage from "pages/restaurant/page";
|
||||
import RewardsAndLoyalityPage from "pages/rewardsAndLoyalty/page";
|
||||
import SearchPage from "pages/search/page";
|
||||
import SplitBillPage from "pages/split-bill/page";
|
||||
import React, { ReactNode, Suspense, useEffect } from "react";
|
||||
@@ -170,6 +171,11 @@ export const router = createHashRouter([
|
||||
element: <PageWrapper children={<RedeemPage />} />,
|
||||
errorElement: <ErrorPage />,
|
||||
},
|
||||
{
|
||||
path: "rewards-and-loyalty",
|
||||
element: <PageWrapper children={<RewardsAndLoyalityPage />} />,
|
||||
errorElement: <ErrorPage />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -110,3 +110,4 @@ export const PAYMENT_CONFIRMATION_URL = `https://menu.fascano.com/payment/confir
|
||||
export const DISCOUNT_URL = `${BASE_URL}getDiscount`;
|
||||
export const EGIFT_CARDS_URL = `${BASE_URL}gift/cards`;
|
||||
export const REDEEM_DETAILS_URL = `${BASE_URL}gift/getGiftOrderByVoucherCode`;
|
||||
export const LOYALTY_HISTORY_URL = `${BASE_URL}loyaltyHistory`;
|
||||
Reference in New Issue
Block a user