redeem: initial commit
This commit is contained in:
@@ -23,6 +23,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { Variant } from "utils/types/appTypes";
|
||||
import DeleteIcon from "components/Icons/DeleteIcon";
|
||||
import PlusIcon from "components/Icons/PlusIcon";
|
||||
import { GiftItemsCard } from "pages/redeem/components/GiftItemsCard";
|
||||
|
||||
interface CartMobileTabletLayoutProps {
|
||||
form: FormInstance;
|
||||
@@ -66,7 +67,9 @@ export default function CartMobileTabletLayout({
|
||||
>
|
||||
{/* Table Number */}
|
||||
{(orderType === OrderType.DineIn ||
|
||||
orderType === OrderType.ToOffice) && <TableNumberCard />}
|
||||
orderType === OrderType.ToOffice) && <TableNumberCard />}
|
||||
|
||||
{orderType === OrderType.Redeem && <GiftItemsCard isCart={true} />}
|
||||
|
||||
<div className={`${styles.cartContent} ${getResponsiveClass()}`}>
|
||||
<Card className={styles.cartItem}>
|
||||
|
||||
@@ -17,7 +17,7 @@ export default function RewardWaiterCard() {
|
||||
const dispatch = useAppDispatch();
|
||||
const { tip } = useAppSelector(selectCart);
|
||||
const { isDesktop } = useBreakPoint();
|
||||
const [selectedTip, setSelectedTip] = useState<number | null>(null);
|
||||
const [selectedTip, setSelectedTip] = useState<number | null>(parseFloat(tip));
|
||||
|
||||
const [isTipOpen, setIsTipOpen] = useState(false);
|
||||
|
||||
|
||||
@@ -246,5 +246,6 @@ export enum OrderType {
|
||||
ToRoom = "room",
|
||||
ToOffice = "office",
|
||||
Booking = "booking",
|
||||
Pay = "pay"
|
||||
Pay = "pay",
|
||||
Redeem = "redeem"
|
||||
}
|
||||
|
||||
@@ -22,17 +22,25 @@ import { useEffect } from "react";
|
||||
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";
|
||||
|
||||
export default function CheckoutPage() {
|
||||
const { t } = useTranslation();
|
||||
const [form] = Form.useForm();
|
||||
const { phone, order, orderType, collectionMethod, coupon, customerName } =
|
||||
useAppSelector(selectCart);
|
||||
const {
|
||||
phone,
|
||||
order,
|
||||
orderType,
|
||||
collectionMethod,
|
||||
coupon,
|
||||
customerName,
|
||||
tip,
|
||||
} = useAppSelector(selectCart);
|
||||
const { token } = useAppSelector((state) => state.auth);
|
||||
const dispatch = useAppDispatch();
|
||||
useEffect(() => {
|
||||
form.setFieldsValue({ coupon, collectionMethod, phone, customerName });
|
||||
}, [form, phone, coupon, collectionMethod, customerName]);
|
||||
form.setFieldsValue({ coupon, collectionMethod, phone, customerName, tip });
|
||||
}, [form, phone, coupon, collectionMethod, customerName, tip]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -71,12 +79,13 @@ export default function CheckoutPage() {
|
||||
value={order?.officeNumber}
|
||||
/>
|
||||
)}
|
||||
{orderType === OrderType.Redeem && <VoucherSummary />}
|
||||
{/* {orderType === OrderType.Gift && <GiftCard />} */}
|
||||
{/* <RoomDetails />
|
||||
<OfficeDetails /> */}
|
||||
{/* <GiftDetails /> */}
|
||||
{/* <BriefMenu /> */}
|
||||
<CouponCard />
|
||||
{orderType !== OrderType.Redeem && <CouponCard />}
|
||||
|
||||
{/* Collection Method */}
|
||||
{orderType === OrderType.Pickup && (
|
||||
@@ -114,7 +123,7 @@ export default function CheckoutPage() {
|
||||
)}
|
||||
|
||||
{/* Reward Your Waiter */}
|
||||
<RewardWaiterCard />
|
||||
{orderType !== OrderType.Redeem && <RewardWaiterCard />}
|
||||
<BriefMenuCard />
|
||||
<Ads1 />
|
||||
<OrderSummary />
|
||||
|
||||
@@ -483,9 +483,6 @@
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
top: 70px;
|
||||
opacity: 0.9;
|
||||
background: #aaa8a833;
|
||||
backdrop-filter: blur(40px);
|
||||
}
|
||||
|
||||
.backButtonContainer {
|
||||
@@ -567,7 +564,7 @@
|
||||
|
||||
.ratingScore {
|
||||
position: relative;
|
||||
top:6px;
|
||||
top: 6px;
|
||||
font-family: Roboto;
|
||||
font-weight: 600;
|
||||
font-style: SemiBold;
|
||||
@@ -802,3 +799,48 @@
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.frame {
|
||||
align-items: flex-start;
|
||||
background-color: #aaa7a733;
|
||||
border-radius: 60px;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 8px 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.div {
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
gap: 4px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pickup {
|
||||
color: #ffffff;
|
||||
font-family: "Roboto-Medium", Helvetica;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0;
|
||||
line-height: normal;
|
||||
margin-top: -1px;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.elementMin {
|
||||
color: var(--greylight-hover);
|
||||
font-family: "Roboto-Regular", Helvetica;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0;
|
||||
line-height: normal;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
@@ -96,21 +96,31 @@ function MenuPage() {
|
||||
<div
|
||||
className={`${styles.headerFloatingBtn} ${styles.orderTypeSelectContainer} order-type-select-container`}
|
||||
>
|
||||
<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}
|
||||
/>
|
||||
{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}
|
||||
/>
|
||||
)}
|
||||
{orderType === OrderType.Redeem && (
|
||||
<div className={styles.frame}>
|
||||
<div className={styles.div}>
|
||||
<div className={styles.pickup}>Balance</div>
|
||||
<div className={styles.elementMin}>60 OMR</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<SearchButton />
|
||||
</div>
|
||||
|
||||
@@ -3,11 +3,9 @@ import { useGetOrderDetailsQuery } from "redux/api/others";
|
||||
import { useAppSelector } from "redux/hooks";
|
||||
import styles from "./OrderDetails.module.css";
|
||||
import ProHeader from "components/ProHeader/ProHeader";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ProText from "components/ProText";
|
||||
import useBreakPoint from "hooks/useBreakPoint";
|
||||
import ArabicPrice from "components/ArabicPrice";
|
||||
import ImageWithFallback from "components/ImageWithFallback";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
@@ -16,6 +14,7 @@ export default function OrderDetails() {
|
||||
const { t } = useTranslation();
|
||||
const { isRTL } = useAppSelector((state) => state.locale);
|
||||
const { isMobile, isTablet } = useBreakPoint();
|
||||
|
||||
const { data: orderDetails } = useGetOrderDetailsQuery(
|
||||
{
|
||||
orderID: orderId || "",
|
||||
@@ -25,6 +24,7 @@ export default function OrderDetails() {
|
||||
skip: !orderId,
|
||||
},
|
||||
);
|
||||
|
||||
const getMenuItemImageStyle = () => {
|
||||
if (isMobile) {
|
||||
return {
|
||||
@@ -86,7 +86,6 @@ export default function OrderDetails() {
|
||||
<br />
|
||||
<ProText
|
||||
type="secondary"
|
||||
className={`${styles.itemDescription} responsive-text`}
|
||||
style={{
|
||||
margin: 0,
|
||||
lineClamp: 1,
|
||||
@@ -135,7 +134,9 @@ export default function OrderDetails() {
|
||||
border: "none",
|
||||
}}
|
||||
>
|
||||
<ProText style={{color: "#1F1C2E"}}>{item.qty} </ProText>
|
||||
<ProText style={{ color: "#1F1C2E" }}>
|
||||
{item.qty}{" "}
|
||||
</ProText>
|
||||
</Button>
|
||||
</div>
|
||||
</Space>
|
||||
|
||||
77
src/pages/redeem/components/GiftItemsCard.module.css
Normal file
77
src/pages/redeem/components/GiftItemsCard.module.css
Normal file
@@ -0,0 +1,77 @@
|
||||
.floatingContainer {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
.floatingPresent {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
animation: float 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.floatingShadow {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 50%;
|
||||
width: 80px;
|
||||
height: 20px;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 50%;
|
||||
filter: blur(6px);
|
||||
z-index: 1;
|
||||
transform-origin: center;
|
||||
transform: translateX(-50%);
|
||||
animation: shadowPulse 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-15px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shadowPulse {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateX(-50%) scale(1);
|
||||
opacity: 0.3;
|
||||
}
|
||||
50% {
|
||||
transform: translateX(-50%) scale(0.6);
|
||||
opacity: 0.15;
|
||||
}
|
||||
}
|
||||
|
||||
.orderNotes {
|
||||
gap: 20px;
|
||||
opacity: 1;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.menuItemImage {
|
||||
object-fit: cover;
|
||||
border-radius: 8px;
|
||||
transition: transform 0.3s ease;
|
||||
width: 90px;
|
||||
height: 80px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.backIcon {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
.nextIcon {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
328
src/pages/redeem/components/GiftItemsCard.tsx
Normal file
328
src/pages/redeem/components/GiftItemsCard.tsx
Normal file
@@ -0,0 +1,328 @@
|
||||
import { Button, Divider, Space, Switch, Tag, Skeleton } from "antd";
|
||||
import ProInputCard from "components/ProInputCard/ProInputCard";
|
||||
import ProText from "components/ProText";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import styles from "./GiftItemsCard.module.css";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useGetOrderDetailsQuery } from "redux/api/others";
|
||||
import ImageWithFallback from "components/ImageWithFallback";
|
||||
import { useAppSelector } from "redux/hooks";
|
||||
import useBreakPoint from "hooks/useBreakPoint";
|
||||
import GiftIcon from "components/Icons/GiftIcon";
|
||||
import NextIcon from "components/Icons/NextIcon";
|
||||
import BackIcon from "components/Icons/BackIcon";
|
||||
|
||||
export function GiftItemsCard({ isCart = false }: { isCart?: boolean }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { voucherId } = useParams();
|
||||
const { data: orderDetails, isLoading } = useGetOrderDetailsQuery(
|
||||
{
|
||||
orderID: voucherId || "5711385",
|
||||
restaurantID: localStorage.getItem("restaurantID") || "",
|
||||
},
|
||||
// {
|
||||
// skip: !voucherId,
|
||||
// },
|
||||
);
|
||||
const { isRTL } = useAppSelector((state) => state.locale);
|
||||
const { isMobile, isTablet } = useBreakPoint();
|
||||
const getMenuItemImageStyle = () => {
|
||||
if (isMobile) {
|
||||
return {
|
||||
width: 72,
|
||||
height: 72,
|
||||
};
|
||||
}
|
||||
return {
|
||||
width: 120,
|
||||
height: 120,
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProInputCard
|
||||
title={t("redeem.giftedItems")}
|
||||
titleRight={
|
||||
<>
|
||||
{!isCart && (
|
||||
<Tag
|
||||
style={{
|
||||
height: 23,
|
||||
textAlign: "center",
|
||||
opacity: 1,
|
||||
paddingRight: 10,
|
||||
paddingLeft: 10,
|
||||
borderRadius: 100,
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 12,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
cursor: "pointer",
|
||||
backgroundColor: "#FFF9E6",
|
||||
color: "#B58D00",
|
||||
}}
|
||||
>
|
||||
{t("redeem.pending")}
|
||||
</Tag>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
>
|
||||
{!isCart && (
|
||||
<>
|
||||
<div className={styles.orderNotes}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 7,
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#333333",
|
||||
}}
|
||||
>
|
||||
{t("redeem.redeemGiftedItems")}
|
||||
</ProText>
|
||||
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 12,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#777580",
|
||||
}}
|
||||
>
|
||||
{t("redeem.includesFreeItemsInThisOrder")}
|
||||
</ProText>
|
||||
</div>
|
||||
<Switch />
|
||||
</div>
|
||||
|
||||
<Divider style={{ margin: "16px 0" }} />
|
||||
</>
|
||||
)}
|
||||
|
||||
{isLoading ? (
|
||||
// Skeleton loading state
|
||||
<>
|
||||
{[1, 2].map((skeletonIndex) => (
|
||||
<div key={skeletonIndex} style={{ position: "relative" }}>
|
||||
<Space
|
||||
size="middle"
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
height: "100%",
|
||||
}}
|
||||
>
|
||||
<Space orientation="vertical" size="small">
|
||||
<div>
|
||||
<Skeleton.Input
|
||||
active
|
||||
style={{
|
||||
width: isMobile ? 150 : 200,
|
||||
height: 20,
|
||||
marginBottom: 8,
|
||||
}}
|
||||
/>
|
||||
<Skeleton.Input
|
||||
active
|
||||
style={{
|
||||
width: isMobile ? 120 : 180,
|
||||
height: 16,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Skeleton.Button
|
||||
active
|
||||
style={{
|
||||
width: isMobile ? 80 : 100,
|
||||
height: 21,
|
||||
}}
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
</Space>
|
||||
<div style={{ position: "relative" }}>
|
||||
<Skeleton.Image
|
||||
active
|
||||
style={{
|
||||
width: getMenuItemImageStyle().width,
|
||||
height: getMenuItemImageStyle().height,
|
||||
borderRadius: 8,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Space>
|
||||
{skeletonIndex !== 3 && (
|
||||
<Divider style={{ margin: "16px 0" }} />
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
orderDetails?.orderItems?.map((item: any, index: number) => (
|
||||
<div key={index} style={{ position: "relative" }}>
|
||||
<Space
|
||||
size="middle"
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
height: "100%",
|
||||
}}
|
||||
>
|
||||
<Space orientation="vertical" size="small">
|
||||
<div>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 600,
|
||||
fontStyle: "SemiBold",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#333333",
|
||||
}}
|
||||
>
|
||||
{item.name}
|
||||
<span
|
||||
style={{
|
||||
fontWeight: 400,
|
||||
}}
|
||||
>
|
||||
{/* {isRTL
|
||||
? (item.variant as Variant)?.optionsAR?.[0]?.value
|
||||
: (item.variant as Variant)?.options?.[0]?.value} */}
|
||||
</span>
|
||||
</ProText>
|
||||
<br />
|
||||
<ProText
|
||||
className={`${styles.itemDescription} responsive-text`}
|
||||
style={{
|
||||
margin: 0,
|
||||
lineClamp: 1,
|
||||
padding: isMobile ? "3px 0" : isTablet ? 8 : 10,
|
||||
fontSize: isMobile ? 12 : isTablet ? 18 : 20,
|
||||
display: "-webkit-box",
|
||||
WebkitBoxOrient: "vertical",
|
||||
WebkitLineClamp: 1,
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
wordWrap: "break-word",
|
||||
overflowWrap: "break-word",
|
||||
lineHeight: "140%",
|
||||
maxHeight: isMobile ? "3em" : isTablet ? "5em" : "7em",
|
||||
width: "55%",
|
||||
fontWeight: 400,
|
||||
fontStyle: "Regular",
|
||||
letterSpacing: "0%",
|
||||
color: "#777580",
|
||||
}}
|
||||
>
|
||||
{item.name}
|
||||
</ProText>
|
||||
</div>
|
||||
<div>
|
||||
<Button
|
||||
iconPlacement="start"
|
||||
size="small"
|
||||
style={{
|
||||
background: "#F5F5F6",
|
||||
height: 21,
|
||||
border: "none",
|
||||
borderRadius: 888,
|
||||
}}
|
||||
>
|
||||
<GiftIcon />
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 12,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
textAlign: "right",
|
||||
color: "#7950E6",
|
||||
padding: "2px 8px 2px 0",
|
||||
}}
|
||||
>
|
||||
Gift x {item.qty}
|
||||
</ProText>
|
||||
</Button>
|
||||
</div>
|
||||
</Space>
|
||||
<div style={{ position: "relative" }}>
|
||||
<ImageWithFallback
|
||||
src={item.image}
|
||||
alt={item.name}
|
||||
className={`${styles.menuItemImage} responsive-image`}
|
||||
{...getMenuItemImageStyle()}
|
||||
fallbackSrc={
|
||||
"https://fascano-space.s3.me-central-1.amazonaws.com/uploads/restorants/685a8fc884a8c_large.jpg"
|
||||
}
|
||||
style={{
|
||||
width: 72,
|
||||
height: 72,
|
||||
borderRadius: 8,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Space>
|
||||
|
||||
{index !== orderDetails?.orderItems?.length - 1 && (
|
||||
<Divider style={{ margin: "16px 0" }} />
|
||||
)}
|
||||
</div>
|
||||
)) || null
|
||||
)}
|
||||
|
||||
{!isCart && (
|
||||
<>
|
||||
<Divider style={{ margin: "16px 0" }} />
|
||||
|
||||
<Button
|
||||
style={{
|
||||
height: 48,
|
||||
borderRadius: 888,
|
||||
gap: 16,
|
||||
opacity: 1,
|
||||
borderWidth: 1,
|
||||
paddingTop: 8,
|
||||
paddingRight: 32,
|
||||
paddingBottom: 8,
|
||||
paddingLeft: 32,
|
||||
width: "100%",
|
||||
color: "#4C4A58",
|
||||
}}
|
||||
icon={
|
||||
isRTL ? (
|
||||
<BackIcon className={styles.backIcon} iconColor="#FFC600" />
|
||||
) : (
|
||||
<NextIcon className={styles.nextIcon} iconColor="#FFC600" />
|
||||
)
|
||||
}
|
||||
iconPlacement={isRTL ? "start" : "end"}
|
||||
>
|
||||
{t("redeem.viewAll")}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</ProInputCard>
|
||||
</>
|
||||
);
|
||||
}
|
||||
58
src/pages/redeem/components/LocationCard.module.css
Normal file
58
src/pages/redeem/components/LocationCard.module.css
Normal file
@@ -0,0 +1,58 @@
|
||||
.floatingContainer {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
.floatingPresent {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
animation: float 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.floatingShadow {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 50%;
|
||||
width: 80px;
|
||||
height: 20px;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 50%;
|
||||
filter: blur(6px);
|
||||
z-index: 1;
|
||||
transform-origin: center;
|
||||
transform: translateX(-50%);
|
||||
animation: shadowPulse 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-15px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shadowPulse {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateX(-50%) scale(1);
|
||||
opacity: 0.3;
|
||||
}
|
||||
50% {
|
||||
transform: translateX(-50%) scale(0.6);
|
||||
opacity: 0.15;
|
||||
}
|
||||
}
|
||||
|
||||
.orderNotes {
|
||||
gap: 20px;
|
||||
opacity: 1;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
94
src/pages/redeem/components/LocationCard.tsx
Normal file
94
src/pages/redeem/components/LocationCard.tsx
Normal file
@@ -0,0 +1,94 @@
|
||||
import { Divider, Tag } from "antd";
|
||||
import ProInputCard from "components/ProInputCard/ProInputCard";
|
||||
import ProText from "components/ProText";
|
||||
import { selectCart } from "features/order/orderSlice";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAppSelector } from "redux/hooks";
|
||||
import styles from "./LocationCard.module.css";
|
||||
import { GoogleMap } from "components/CustomBottomSheet/GoogleMap";
|
||||
import DirectionsIcon from "components/Icons/DirectionsIcon";
|
||||
|
||||
export function LocationCard() {
|
||||
const { t } = useTranslation();
|
||||
const { restaurant } = useAppSelector(selectCart);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProInputCard title={t("redeem.restaurantLocation")}>
|
||||
<div className={styles.mapContainer}>
|
||||
<GoogleMap
|
||||
readOnly={true}
|
||||
initialLocation={{
|
||||
lat: parseFloat(restaurant.lat || "0"),
|
||||
lng: parseFloat(restaurant.lng || "0"),
|
||||
address: "",
|
||||
}}
|
||||
height="160px"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Divider style={{ margin: "16px 0" }} />
|
||||
|
||||
<div className={styles.orderNotes}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 4,
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#333333",
|
||||
}}
|
||||
>
|
||||
{restaurant.restautantName}
|
||||
</ProText>
|
||||
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#777580",
|
||||
}}
|
||||
>
|
||||
{restaurant.address}
|
||||
</ProText>
|
||||
</div>
|
||||
<Tag
|
||||
style={{
|
||||
backgroundColor: "#FFF9E6",
|
||||
color: "#E8B400",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 4,
|
||||
}}
|
||||
>
|
||||
<DirectionsIcon />
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#E8B400",
|
||||
}}
|
||||
>
|
||||
{t("redeem.getDirections")}
|
||||
</ProText>
|
||||
</Tag>
|
||||
</div>
|
||||
</ProInputCard>
|
||||
</>
|
||||
);
|
||||
}
|
||||
58
src/pages/redeem/components/VoucherBalanceCard.module.css
Normal file
58
src/pages/redeem/components/VoucherBalanceCard.module.css
Normal file
@@ -0,0 +1,58 @@
|
||||
.floatingContainer {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
.floatingPresent {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
animation: float 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.floatingShadow {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 50%;
|
||||
width: 80px;
|
||||
height: 20px;
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 50%;
|
||||
filter: blur(6px);
|
||||
z-index: 1;
|
||||
transform-origin: center;
|
||||
transform: translateX(-50%);
|
||||
animation: shadowPulse 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-15px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shadowPulse {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateX(-50%) scale(1);
|
||||
opacity: 0.3;
|
||||
}
|
||||
50% {
|
||||
transform: translateX(-50%) scale(0.6);
|
||||
opacity: 0.15;
|
||||
}
|
||||
}
|
||||
|
||||
.orderNotes {
|
||||
gap: 20px;
|
||||
opacity: 1;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
124
src/pages/redeem/components/VoucherBalanceCard.tsx
Normal file
124
src/pages/redeem/components/VoucherBalanceCard.tsx
Normal file
@@ -0,0 +1,124 @@
|
||||
import { Divider, Switch, Tag } from "antd";
|
||||
import ProInputCard from "components/ProInputCard/ProInputCard";
|
||||
import ProText from "components/ProText";
|
||||
import { selectCart } from "features/order/orderSlice";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAppSelector } from "redux/hooks";
|
||||
import styles from "./VoucherBalanceCard.module.css";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import CardAmountIcon from "components/Icons/CardAmountIcon";
|
||||
import ArabicPrice from "components/ArabicPrice";
|
||||
|
||||
export function VoucherBalanceCard() {
|
||||
const { t } = useTranslation();
|
||||
const { giftDetails } = useAppSelector(selectCart);
|
||||
|
||||
const navigate = useNavigate();
|
||||
const { subdomain } = useParams();
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProInputCard
|
||||
title={t("redeem.voucherBalance")}
|
||||
titleRight={
|
||||
<>
|
||||
<Tag
|
||||
style={{
|
||||
height: 23,
|
||||
textAlign: "center",
|
||||
opacity: 1,
|
||||
paddingRight: 10,
|
||||
paddingLeft: 10,
|
||||
borderRadius: 100,
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 12,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
cursor: "pointer",
|
||||
backgroundColor: "#FFF9E6",
|
||||
color: "#B58D00",
|
||||
}}
|
||||
>
|
||||
{t("redeem.pending")}
|
||||
</Tag>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<div className={styles.orderNotes}>
|
||||
<div
|
||||
style={{
|
||||
height: 42,
|
||||
width: 64,
|
||||
backgroundColor: "var(--background)",
|
||||
borderRadius: 8,
|
||||
}}
|
||||
>
|
||||
<CardAmountIcon />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 4,
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#777580",
|
||||
}}
|
||||
>
|
||||
{t("redeem.yourGiftCardBalance")}
|
||||
</ProText>
|
||||
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#333333",
|
||||
}}
|
||||
>
|
||||
<ArabicPrice price={giftDetails?.amount || 0} />
|
||||
</ProText>
|
||||
</div>
|
||||
<Switch />
|
||||
</div>
|
||||
|
||||
<Divider style={{ margin: "10px 0" }} />
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
onClick={() => {
|
||||
navigate(`/${subdomain}/cart`);
|
||||
}}
|
||||
>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 400,
|
||||
fontStyle: "Regular",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#777580",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
{t("redeem.voucherWillBeAppliedAtCheckout")}
|
||||
</ProText>
|
||||
</div>
|
||||
</ProInputCard>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
.voucherSummary :global(.ant-card-body) {
|
||||
padding: 16px !important;
|
||||
}
|
||||
|
||||
.voucherSummary {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.summaryRow {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.summaryDivider {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.totalRow {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.desktopOrderSummary {
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.desktopSummaryRow {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.desktopTotalRow {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px 0;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
/* Enhanced responsive focus states */
|
||||
.voucherSummary:focus {
|
||||
outline: 2px solid var(--primary);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Enhanced responsive animations */
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== MEDIA QUERIES ===== */
|
||||
|
||||
/* Tablet styles (769px - 1024px) */
|
||||
@media (min-width: 769px) and (max-width: 1024px) {
|
||||
.summaryRow {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.summaryDivider {
|
||||
margin: 10px 0 !important;
|
||||
}
|
||||
|
||||
.totalRow {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Desktop styles (1025px+) */
|
||||
@media (min-width: 1025px) {
|
||||
.summaryRow {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.summaryDivider {
|
||||
margin: 10px 0 !important;
|
||||
}
|
||||
|
||||
.totalRow {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Focus states for larger screens */
|
||||
@media (min-width: 768px) {
|
||||
.voucherSummary:focus {
|
||||
outline-offset: 4px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import { Card, Checkbox, Divider, Space } from "antd";
|
||||
import ArabicPrice from "components/ArabicPrice";
|
||||
import {
|
||||
selectCart,
|
||||
selectCartTotal,
|
||||
selectGrandTotal,
|
||||
} from "features/order/orderSlice";
|
||||
import { OrderType } from "pages/checkout/hooks/types";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useGetRestaurantDetailsQuery } from "redux/api/others";
|
||||
import { useAppSelector } from "redux/hooks";
|
||||
import ProText from "components/ProText";
|
||||
import ProTitle from "components/ProTitle";
|
||||
import styles from "./VoucherSummary.module.css";
|
||||
import { CSSProperties } from "react";
|
||||
|
||||
export default function VoucherSummary() {
|
||||
const { t } = useTranslation();
|
||||
const { subdomain } = useParams();
|
||||
const { data: restaurant } = useGetRestaurantDetailsQuery(subdomain);
|
||||
const subtotal = useAppSelector(selectCartTotal);
|
||||
const grandTotal = useAppSelector(selectGrandTotal);
|
||||
|
||||
const titlesStyle: CSSProperties = {
|
||||
fontWeight: 400,
|
||||
fontStyle: "Regular",
|
||||
fontSize: 12,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
textAlign: "center",
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card className={`${styles.voucherSummary}`}>
|
||||
<ProTitle
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
fontSize: 18,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#333333",
|
||||
}}
|
||||
>
|
||||
{t("cart.voucherSummary")}
|
||||
</ProTitle>
|
||||
<Divider style={{ margin: "15px 0 15px 0" }} />
|
||||
<Space orientation="vertical" style={{ width: "100%", gap: 16 }}>
|
||||
<div className={styles.summaryRow}>
|
||||
<ProText type="secondary" style={titlesStyle}>
|
||||
{t("cart.voucherBalance")}
|
||||
</ProText>
|
||||
<ArabicPrice price={subtotal} textStyle={titlesStyle} />
|
||||
</div>
|
||||
<div className={styles.summaryRow}>
|
||||
<ProText type="secondary" style={titlesStyle}>
|
||||
{t("cart.voucherApplied")}
|
||||
</ProText>
|
||||
<ArabicPrice
|
||||
price={Number(restaurant?.delivery_fees || 0)}
|
||||
textStyle={{ ...titlesStyle, color: "#434E5C" }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={`${styles.summaryRow} ${styles.totalRow}`}>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 600,
|
||||
fontStyle: "SemiBold",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
textAlign: "center",
|
||||
color: "#333333",
|
||||
}}
|
||||
>
|
||||
{t("cart.remainingVoucherAmount")}
|
||||
</ProText>
|
||||
<ArabicPrice
|
||||
price={grandTotal}
|
||||
textStyle={{ ...titlesStyle, color: "#434E5C" }}
|
||||
/>
|
||||
</div>
|
||||
</Space>
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,16 +1,7 @@
|
||||
import { Button, Card, Divider, Image } from "antd";
|
||||
import Ads2 from "components/Ads/Ads2";
|
||||
import { CancelOrderBottomSheet } from "components/CustomBottomSheet/CancelOrderBottomSheet";
|
||||
import LocationIcon from "components/Icons/LocationIcon";
|
||||
import InvoiceIcon from "components/Icons/order/InvoiceIcon";
|
||||
import TimeIcon from "components/Icons/order/TimeIcon";
|
||||
import OrderDishIcon from "components/Icons/OrderDishIcon";
|
||||
import PaymentDetails from "components/PaymentDetails/PaymentDetails";
|
||||
import { Button, Card, Image, Layout, Skeleton } from "antd";
|
||||
|
||||
import ProHeader from "components/ProHeader/ProHeader";
|
||||
import ProInputCard from "components/ProInputCard/ProInputCard";
|
||||
import ProText from "components/ProText";
|
||||
import ProTitle from "components/ProTitle";
|
||||
import dayjs from "dayjs";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
@@ -18,31 +9,30 @@ import {
|
||||
useGetOrderDetailsQuery,
|
||||
useGetRestaurantDetailsQuery,
|
||||
} from "redux/api/others";
|
||||
import { useAppSelector } from "redux/hooks";
|
||||
import styles from "./redeem.module.css";
|
||||
import BackIcon from "components/Icons/BackIcon";
|
||||
import NextIcon from "components/Icons/NextIcon";
|
||||
import { RateBottomSheet } from "components/CustomBottomSheet/RateBottomSheet";
|
||||
import Stepper from "pages/order/components/Stepper";
|
||||
import QRIcon from "components/Icons/QRIcon";
|
||||
import CopyIcon from "components/Icons/CopyIcon";
|
||||
import { useAppSelector } from "redux/hooks";
|
||||
import { LocationCard } from "./components/LocationCard.tsx";
|
||||
import { GiftItemsCard } from "./components/GiftItemsCard.tsx";
|
||||
import { VoucherBalanceCard } from "./components/VoucherBalanceCard.tsx";
|
||||
import { OrderType } from "pages/checkout/hooks/types.ts";
|
||||
|
||||
export default function RedeemPage() {
|
||||
const { t } = useTranslation();
|
||||
const { orderId } = useParams();
|
||||
const { isRTL } = useAppSelector((state) => state.locale);
|
||||
const { voucherId } = useParams();
|
||||
const { restaurant } = useAppSelector((state) => state.order);
|
||||
const navigate = useNavigate();
|
||||
const hasRefetchedRef = useRef(false);
|
||||
const navigate = useNavigate();
|
||||
const { subdomain } = useParams();
|
||||
|
||||
const { data: orderDetails } = useGetOrderDetailsQuery(
|
||||
const { data: orderDetails, isLoading } = useGetOrderDetailsQuery(
|
||||
{
|
||||
orderID: orderId || "",
|
||||
orderID: voucherId || "",
|
||||
restaurantID: localStorage.getItem("restaurantID") || "",
|
||||
},
|
||||
{
|
||||
skip: !orderId,
|
||||
// return it t0 60000 after finish testing
|
||||
pollingInterval: 10000,
|
||||
refetchOnMountOrArgChange: true,
|
||||
skip: !voucherId,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -58,7 +48,7 @@ export default function RedeemPage() {
|
||||
// Reset refetch flag when orderId changes
|
||||
useEffect(() => {
|
||||
hasRefetchedRef.current = false;
|
||||
}, [orderId]);
|
||||
}, [voucherId]);
|
||||
|
||||
// Refetch restaurant details when order status has alias "closed"
|
||||
useEffect(() => {
|
||||
@@ -74,190 +64,225 @@ export default function RedeemPage() {
|
||||
}
|
||||
}, [orderDetails?.status, restaurantSubdomain, refetchRestaurantDetails]);
|
||||
|
||||
const handleCheckout = () => {
|
||||
navigate(`/${subdomain}/menu?orderType=${OrderType.Redeem}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProHeader>{t("order.title")}</ProHeader>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
height: "92vh",
|
||||
padding: 16,
|
||||
gap: 16,
|
||||
overflow: "auto",
|
||||
scrollbarWidth: "none",
|
||||
}}
|
||||
>
|
||||
<Card className={styles.orderCard}>
|
||||
<Layout>
|
||||
<ProHeader>{t("redeem.title")}</ProHeader>
|
||||
<Layout.Content className={styles.redeemContainer}>
|
||||
<div
|
||||
style={{
|
||||
textAlign: "center",
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
gap: "1rem",
|
||||
backgroundColor: "rgba(255, 183, 0, 0.08)",
|
||||
borderRadius: "12px",
|
||||
padding: 16,
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
margin: "32px 28px 21px 28px",
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
type="text"
|
||||
shape="circle"
|
||||
style={{
|
||||
backgroundColor: "rgba(255, 183, 0, 0.08)",
|
||||
}}
|
||||
<ProText
|
||||
style={{ fontSize: 16, fontWeight: 600, color: "#333333" }}
|
||||
>
|
||||
<Image
|
||||
src={orderDetails?.restaurant_iimage}
|
||||
className={styles.profileImage}
|
||||
width={50}
|
||||
height={50}
|
||||
preview={false}
|
||||
/>
|
||||
</Button>
|
||||
<div>
|
||||
<ProText style={{ fontSize: "1rem" }}>
|
||||
{t("order.yourOrderFromFascanoRestaurant")}
|
||||
</ProText>
|
||||
<br />
|
||||
<ProText type="secondary">
|
||||
<LocationIcon className={styles.locationIcon} />{" "}
|
||||
{isRTL ? orderDetails?.restaurantAR : orderDetails?.restaurant}
|
||||
</ProText>
|
||||
</div>
|
||||
{t("redeem.addGiftDetails")}
|
||||
</ProText>
|
||||
<ProText
|
||||
style={{ fontSize: 14, fontWeight: 400, color: "#95949C" }}
|
||||
>
|
||||
{t("redeem.description")}
|
||||
</ProText>
|
||||
</div>
|
||||
|
||||
<OrderDishIcon className={styles.orderDishIcon} />
|
||||
{isLoading || !orderDetails?.restaurant_iimage ? (
|
||||
<div className={styles.carouselContainer}>
|
||||
<div className={styles.cardWrapper}>
|
||||
<Skeleton.Image
|
||||
active
|
||||
style={{
|
||||
width: 205,
|
||||
height: 134,
|
||||
borderRadius: 8,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className={styles.carouselContainer}>
|
||||
<div className={styles.cardWrapper}>
|
||||
<Image
|
||||
src={orderDetails?.restaurant_iimage}
|
||||
width={205}
|
||||
height={134}
|
||||
className={styles.cardImage}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<ProTitle
|
||||
level={5}
|
||||
<div
|
||||
style={{
|
||||
textAlign: "center",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
margin: "18px 28px 26px 28px",
|
||||
gap: 12,
|
||||
}}
|
||||
>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 400,
|
||||
fontStyle: "Regular",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
textAlign: "center",
|
||||
color: "#95949C",
|
||||
}}
|
||||
>
|
||||
{t("redeem.description")}
|
||||
</ProText>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 600,
|
||||
fontSize: "18px",
|
||||
marginBottom: "0.75rem",
|
||||
fontStyle: "SemiBold",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
textAlign: "center",
|
||||
color: "#333333",
|
||||
}}
|
||||
>
|
||||
{t("order.inProgressOrder")} (1)
|
||||
</ProTitle>
|
||||
<div style={{ display: "flex", flexDirection: "row", gap: 8 }}>
|
||||
<InvoiceIcon className={styles.invoiceIcon} />
|
||||
<ProText type="secondary" style={{ fontSize: "14px" }}>
|
||||
#{orderDetails?.order.id}
|
||||
</ProText>
|
||||
<TimeIcon className={styles.timeIcon} />
|
||||
<ProText type="secondary" style={{ fontSize: "14px" }}>
|
||||
ordered :- Today -{" "}
|
||||
{dayjs(orderDetails?.status[0]?.pivot?.created_at).format(
|
||||
"h:mm A",
|
||||
)}
|
||||
</ProText>
|
||||
</div>
|
||||
|
||||
<Divider style={{ margin: "12px 0" }} />
|
||||
|
||||
<Stepper statuses={orderDetails?.status} />
|
||||
{t("redeem.addGiftDetails")}
|
||||
</ProText>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Ads2 />
|
||||
|
||||
<ProInputCard
|
||||
title={
|
||||
<div style={{ marginBottom: 7 }}>
|
||||
<ProText style={{ fontSize: "1rem" }}>
|
||||
{t("order.yourOrderFrom")}
|
||||
</ProText>
|
||||
<br />
|
||||
<ProText type="secondary">
|
||||
<LocationIcon className={styles.locationIcon} />{" "}
|
||||
{t("order.muscat")}
|
||||
</ProText>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div
|
||||
style={{ display: "flex", flexDirection: "column", gap: "1rem" }}
|
||||
>
|
||||
{orderDetails?.orderItems.map((item, index) => (
|
||||
<div key={item.id}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "flex-start",
|
||||
gap: "1rem",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
type="text"
|
||||
shape="circle"
|
||||
style={{
|
||||
backgroundColor: "rgba(255, 183, 0, 0.08)",
|
||||
}}
|
||||
>
|
||||
{index + 1}X
|
||||
</Button>
|
||||
<div>
|
||||
<ProText
|
||||
style={{ fontSize: "1rem", position: "relative", top: 8 }}
|
||||
>
|
||||
{item.name}
|
||||
</ProText>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ProInputCard>
|
||||
|
||||
<PaymentDetails order={orderDetails?.order} />
|
||||
|
||||
<Card
|
||||
className={styles.backToHomePage}
|
||||
onClick={() => navigate(`/${restaurant?.subdomain}`)}
|
||||
>
|
||||
<div
|
||||
<Card
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
marginTop: 1,
|
||||
borderRadius: 0,
|
||||
borderTopRightRadius: 16,
|
||||
borderTopLeftRadius: 16,
|
||||
border: "1px solid transparent",
|
||||
borderImageSource:
|
||||
"radial-gradient(38.92% 103.83% at 49.85% -3.83%, #FFB700 0%, rgba(255, 233, 179, 0) 100%)",
|
||||
borderImageSlice: 1,
|
||||
}}
|
||||
styles={{
|
||||
body: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 24,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
padding: 32,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src={restaurant?.restautantImage}
|
||||
width={30}
|
||||
height={30}
|
||||
preview={false}
|
||||
style={{
|
||||
borderRadius: "50%",
|
||||
objectFit: "cover",
|
||||
position: "relative",
|
||||
top: -4,
|
||||
}}
|
||||
/>
|
||||
|
||||
<ProTitle
|
||||
level={5}
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 400,
|
||||
fontStyle: "Regular",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#95949C",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
{isRTL ? restaurant?.nameAR : restaurant?.restautantName}
|
||||
</ProTitle>
|
||||
{t("redeem.showThisCodeAtTheRestaurant")}
|
||||
</ProText>
|
||||
<QRIcon />
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
|
||||
<Button
|
||||
style={{
|
||||
height: 40,
|
||||
borderRadius: 888,
|
||||
gap: 16,
|
||||
opacity: 1,
|
||||
borderWidth: 1,
|
||||
backgroundColor: "var(--background)",
|
||||
}}
|
||||
icon={<CopyIcon className={styles.copyIcon} />}
|
||||
iconPlacement="end"
|
||||
>
|
||||
GFT - 92KD - 7X84
|
||||
</Button>
|
||||
<ProText
|
||||
style={{
|
||||
fontWeight: 400,
|
||||
fontStyle: "Regular",
|
||||
fontSize: 14,
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
color: "#95949C",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
{t("redeem.useThisCodeIfScanningNotPossible")}
|
||||
</ProText>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{isRTL ? (
|
||||
<BackIcon className={styles.serviceIcon} />
|
||||
) : (
|
||||
<NextIcon className={styles.serviceIcon} />
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: 44,
|
||||
opacity: 1,
|
||||
borderBottomRightRadius: 16,
|
||||
borderBottomLeftRadius: 16,
|
||||
paddingTop: 12,
|
||||
paddingBottom: 12,
|
||||
gap: 10,
|
||||
borderTopWidth: 1,
|
||||
background: "#FFF9E6",
|
||||
borderTop: "1px solid #FFEDB0",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
<ProText
|
||||
style={{
|
||||
fontSize: 14,
|
||||
fontWeight: 500,
|
||||
fontStyle: "Medium",
|
||||
lineHeight: "140%",
|
||||
letterSpacing: "0%",
|
||||
textAlign: "center",
|
||||
color: "#E8B400",
|
||||
}}
|
||||
>
|
||||
Active - Expires in 12 days
|
||||
</ProText>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* <RateBottomSheet /> */}
|
||||
<div
|
||||
style={{
|
||||
margin: "20px 0",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 16,
|
||||
}}
|
||||
>
|
||||
<GiftItemsCard />
|
||||
<VoucherBalanceCard />
|
||||
<LocationCard />
|
||||
</div>
|
||||
</Layout.Content>
|
||||
|
||||
<CancelOrderBottomSheet />
|
||||
</div>
|
||||
<Layout.Footer className={styles.checkoutButtonContainer}>
|
||||
<Button
|
||||
type="primary"
|
||||
shape="round"
|
||||
className={styles.checkoutButton}
|
||||
onClick={handleCheckout}
|
||||
>
|
||||
{t("redeem.redeemNow")}
|
||||
</Button>
|
||||
</Layout.Footer>
|
||||
</Layout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,247 +1,81 @@
|
||||
.orderSummary :global(.ant-card-body) {
|
||||
padding: 16px !important;
|
||||
}
|
||||
|
||||
.profileImage {
|
||||
border-radius: 50%;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
/* Enhanced responsive order summary */
|
||||
@media (min-width: 769px) and (max-width: 1024px) {
|
||||
.orderSummary {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
.fascanoIcon {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.locationIcon {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.orderDishIcon {
|
||||
.carouselContainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.orderCard :global(.ant-card-body) {
|
||||
.cardWrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.orderCard :global(.ant-card-body) > *:not(:last-child) {
|
||||
margin-bottom: 3.5rem;
|
||||
}
|
||||
|
||||
.orderSummary {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.invoiceIcon {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.timeIcon {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
/* Enhanced responsive order summary */
|
||||
@media (min-width: 769px) and (max-width: 1024px) {
|
||||
.orderSummary {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
.summaryRow {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Enhanced responsive summary rows */
|
||||
@media (min-width: 769px) and (max-width: 1024px) {
|
||||
.summaryRow {
|
||||
padding: 12px 0;
|
||||
font-size: 16px;
|
||||
}
|
||||
.cardImage {
|
||||
width: 205px;
|
||||
height: 134px;
|
||||
object-fit: cover;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@media (min-width: 1025px) {
|
||||
.summaryRow {
|
||||
padding: 16px 0;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.summaryDivider {
|
||||
margin: 8px 0 !important;
|
||||
}
|
||||
|
||||
/* Enhanced responsive summary divider */
|
||||
@media (min-width: 769px) and (max-width: 1024px) {
|
||||
.summaryDivider {
|
||||
margin: 20px 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1025px) {
|
||||
.summaryDivider {
|
||||
margin: 24px 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.totalRow {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* Enhanced responsive total row */
|
||||
@media (min-width: 769px) and (max-width: 1024px) {
|
||||
.totalRow {
|
||||
font-size: 18px;
|
||||
padding-top: 20px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1025px) {
|
||||
.totalRow {
|
||||
font-size: 20px;
|
||||
padding-top: 24px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.desktopOrderSummary {
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.desktopSummaryRow {
|
||||
.arrowButton {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 0;
|
||||
font-size: 16px;
|
||||
justify-content: center;
|
||||
min-width: 40px;
|
||||
height: 40px;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.desktopTotalRow {
|
||||
.arrowButton:hover {
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* CheckoutButton Styles */
|
||||
.checkoutButtonContainer {
|
||||
width: 100%;
|
||||
padding: 16px 16px 0;
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 80px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px 0;
|
||||
margin-top: 16px;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
gap: 1rem;
|
||||
background-color: var(--secondary-background);
|
||||
box-shadow: none;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .orderSummary {
|
||||
background-color: #181818 !important;
|
||||
border-color: #363636 !important;
|
||||
/* Dark theme styles for checkout */
|
||||
:global(.darkApp) .checkoutButtonContainer {
|
||||
background-color: #000000 !important;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .orderSummary:hover {
|
||||
background-color: #363636 !important;
|
||||
border-color: #424242 !important;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .summaryRow {
|
||||
color: #b0b0b0;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .totalRow {
|
||||
color: #ffffff;
|
||||
border-top-color: #424242;
|
||||
}
|
||||
|
||||
/* Enhanced responsive animations */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.orderSummary {
|
||||
animation: fadeInUp 0.8s ease-out;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Enhanced responsive focus states */
|
||||
.orderSummary:focus {
|
||||
outline: 2px solid var(--primary);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.orderSummary:focus {
|
||||
outline-offset: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enhanced responsive print styles */
|
||||
@media print {
|
||||
.orderSummary {
|
||||
box-shadow: none !important;
|
||||
border: 1px solid #ccc !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enhanced responsive hover effects */
|
||||
@media (hover: hover) {
|
||||
.orderSummary:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.menuItemImage:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .orderSummary:hover {
|
||||
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
.backToHomePage {
|
||||
.checkoutButton {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
margin-bottom: 16px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.copyIcon {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.redeemContainer {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
padding: 12px 18px !important;
|
||||
row-gap: 10px;
|
||||
transition: all 0.3s ease;
|
||||
border-radius: 50px;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
gap: 16px;
|
||||
overflow: auto;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.backToHomePage :global(.ant-card-body) {
|
||||
padding: 0px !important;
|
||||
text-align: start;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nextIcon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.backIcon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user