From ba350e877f9f72e2a349463f0f11649380daf1d3 Mon Sep 17 00:00:00 2001 From: Mohammed Al-yaseen Date: Wed, 14 Jan 2026 22:12:14 +0300 Subject: [PATCH] handle cancel case in order stepper --- src/pages/order/components/Stepper.tsx | 86 ++++++++++++++++++++++---- src/pages/order/page.tsx | 32 +++++----- 2 files changed, 92 insertions(+), 26 deletions(-) diff --git a/src/pages/order/components/Stepper.tsx b/src/pages/order/components/Stepper.tsx index bb92d86..eab4801 100644 --- a/src/pages/order/components/Stepper.tsx +++ b/src/pages/order/components/Stepper.tsx @@ -13,29 +13,68 @@ interface StepperProps { export default function Stepper({ statuses = [] }: StepperProps) { const { t } = useTranslation(); + // Check if order has canceled_by_customer status + const hasCanceledStatus = useMemo( + () => statuses.some((status) => status?.alias === "canceled_by_customer"), + [statuses], + ); + + // Get the canceled status if it exists + const canceledStatus = useMemo( + () => statuses.find((status) => status?.alias === "canceled_by_customer"), + [statuses], + ); + const labels = useMemo( () => [t("order.reserved"), t("order.prepare"), t("order.ready")], [t], ); + // Determine number of steps: 2 if canceled, 3 otherwise + const stepCount = hasCanceledStatus ? 2 : 3; + const activeIndex = useMemo(() => { + if (hasCanceledStatus) { + // For canceled orders, the last step (index 1) is always active + return 1; + } const reachedStatuses = statuses.length > 0 ? statuses.length - 1 : 0; return Math.min(Math.max(reachedStatuses, 0), 2); - }, [statuses.length]); + }, [statuses.length, hasCanceledStatus]); const steps = useMemo( () => - Array.from({ length: 3 }, (_, index) => { - const status = statuses[index]; - const label = status?.name || status?.alias || labels[index] || ""; + Array.from({ length: stepCount }, (_, index) => { + let status; + let label; + let isCanceled = false; + + if (hasCanceledStatus) { + if (index === 0) { + // First step: show first status or default label + status = statuses[0]; + label = status?.name || status?.alias || labels[0] || ""; + } else if (index === 1) { + // Second step: show canceled status + status = canceledStatus; + label = status?.name || status?.alias || t("order.canceled") || ""; + isCanceled = true; + } + } else { + // Normal flow: 3 steps + status = statuses[index]; + label = status?.name || status?.alias || labels[index] || ""; + } + const isPending = index > activeIndex; return { key: status ? `status-${status.id}` : `placeholder-${index}`, label, isPending, + isCanceled, }; }), - [activeIndex, labels, statuses], + [activeIndex, labels, statuses, stepCount, hasCanceledStatus, canceledStatus, t], ); return ( @@ -57,7 +96,16 @@ export default function Stepper({ statuses = [] }: StepperProps) { }} > {steps.map((step, index) => { - const circleStyle: CSSProperties = step.isPending + // Determine circle style based on state + const circleStyle: CSSProperties = step.isCanceled + ? { + width: 12, + height: 12, + borderRadius: "50%", + backgroundColor: "#EF4444", // Red for canceled + border: "2px solid #EF4444", + } + : step.isPending ? { width: 12, height: 12, @@ -72,11 +120,21 @@ export default function Stepper({ statuses = [] }: StepperProps) { backgroundColor: colors.primary, }; - const lineStyle: CSSProperties = { - height: 1.5, - backgroundColor: step.isPending ? "#BDBDBD" : colors.primary, - margin: "0 8px", - }; + // Determine line style based on state + // Line should be red if the next step is canceled + const nextStep = index < steps.length - 1 ? steps[index + 1] : null; + const lineStyle: CSSProperties = + nextStep?.isCanceled + ? { + height: 1.5, + backgroundColor: "#EF4444", // Red for canceled + margin: "0 8px", + } + : { + height: 1.5, + backgroundColor: step.isPending ? "#BDBDBD" : colors.primary, + margin: "0 8px", + }; return ( @@ -120,7 +178,11 @@ export default function Stepper({ statuses = [] }: StepperProps) { lineHeight: "140%", letterSpacing: "0%", textAlign: "center", - color: step.isPending ? "#99A2AE" : "#333333", + color: step.isCanceled + ? "#EF4444" // Red for canceled + : step.isPending + ? "#99A2AE" + : "#333333", }} > {step.label} diff --git a/src/pages/order/page.tsx b/src/pages/order/page.tsx index cf34c96..d5ce055 100644 --- a/src/pages/order/page.tsx +++ b/src/pages/order/page.tsx @@ -37,7 +37,6 @@ 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 ProInputCard from "components/ProInputCard/ProInputCard"; import { SplitBillParticipantsBottomSheet } from "./components/SplitBillParticipantsBottomSheet"; export default function OrderPage() { @@ -49,10 +48,6 @@ export default function OrderPage() { const hasRefetchedRef = useRef(false); const [isOpen, setIsOpen] = useState(false); const [isRateOrderOpen, setIsRateOrderOpen] = useState(false); - const [ - isSplitBillParticipantsBottomSheetOpen, - setIsSplitBillParticipantsBottomSheetOpen, - ] = useState(false); const { data: orderDetails } = useGetOrderDetailsQuery( { orderID: orderId || "", @@ -65,6 +60,19 @@ export default function OrderPage() { refetchOnMountOrArgChange: true, }, ); + 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; @@ -74,13 +82,6 @@ export default function OrderPage() { skip: !restaurantSubdomain, }, ); - const hasClosedStatus = orderDetails?.status?.some( - (status) => status?.alias === "closed", - ); - - const hasCanceledByCustomerStatus = orderDetails?.status?.some( - (status) => status?.alias === "canceled_by_customer", - ); // Reset refetch flag when orderId changes useEffect(() => { @@ -90,7 +91,10 @@ export default function OrderPage() { // Refetch restaurant details when order status has alias "closed" useEffect(() => { if (orderDetails?.status && !hasRefetchedRef.current) { - if (hasClosedStatus && restaurantSubdomain) { + if ( + (hasClosedStatus || hasCanceledByCustomerStatus) && + restaurantSubdomain + ) { refetchRestaurantDetails(); hasRefetchedRef.current = true; } @@ -671,7 +675,7 @@ export default function OrderPage() { onClose={() => setIsRateOrderOpen(false)} /> - {(!hasClosedStatus && !hasCanceledByCustomerStatus) && ( + {!hasClosedStatus && !hasCanceledByCustomerStatus && ( )}