enhance loyalty section UI
This commit is contained in:
@@ -92,7 +92,7 @@
|
||||
"scheduledOrder": "طلب مجدول"
|
||||
},
|
||||
"promotion": {
|
||||
"title": "الترويجات",
|
||||
"title": "عرض التفاصيل",
|
||||
"description": "احصل على خصم 10% على طلبك الأول"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
"scheduledOrder": "Scheduled Order"
|
||||
},
|
||||
"promotion": {
|
||||
"title": "Promotions",
|
||||
"title": "Show details",
|
||||
"description": "Get 10% off your first order"
|
||||
}
|
||||
},
|
||||
@@ -282,7 +282,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",
|
||||
|
||||
@@ -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,11 +87,43 @@ export default function OrderSummary() {
|
||||
<ProText type="secondary" style={titlesStyle}>
|
||||
{t("cart.discount")}
|
||||
</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
|
||||
price={discountAmount}
|
||||
style={{ ...titlesStyle, color: "#434E5C" }}
|
||||
textStyle={{ ...titlesStyle, color: "#434E5C" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{orderType !== OrderType.Redeem && (
|
||||
<div className={styles.summaryRow}>
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -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 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 && orderType !== OrderType.Gift && <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 && orderType !== OrderType.Gift && <RewardWaiterCard />}
|
||||
{orderType !== OrderType.Redeem && orderType !== OrderType.Gift && (
|
||||
<RewardWaiterCard />
|
||||
)}
|
||||
{orderType !== OrderType.Redeem && orderType !== OrderType.Gift && (
|
||||
<EarnLoyaltyPointsCard />
|
||||
)}
|
||||
<BriefMenuCard />
|
||||
<Ads1 />
|
||||
<OrderSummary />
|
||||
|
||||
@@ -7,8 +7,8 @@ import { useNavigate, useParams } from "react-router-dom";
|
||||
import styles from "./rewardsAndLoyalty.module.css";
|
||||
|
||||
import { OrderType } from "pages/checkout/hooks/types.ts";
|
||||
import { useAppSelector } from "redux/hooks";
|
||||
import { selectCart } from "features/order/orderSlice";
|
||||
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";
|
||||
@@ -19,6 +19,7 @@ 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();
|
||||
@@ -27,19 +28,17 @@ export default function RewardsAndLoyalityPage() {
|
||||
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),
|
||||
);
|
||||
|
||||
console.log(loyaltyHistory);
|
||||
|
||||
// Calculate percentage: (customer_loyalty_points / loyalty_stamps) * 100
|
||||
const progressPercent =
|
||||
loyaltyStamps > 0
|
||||
? Math.min((customerLoyaltyPoints / loyaltyStamps) * 100, 100)
|
||||
: 0;
|
||||
|
||||
const handleCheckout = () => {
|
||||
navigate(`/${subdomain}/menu?orderType=${OrderType.Redeem}`);
|
||||
const handleRedeem = () => {
|
||||
navigate(`/${subdomain}/menu?orderType=${OrderType.DineIn}`);
|
||||
dispatch(updateUseLoyaltyPoints(true));
|
||||
};
|
||||
|
||||
const currentStampRound = customerLoyaltyPoints % loyaltyStamps;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Layout>
|
||||
@@ -49,7 +48,7 @@ export default function RewardsAndLoyalityPage() {
|
||||
<Tooltip title="3 done / 3 in progress / 4 to do">
|
||||
<div style={{ margin: "47px 47px 20px 47px" }}>
|
||||
<Progress
|
||||
percent={70}
|
||||
percent={(currentStampRound / loyaltyStamps) * 100}
|
||||
format={() => (
|
||||
<div
|
||||
style={{
|
||||
@@ -70,9 +69,7 @@ export default function RewardsAndLoyalityPage() {
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
{Number(customerLoyaltyPoints / loyaltyStamps).toFixed(
|
||||
0,
|
||||
)}
|
||||
{currentStampRound} / {loyaltyStamps}
|
||||
</ProText>
|
||||
<ProText
|
||||
style={{
|
||||
@@ -332,7 +329,7 @@ export default function RewardsAndLoyalityPage() {
|
||||
type="primary"
|
||||
shape="round"
|
||||
className={styles.checkoutButton}
|
||||
onClick={handleCheckout}
|
||||
onClick={handleRedeem}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: 40,
|
||||
@@ -349,8 +346,8 @@ export default function RewardsAndLoyalityPage() {
|
||||
<ProInputCard title={t("rewardsAndLoyalty.loyaltyHistory")}>
|
||||
<Timeline
|
||||
items={
|
||||
loyaltyHistory && loyaltyHistory.length > 0
|
||||
? loyaltyHistory.map((item: any, index: number) => ({
|
||||
loyaltyHistories && loyaltyHistories.length > 0
|
||||
? loyaltyHistories.map((item: any, index: number) => ({
|
||||
content: (
|
||||
<div key={index}>
|
||||
{/* <ProText
|
||||
|
||||
@@ -39,7 +39,13 @@
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: var(--secondary-background);
|
||||
padding: 16px;
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user