redeem: integration

This commit is contained in:
2026-01-11 15:25:45 +03:00
parent 6271c14eff
commit b0288ebcf6
9 changed files with 278 additions and 170 deletions

View File

@@ -1,73 +1,51 @@
import { Button, Card, Image, Layout, Skeleton } from "antd";
import { Button, Card, Image, Layout, QRCode, Skeleton, message } from "antd";
import ProHeader from "components/ProHeader/ProHeader";
import ProText from "components/ProText";
import { useEffect, useRef } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate, useParams } from "react-router-dom";
import {
useGetOrderDetailsQuery,
useGetRestaurantDetailsQuery,
} from "redux/api/others";
import { useGetRedeemDetailsQuery } from "redux/api/others";
import styles from "./redeem.module.css";
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";
import { Loader } from "components/Loader/Loader.tsx";
export default function RedeemPage() {
const { t } = useTranslation();
const { voucherId } = useParams();
const { restaurant } = useAppSelector((state) => state.order);
const hasRefetchedRef = useRef(false);
const navigate = useNavigate();
const { subdomain } = useParams();
const { data: orderDetails, isLoading } = useGetOrderDetailsQuery(
{
orderID: voucherId || "",
restaurantID: localStorage.getItem("restaurantID") || "",
},
const { data: redeemDetails, isLoading } = useGetRedeemDetailsQuery(
voucherId || "",
{
skip: !voucherId,
},
);
// Get restaurant subdomain for refetching
const restaurantSubdomain = restaurant?.subdomain;
const { refetch: refetchRestaurantDetails } = useGetRestaurantDetailsQuery(
restaurantSubdomain || "",
{
skip: !restaurantSubdomain,
},
);
// Reset refetch flag when orderId changes
useEffect(() => {
hasRefetchedRef.current = false;
}, [voucherId]);
// Refetch restaurant details when order status has alias "closed"
useEffect(() => {
if (orderDetails?.status && !hasRefetchedRef.current) {
const hasClosedStatus = orderDetails.status.some(
(status) => status?.alias === "closed",
);
if (hasClosedStatus && restaurantSubdomain) {
refetchRestaurantDetails();
hasRefetchedRef.current = true;
}
}
}, [orderDetails?.status, restaurantSubdomain, refetchRestaurantDetails]);
const handleCheckout = () => {
navigate(`/${subdomain}/menu?orderType=${OrderType.Redeem}`);
};
const handleCopyVoucherCode = async () => {
const voucherCode = redeemDetails?.gift?.voucher_code;
if (voucherCode) {
try {
await navigator.clipboard.writeText(voucherCode);
message.success(
t("redeem.voucherCodeCopied") || "Voucher code copied!",
);
} catch (error) {
message.error(t("redeem.copyFailed") || "Failed to copy voucher code");
}
}
};
if (isLoading) return <Loader />;
return (
<>
<Layout>
@@ -96,7 +74,7 @@ export default function RedeemPage() {
</ProText>
</div>
{isLoading || !orderDetails?.restaurant_iimage ? (
{isLoading || !redeemDetails?.gift?.restaurant_iimage ? (
<div className={styles.carouselContainer}>
<div className={styles.cardWrapper}>
<Skeleton.Image
@@ -113,7 +91,7 @@ export default function RedeemPage() {
<div className={styles.carouselContainer}>
<div className={styles.cardWrapper}>
<Image
src={orderDetails?.restaurant_iimage}
src={redeemDetails?.gift?.card_url}
width={205}
height={134}
className={styles.cardImage}
@@ -161,56 +139,28 @@ export default function RedeemPage() {
</ProText>
</div>
<Card
style={{
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,
},
}}
>
<ProText
<div>
<Card
style={{
fontWeight: 400,
fontStyle: "Regular",
fontSize: 14,
lineHeight: "140%",
letterSpacing: "0%",
color: "#95949C",
alignItems: "center",
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,
},
}}
>
{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,
@@ -222,40 +172,73 @@ export default function RedeemPage() {
alignItems: "center",
}}
>
{t("redeem.useThisCodeIfScanningNotPossible")}
{t("redeem.showThisCodeAtTheRestaurant")}
</ProText>
</div>
</Card>
<QRCode value={redeemDetails?.gift?.gr_url || "-"} />
<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"
onClick={handleCopyVoucherCode}
>
{redeemDetails?.gift?.voucher_code}
</Button>
<ProText
style={{
fontWeight: 400,
fontStyle: "Regular",
fontSize: 14,
lineHeight: "140%",
letterSpacing: "0%",
color: "#95949C",
alignItems: "center",
}}
>
{t("redeem.useThisCodeIfScanningNotPossible")}
</ProText>
</div>
</Card>
<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
<div
style={{
fontSize: 14,
fontWeight: 500,
fontStyle: "Medium",
lineHeight: "140%",
letterSpacing: "0%",
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",
color: "#E8B400",
}}
>
Active - Expires in 12 days
</ProText>
<ProText
style={{
fontSize: 14,
fontWeight: 500,
fontStyle: "Medium",
lineHeight: "140%",
letterSpacing: "0%",
textAlign: "center",
color: "#E8B400",
}}
>
Active - Expires in 12 days
</ProText>
</div>
</div>
<div