enhance loyalty section UI
This commit is contained in:
@@ -92,7 +92,7 @@
|
|||||||
"scheduledOrder": "طلب مجدول"
|
"scheduledOrder": "طلب مجدول"
|
||||||
},
|
},
|
||||||
"promotion": {
|
"promotion": {
|
||||||
"title": "الترويجات",
|
"title": "عرض التفاصيل",
|
||||||
"description": "احصل على خصم 10% على طلبك الأول"
|
"description": "احصل على خصم 10% على طلبك الأول"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -108,7 +108,7 @@
|
|||||||
"scheduledOrder": "Scheduled Order"
|
"scheduledOrder": "Scheduled Order"
|
||||||
},
|
},
|
||||||
"promotion": {
|
"promotion": {
|
||||||
"title": "Promotions",
|
"title": "Show details",
|
||||||
"description": "Get 10% off your first order"
|
"description": "Get 10% off your first order"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -282,7 +282,9 @@
|
|||||||
"am": "AM",
|
"am": "AM",
|
||||||
"pm": "PM",
|
"pm": "PM",
|
||||||
"cannotSelectPastDate": "You cannot select a past date. Please select today or a future date.",
|
"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": {
|
"checkout": {
|
||||||
"addCarDetails": "Add Car Details",
|
"addCarDetails": "Add Car Details",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
min-height: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.summaryDivider {
|
.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 ArabicPrice from "components/ArabicPrice";
|
||||||
import {
|
import {
|
||||||
selectCart,
|
selectCart,
|
||||||
@@ -69,7 +69,7 @@ export default function OrderSummary() {
|
|||||||
<ProText type="secondary" style={titlesStyle}>
|
<ProText type="secondary" style={titlesStyle}>
|
||||||
{t("cart.basketTotal")}
|
{t("cart.basketTotal")}
|
||||||
</ProText>
|
</ProText>
|
||||||
<ArabicPrice price={subtotal} style={titlesStyle} />
|
<ArabicPrice price={subtotal} textStyle={titlesStyle} />
|
||||||
</div>
|
</div>
|
||||||
{orderType === OrderType.Delivery && (
|
{orderType === OrderType.Delivery && (
|
||||||
<div className={styles.summaryRow}>
|
<div className={styles.summaryRow}>
|
||||||
@@ -78,7 +78,7 @@ export default function OrderSummary() {
|
|||||||
</ProText>
|
</ProText>
|
||||||
<ArabicPrice
|
<ArabicPrice
|
||||||
price={Number(restaurant?.delivery_fees || 0)}
|
price={Number(restaurant?.delivery_fees || 0)}
|
||||||
style={{ ...titlesStyle, color: "#434E5C" }}
|
textStyle={{ ...titlesStyle, color: "#434E5C" }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -87,11 +87,43 @@ export default function OrderSummary() {
|
|||||||
<ProText type="secondary" style={titlesStyle}>
|
<ProText type="secondary" style={titlesStyle}>
|
||||||
{t("cart.discount")}
|
{t("cart.discount")}
|
||||||
</ProText>
|
</ProText>
|
||||||
|
<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
|
<ArabicPrice
|
||||||
price={discountAmount}
|
price={discountAmount}
|
||||||
style={{ ...titlesStyle, color: "#434E5C" }}
|
textStyle={{ ...titlesStyle, color: "#434E5C" }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
{orderType !== OrderType.Redeem && (
|
{orderType !== OrderType.Redeem && (
|
||||||
<div className={styles.summaryRow}>
|
<div className={styles.summaryRow}>
|
||||||
@@ -100,7 +132,7 @@ export default function OrderSummary() {
|
|||||||
</ProText>
|
</ProText>
|
||||||
<ArabicPrice
|
<ArabicPrice
|
||||||
price={tip || 0}
|
price={tip || 0}
|
||||||
style={{ ...titlesStyle, color: "#434E5C" }}
|
textStyle={{ ...titlesStyle, color: "#434E5C" }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -111,7 +143,7 @@ export default function OrderSummary() {
|
|||||||
</ProText>
|
</ProText>
|
||||||
<ArabicPrice
|
<ArabicPrice
|
||||||
price={0}
|
price={0}
|
||||||
style={{ ...titlesStyle, color: "#434E5C" }}
|
textStyle={{ ...titlesStyle, color: "#434E5C" }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -122,7 +154,7 @@ export default function OrderSummary() {
|
|||||||
</ProText>
|
</ProText>
|
||||||
<ArabicPrice
|
<ArabicPrice
|
||||||
price={0}
|
price={0}
|
||||||
style={{ ...titlesStyle, color: "#32AD6D" }}
|
textStyle={{ ...titlesStyle, color: "#32AD6D" }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -133,7 +165,7 @@ export default function OrderSummary() {
|
|||||||
</ProText>
|
</ProText>
|
||||||
<ArabicPrice
|
<ArabicPrice
|
||||||
price={taxAmount || 0}
|
price={taxAmount || 0}
|
||||||
style={{ ...titlesStyle, color: "#434E5C" }}
|
textStyle={{ ...titlesStyle, color: "#434E5C" }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -144,7 +176,7 @@ export default function OrderSummary() {
|
|||||||
</ProText>
|
</ProText>
|
||||||
<ArabicPrice
|
<ArabicPrice
|
||||||
price={splitBillAmount}
|
price={splitBillAmount}
|
||||||
style={{ ...titlesStyle, color: "#434E5C" }}
|
textStyle={{ ...titlesStyle, color: "#434E5C" }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -167,7 +199,7 @@ export default function OrderSummary() {
|
|||||||
</ProText>
|
</ProText>
|
||||||
<ArabicPrice
|
<ArabicPrice
|
||||||
price={grandTotal}
|
price={grandTotal}
|
||||||
style={{
|
textStyle={{
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
fontStyle: "SemiBold",
|
fontStyle: "SemiBold",
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
@@ -178,43 +210,6 @@ export default function OrderSummary() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Space>
|
</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>
|
</Card>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ import { CarCard } from "./components/CarCard";
|
|||||||
import { CollectWay } from "./components/CollectWay/CollectWay";
|
import { CollectWay } from "./components/CollectWay/CollectWay";
|
||||||
import PickupTimeCard from "./components/pickupEstimate/TimeEstimateCard";
|
import PickupTimeCard from "./components/pickupEstimate/TimeEstimateCard";
|
||||||
import VoucherSummary from "pages/redeem/components/VoucherSummary/VoucherSummary";
|
import VoucherSummary from "pages/redeem/components/VoucherSummary/VoucherSummary";
|
||||||
|
import EarnLoyaltyPointsCard from "pages/cart/components/earnLoyaltyPointsCard/EarnLoyaltyPointsCard";
|
||||||
|
|
||||||
export default function CheckoutPage() {
|
export default function CheckoutPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -85,7 +86,9 @@ export default function CheckoutPage() {
|
|||||||
<OfficeDetails /> */}
|
<OfficeDetails /> */}
|
||||||
{/* <GiftDetails /> */}
|
{/* <GiftDetails /> */}
|
||||||
{/* <BriefMenu /> */}
|
{/* <BriefMenu /> */}
|
||||||
{orderType !== OrderType.Redeem && orderType !== OrderType.Gift && <CouponCard />}
|
{orderType !== OrderType.Redeem && orderType !== OrderType.Gift && (
|
||||||
|
<CouponCard />
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Collection Method */}
|
{/* Collection Method */}
|
||||||
{orderType === OrderType.Pickup && (
|
{orderType === OrderType.Pickup && (
|
||||||
@@ -123,7 +126,12 @@ export default function CheckoutPage() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Reward Your Waiter */}
|
{/* Reward Your Waiter */}
|
||||||
{orderType !== OrderType.Redeem && orderType !== OrderType.Gift && <RewardWaiterCard />}
|
{orderType !== OrderType.Redeem && orderType !== OrderType.Gift && (
|
||||||
|
<RewardWaiterCard />
|
||||||
|
)}
|
||||||
|
{orderType !== OrderType.Redeem && orderType !== OrderType.Gift && (
|
||||||
|
<EarnLoyaltyPointsCard />
|
||||||
|
)}
|
||||||
<BriefMenuCard />
|
<BriefMenuCard />
|
||||||
<Ads1 />
|
<Ads1 />
|
||||||
<OrderSummary />
|
<OrderSummary />
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import { useNavigate, useParams } from "react-router-dom";
|
|||||||
import styles from "./rewardsAndLoyalty.module.css";
|
import styles from "./rewardsAndLoyalty.module.css";
|
||||||
|
|
||||||
import { OrderType } from "pages/checkout/hooks/types.ts";
|
import { OrderType } from "pages/checkout/hooks/types.ts";
|
||||||
import { useAppSelector } from "redux/hooks";
|
import { useAppDispatch, useAppSelector } from "redux/hooks";
|
||||||
import { selectCart } from "features/order/orderSlice";
|
import { selectCart, updateUseLoyaltyPoints } from "features/order/orderSlice";
|
||||||
import CoinsIcon from "components/Icons/CoinsIcon";
|
import CoinsIcon from "components/Icons/CoinsIcon";
|
||||||
import ArabicPrice from "components/ArabicPrice";
|
import ArabicPrice from "components/ArabicPrice";
|
||||||
import RaiseIcon from "components/Icons/RaiseIcon";
|
import RaiseIcon from "components/Icons/RaiseIcon";
|
||||||
@@ -19,6 +19,7 @@ import dayjs from "dayjs";
|
|||||||
import PopularIcon from "components/Icons/PopularIcon";
|
import PopularIcon from "components/Icons/PopularIcon";
|
||||||
|
|
||||||
export default function RewardsAndLoyalityPage() {
|
export default function RewardsAndLoyalityPage() {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { subdomain } = useParams();
|
const { subdomain } = useParams();
|
||||||
@@ -27,19 +28,17 @@ export default function RewardsAndLoyalityPage() {
|
|||||||
const loyaltyStamps = restaurant?.loyalty_stamps ?? 0;
|
const loyaltyStamps = restaurant?.loyalty_stamps ?? 0;
|
||||||
const customerLoyaltyPoints = restaurant?.customer_loyalty_points ?? 0;
|
const customerLoyaltyPoints = restaurant?.customer_loyalty_points ?? 0;
|
||||||
const { data: loyaltyHistory } = useGetLoyaltyHistoryQuery();
|
const { data: loyaltyHistory } = useGetLoyaltyHistoryQuery();
|
||||||
|
const loyaltyHistories = loyaltyHistory?.filter(
|
||||||
|
(LH) => Number(LH.restaurant_id) === Number(restaurant.restautantId),
|
||||||
|
);
|
||||||
|
|
||||||
console.log(loyaltyHistory);
|
const handleRedeem = () => {
|
||||||
|
navigate(`/${subdomain}/menu?orderType=${OrderType.DineIn}`);
|
||||||
// Calculate percentage: (customer_loyalty_points / loyalty_stamps) * 100
|
dispatch(updateUseLoyaltyPoints(true));
|
||||||
const progressPercent =
|
|
||||||
loyaltyStamps > 0
|
|
||||||
? Math.min((customerLoyaltyPoints / loyaltyStamps) * 100, 100)
|
|
||||||
: 0;
|
|
||||||
|
|
||||||
const handleCheckout = () => {
|
|
||||||
navigate(`/${subdomain}/menu?orderType=${OrderType.Redeem}`);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const currentStampRound = customerLoyaltyPoints % loyaltyStamps;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Layout>
|
<Layout>
|
||||||
@@ -49,7 +48,7 @@ export default function RewardsAndLoyalityPage() {
|
|||||||
<Tooltip title="3 done / 3 in progress / 4 to do">
|
<Tooltip title="3 done / 3 in progress / 4 to do">
|
||||||
<div style={{ margin: "47px 47px 20px 47px" }}>
|
<div style={{ margin: "47px 47px 20px 47px" }}>
|
||||||
<Progress
|
<Progress
|
||||||
percent={70}
|
percent={(currentStampRound / loyaltyStamps) * 100}
|
||||||
format={() => (
|
format={() => (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -70,9 +69,7 @@ export default function RewardsAndLoyalityPage() {
|
|||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Number(customerLoyaltyPoints / loyaltyStamps).toFixed(
|
{currentStampRound} / {loyaltyStamps}
|
||||||
0,
|
|
||||||
)}
|
|
||||||
</ProText>
|
</ProText>
|
||||||
<ProText
|
<ProText
|
||||||
style={{
|
style={{
|
||||||
@@ -332,7 +329,7 @@ export default function RewardsAndLoyalityPage() {
|
|||||||
type="primary"
|
type="primary"
|
||||||
shape="round"
|
shape="round"
|
||||||
className={styles.checkoutButton}
|
className={styles.checkoutButton}
|
||||||
onClick={handleCheckout}
|
onClick={handleRedeem}
|
||||||
style={{
|
style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: 40,
|
height: 40,
|
||||||
@@ -349,8 +346,8 @@ export default function RewardsAndLoyalityPage() {
|
|||||||
<ProInputCard title={t("rewardsAndLoyalty.loyaltyHistory")}>
|
<ProInputCard title={t("rewardsAndLoyalty.loyaltyHistory")}>
|
||||||
<Timeline
|
<Timeline
|
||||||
items={
|
items={
|
||||||
loyaltyHistory && loyaltyHistory.length > 0
|
loyaltyHistories && loyaltyHistories.length > 0
|
||||||
? loyaltyHistory.map((item: any, index: number) => ({
|
? loyaltyHistories.map((item: any, index: number) => ({
|
||||||
content: (
|
content: (
|
||||||
<div key={index}>
|
<div key={index}>
|
||||||
{/* <ProText
|
{/* <ProText
|
||||||
|
|||||||
@@ -39,7 +39,13 @@
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: var(--secondary-background);
|
background-color: var(--background);
|
||||||
padding: 16px;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
width: 275;
|
||||||
|
opacity: 1;
|
||||||
|
padding-top: 14px;
|
||||||
|
padding-right: 12px;
|
||||||
|
padding-bottom: 14px;
|
||||||
|
padding-left: 12px;
|
||||||
|
margin-top: 12px;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user