import { Button, Card, Divider, Flex, Image, Layout, Progress, Tooltip, } from "antd"; 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 ProHeader from "components/ProHeader/ProHeader"; import ProText from "components/ProText"; import ProTitle from "components/ProTitle"; import dayjs from "dayjs"; import { useEffect, useMemo, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { useNavigate, useParams } from "react-router-dom"; import { useGetOrderDetailsQuery, useGetRestaurantDetailsQuery, } from "redux/api/others"; import { useAppSelector } from "redux/hooks"; import Stepper from "./components/Stepper"; import styles from "./order.module.css"; import BackIcon from "components/Icons/BackIcon"; import NextIcon from "components/Icons/NextIcon"; import { RateBottomSheet } from "components/CustomBottomSheet/RateBottomSheet"; import BriefMenuCard from "pages/checkout/components/BriefMenuCard"; import { QRBottomSheet } from "pages/pay/components/splitBill/QRBottomSheet"; import NewRateIcon from "components/Icons/order/NewRateIcon"; import NoteIcon from "components/Icons/NoteIcon"; import SuccessIcon from "components/Icons/SuccessIcon"; import { SplitBillParticipantsBottomSheet } from "./components/SplitBillParticipantsBottomSheet"; import { OrderType } from "pages/checkout/hooks/types"; export default function OrderPage() { const { t } = useTranslation(); const { orderId } = useParams(); const navigate = useNavigate(); const { isRTL } = useAppSelector((state) => state.locale); const { restaurant, orderType } = useAppSelector((state) => state.order); const hasRefetchedRef = useRef(false); const [isOpen, setIsOpen] = useState(false); const [isRateOrderOpen, setIsRateOrderOpen] = useState(false); // Track order details in state to trigger re-evaluation of polling const [lastOrderDetails, setLastOrderDetails] = useState(null); // Compute polling interval based on order status const pollingInterval = useMemo(() => { const orderDetailsToCheck = lastOrderDetails; if (orderDetailsToCheck?.status) { const hasClosedOrCanceled = orderDetailsToCheck.status.some( (status: any) => status?.alias === "closed" || status?.alias === "canceled_by_customer", ); if (hasClosedOrCanceled) { return 0; // Stop polling } } return 10000; // Continue polling }, [lastOrderDetails]); const { data: orderDetails } = useGetOrderDetailsQuery( { orderID: orderId || "", restaurantID: localStorage.getItem("restaurantID") || "", }, { skip: !orderId, // return it t0 60000 after finish testing // Stop polling if order is closed or canceled pollingInterval, refetchOnMountOrArgChange: true, }, ); // Update state when orderDetails changes to trigger polling re-evaluation useEffect(() => { if (orderDetails) { setLastOrderDetails(orderDetails); } }, [orderDetails]); const hasClosedStatus = orderDetails?.status?.some( (status) => status?.alias === "closed", ); const hasCanceledByCustomerStatus = orderDetails?.status?.some( (status) => status?.alias === "canceled_by_customer", ); const [ isSplitBillParticipantsBottomSheetOpen, setIsSplitBillParticipantsBottomSheetOpen, ] = useState(false); // 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; }, [orderId]); // Refetch restaurant details when order status has alias "closed" useEffect(() => { if (orderDetails?.status && !hasRefetchedRef.current) { if ( (hasClosedStatus || hasCanceledByCustomerStatus) && restaurantSubdomain ) { refetchRestaurantDetails(); hasRefetchedRef.current = true; } } }, [orderDetails?.status, restaurantSubdomain, refetchRestaurantDetails]); // Check if order is in progress (check last status alias) const lastStatus = orderDetails?.status?.[orderDetails.status.length - 1]; const isInProgress = lastStatus?.alias === "accepted_by_restaurant"; // Calculate timer and progress const [remainingSeconds, setRemainingSeconds] = useState(0); const [progressPercent, setProgressPercent] = useState(0); useEffect(() => { if ( !isInProgress || !orderDetails?.order?.time_to_prepare || !orderDetails?.order?.created_at ) { return; } const updateTimer = () => { const orderCreatedAt = dayjs(orderDetails.order.created_at); const now = dayjs(); const elapsedSeconds = now.diff(orderCreatedAt, "second"); // time_to_prepare is in minutes, convert to seconds const totalSeconds = (Number(orderDetails.order.time_to_prepare) || 0) * 60; const remaining = Math.max(0, totalSeconds - elapsedSeconds); setRemainingSeconds(remaining); // Calculate progress as remaining time percentage (starts at 100%, decreases to 0%) const percent = totalSeconds > 0 ? Math.min(100, Math.max(0, (remaining / totalSeconds) * 100)) : 100; setProgressPercent(percent); }; updateTimer(); const interval = setInterval(updateTimer, 1000); return () => clearInterval(interval); }, [ isInProgress, orderDetails?.order?.time_to_prepare, orderDetails?.status, ]); // Format remaining time with Min and Sec labels const formatTimer = (totalSeconds: number) => { const mins = Math.floor(totalSeconds / 60); const secs = Math.floor(totalSeconds % 60); return (
{mins.toString().padStart(2, "0")} {t("order.min")}
:
{secs.toString().padStart(2, "0")} {t("order.sec")}
); }; return ( <> {t("order.title")}
{t("order.yourOrderFromFascanoRestaurant")}
{" "} {isRTL ? orderDetails?.restaurantAR : orderDetails?.restaurant}
{isInProgress ? (
(
{t("order.remainingTime")} {formatTimer(remainingSeconds)}
)} strokeColor="#FFB700" size={200} type="dashboard" />
) : (
)}
{t("order.inProgressOrder")} (1)
#{orderDetails?.order.id} ordered :- Today -{" "} {dayjs(orderDetails?.status[0]?.pivot?.created_at).format( "h:mm A", )}
{!hasClosedStatus && orderType === OrderType.DineIn && (
{t( "order.aStaffMemberWillCollectTheCashFromYouAtYourTable", )} {t("order.callWaiter")}
)} {hasClosedStatus && orderType === OrderType.DineIn && (
{t("order.cashPaymentConfirmed")}
)}
{/* */} {/* {t("order.yourOrderFrom")}
{" "} {t("order.muscat")} } >
{orderDetails?.orderItems.map((item, index) => (
{item.name}
))}
*/} {/* inviteToBill */} {/* {!hasClosedStatus && (
{t("order.whosPaidTheirShareSplitBill")} {t("order.seeWhoPaidAndHowMuch")}
} >
setIsSplitBillParticipantsBottomSheetOpen(true)} >
{t("order.personHasPaid")}
{isRTL ? ( ) : ( )}
)} */} setIsOpen(false)} /> {hasClosedStatus && ( setIsRateOrderOpen(true)} >
{t("order.rateOrder")}
{isRTL ? ( ) : ( )}
)} setIsRateOrderOpen(false)} /> {!hasClosedStatus && !hasCanceledByCustomerStatus && ( )}
{(hasClosedStatus || hasCanceledByCustomerStatus) && ( )}
setIsSplitBillParticipantsBottomSheetOpen(false)} /> ); }