add congrats when loyalty prize is available

This commit is contained in:
2025-10-21 16:18:21 +03:00
parent 6a6f92aefc
commit 778233acaa
5 changed files with 123 additions and 28 deletions

View File

@@ -133,6 +133,8 @@
"popular": "الأكثر مبيعاً" "popular": "الأكثر مبيعاً"
}, },
"claim": "إدخال", "claim": "إدخال",
"congratulations": "تهانينا!",
"loyaltyGiftEarned": "لقد حصلت على هدية ولاء!",
"required": "مطلوب", "required": "مطلوب",
"optional": "اختياري", "optional": "اختياري",
"pleaseSelectRequiredOptions": "يرجى اختيار جميع الخيارات المطلوبة قبل إضافة إلى السلة", "pleaseSelectRequiredOptions": "يرجى اختيار جميع الخيارات المطلوبة قبل إضافة إلى السلة",

View File

@@ -149,6 +149,8 @@
"popular": "Popular" "popular": "Popular"
}, },
"claim": "Claim", "claim": "Claim",
"congratulations": "Congratulations!",
"loyaltyGiftEarned": "You've earned a loyalty gift!",
"required": "Required", "required": "Required",
"optional": "Optional", "optional": "Optional",
"pleaseSelectRequiredOptions": "Please select all required options before adding to cart", "pleaseSelectRequiredOptions": "Please select all required options before adding to cart",

View File

@@ -7,14 +7,12 @@
} }
.loyaltyContainer { .loyaltyContainer {
height: 115px; background-color: var(--secondary-background);
background-color: #FFF;
border: none; border: none;
margin-bottom: 1rem; margin-bottom: 1rem;
} }
.loyaltyContainer :global(.ant-card-body) { .loyaltyContainer :global(.ant-card-body) {
height: 115px;
padding: 12px 16px !important; padding: 12px 16px !important;
border: none; border: none;
border-radius: 0px; border-radius: 0px;
@@ -22,7 +20,7 @@
.loyaltyCard { .loyaltyCard {
border-radius: 0px !important; border-radius: 0px !important;
border: none border: none;
} }
.presentIcon { .presentIcon {
@@ -60,3 +58,69 @@
:global(.rtl) .presentIconItem { :global(.rtl) .presentIconItem {
margin-right: 0px; margin-right: 0px;
} }
.congratulationsContainer {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
padding: 8px 12px;
background: linear-gradient(135deg, var(--primary), #fa0505);
border-radius: 8px;
animation: celebrate 0.6s ease-in-out;
}
.congratulationsIcon {
color: var(--secondary-background);
font-size: 18px;
animation: bounce 1s infinite;
}
.congratulationsText {
color: var(--secondary-background);
font-weight: 600;
font-size: 14px;
margin: 0;
}
.congratulationsSubtext {
color: var(--secondary-background);
font-weight: 400;
font-size: 12px;
margin: 0;
opacity: 0.9;
}
@keyframes celebrate {
0% {
transform: scale(0.8);
opacity: 0;
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
opacity: 1;
}
}
@keyframes bounce {
0%,
20%,
50%,
80%,
100% {
transform: translateY(0);
}
40% {
transform: translateY(-3px);
}
60% {
transform: translateY(-2px);
}
}
:global(.darkApp) .congratulationsContainer {
background: linear-gradient(135deg, var(--primary), #fa0505);
}

View File

@@ -10,10 +10,27 @@ import styles from "./LoyaltyCard.module.css";
const LoyaltyCard = () => { const LoyaltyCard = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { data: restaurant } = useGetRestaurantDetailsQuery("595"); const { data: restaurant } = useGetRestaurantDetailsQuery("595");
const isHasLoyaltyGift =
(restaurant?.loyalty_stamps ?? 0) -
(restaurant?.customer_loyalty_points ?? 0) ===
0;
return ( return (
<div className={styles.loyaltyContainer}> <div className={styles.loyaltyContainer}>
<Card className={styles.loyaltyCard}> <Card className={styles.loyaltyCard}>
{isHasLoyaltyGift && (
<div className={styles.congratulationsContainer}>
<PresentIcon className={styles.congratulationsIcon} />
<div>
<p className={styles.congratulationsText}>
{t("menu.congratulations")}
</p>
<p className={styles.congratulationsSubtext}>
{t("menu.loyaltyGiftEarned")}
</p>
</div>
</div>
)}
<Row <Row
justify="space-between" justify="space-between"
align="middle" align="middle"
@@ -53,25 +70,32 @@ const LoyaltyCard = () => {
<Col> <Col>
<div className={styles.presentIcon}> <div className={styles.presentIcon}>
<div style={{ display: "flex" }}> <div style={{ display: "flex" }}>
<Image {isHasLoyaltyGift ? (
className={styles.presentIconItem} <>
preview={false} <Image
width={32} className={styles.presentIconItem}
height={32} preview={false}
src={restaurant?.loyalty_stamp_image} width={32}
/> height={32}
<ProText src={restaurant?.loyalty_stamp_image}
type="secondary" />
strong <ProText
style={{ type="secondary"
fontSize: "1rem", strong
fontWeight: 400, style={{
position: "relative", fontSize: "1rem",
top: 3, fontWeight: 400,
}} position: "relative",
> top: 3,
x{restaurant?.loyalty_stamps} margin: "0 2px",
</ProText> }}
>
x
{(restaurant?.loyalty_stamps ?? 0) -
(restaurant?.customer_loyalty_points ?? 0)}
</ProText>{" "}
</>
) : null}
</div> </div>
</div> </div>
</Col> </Col>

View File

@@ -39,15 +39,13 @@ export default function CartMobileTabletLayout({
form, form,
}: CartMobileTabletLayoutProps) { }: CartMobileTabletLayoutProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const { items, collectionMethod } = useAppSelector(selectCart); const { items, collectionMethod, orderType } = useAppSelector(selectCart);
const { id } = useParams(); const { id } = useParams();
const { isMobile, isTablet } = useBreakPoint(); const { isMobile, isTablet } = useBreakPoint();
const getResponsiveClass = () => (isTablet ? "tablet" : "mobile"); const getResponsiveClass = () => (isTablet ? "tablet" : "mobile");
const orderType = localStorage.getItem("orderType");
const getMenuItemImageStyle = () => { const getMenuItemImageStyle = () => {
if (isMobile) { if (isMobile) {
return { return {
@@ -240,7 +238,12 @@ export default function CartMobileTabletLayout({
<Form.Item <Form.Item
name="collectionMethod" name="collectionMethod"
required required
rules={[{ required: true, message: t("cart.pleaseSelectCollectionMethod") }]} rules={[
{
required: true,
message: t("cart.pleaseSelectCollectionMethod"),
},
]}
> >
<ProRatioGroups <ProRatioGroups
options={[ options={[