Compare commits
2 Commits
a68480c075
...
aaef1bc11b
| Author | SHA1 | Date | |
|---|---|---|---|
| aaef1bc11b | |||
| ba350e877f |
@@ -13,29 +13,68 @@ interface StepperProps {
|
|||||||
export default function Stepper({ statuses = [] }: StepperProps) {
|
export default function Stepper({ statuses = [] }: StepperProps) {
|
||||||
const { t } = useTranslation();
|
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(
|
const labels = useMemo(
|
||||||
() => [t("order.reserved"), t("order.prepare"), t("order.ready")],
|
() => [t("order.reserved"), t("order.prepare"), t("order.ready")],
|
||||||
[t],
|
[t],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Determine number of steps: 2 if canceled, 3 otherwise
|
||||||
|
const stepCount = hasCanceledStatus ? 2 : 3;
|
||||||
|
|
||||||
const activeIndex = useMemo(() => {
|
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;
|
const reachedStatuses = statuses.length > 0 ? statuses.length - 1 : 0;
|
||||||
return Math.min(Math.max(reachedStatuses, 0), 2);
|
return Math.min(Math.max(reachedStatuses, 0), 2);
|
||||||
}, [statuses.length]);
|
}, [statuses.length, hasCanceledStatus]);
|
||||||
|
|
||||||
const steps = useMemo(
|
const steps = useMemo(
|
||||||
() =>
|
() =>
|
||||||
Array.from({ length: 3 }, (_, index) => {
|
Array.from({ length: stepCount }, (_, index) => {
|
||||||
const status = statuses[index];
|
let status;
|
||||||
const label = status?.name || status?.alias || labels[index] || "";
|
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;
|
const isPending = index > activeIndex;
|
||||||
return {
|
return {
|
||||||
key: status ? `status-${status.id}` : `placeholder-${index}`,
|
key: status ? `status-${status.id}` : `placeholder-${index}`,
|
||||||
label,
|
label,
|
||||||
isPending,
|
isPending,
|
||||||
|
isCanceled,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
[activeIndex, labels, statuses],
|
[activeIndex, labels, statuses, stepCount, hasCanceledStatus, canceledStatus, t],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -57,7 +96,16 @@ export default function Stepper({ statuses = [] }: StepperProps) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{steps.map((step, index) => {
|
{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,
|
width: 12,
|
||||||
height: 12,
|
height: 12,
|
||||||
@@ -72,7 +120,17 @@ export default function Stepper({ statuses = [] }: StepperProps) {
|
|||||||
backgroundColor: colors.primary,
|
backgroundColor: colors.primary,
|
||||||
};
|
};
|
||||||
|
|
||||||
const lineStyle: CSSProperties = {
|
// 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,
|
height: 1.5,
|
||||||
backgroundColor: step.isPending ? "#BDBDBD" : colors.primary,
|
backgroundColor: step.isPending ? "#BDBDBD" : colors.primary,
|
||||||
margin: "0 8px",
|
margin: "0 8px",
|
||||||
@@ -120,7 +178,11 @@ export default function Stepper({ statuses = [] }: StepperProps) {
|
|||||||
lineHeight: "140%",
|
lineHeight: "140%",
|
||||||
letterSpacing: "0%",
|
letterSpacing: "0%",
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
color: step.isPending ? "#99A2AE" : "#333333",
|
color: step.isCanceled
|
||||||
|
? "#EF4444" // Red for canceled
|
||||||
|
: step.isPending
|
||||||
|
? "#99A2AE"
|
||||||
|
: "#333333",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{step.label}
|
{step.label}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {
|
|||||||
Progress,
|
Progress,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import Ads2 from "components/Ads/Ads2";
|
|
||||||
import { CancelOrderBottomSheet } from "components/CustomBottomSheet/CancelOrderBottomSheet";
|
import { CancelOrderBottomSheet } from "components/CustomBottomSheet/CancelOrderBottomSheet";
|
||||||
import LocationIcon from "components/Icons/LocationIcon";
|
import LocationIcon from "components/Icons/LocationIcon";
|
||||||
import InvoiceIcon from "components/Icons/order/InvoiceIcon";
|
import InvoiceIcon from "components/Icons/order/InvoiceIcon";
|
||||||
@@ -19,7 +18,7 @@ import ProHeader from "components/ProHeader/ProHeader";
|
|||||||
import ProText from "components/ProText";
|
import ProText from "components/ProText";
|
||||||
import ProTitle from "components/ProTitle";
|
import ProTitle from "components/ProTitle";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
@@ -37,7 +36,6 @@ import { QRBottomSheet } from "pages/pay/components/splitBill/QRBottomSheet";
|
|||||||
import NewRateIcon from "components/Icons/order/NewRateIcon";
|
import NewRateIcon from "components/Icons/order/NewRateIcon";
|
||||||
import NoteIcon from "components/Icons/NoteIcon";
|
import NoteIcon from "components/Icons/NoteIcon";
|
||||||
import SuccessIcon from "components/Icons/SuccessIcon";
|
import SuccessIcon from "components/Icons/SuccessIcon";
|
||||||
import ProInputCard from "components/ProInputCard/ProInputCard";
|
|
||||||
import { SplitBillParticipantsBottomSheet } from "./components/SplitBillParticipantsBottomSheet";
|
import { SplitBillParticipantsBottomSheet } from "./components/SplitBillParticipantsBottomSheet";
|
||||||
|
|
||||||
export default function OrderPage() {
|
export default function OrderPage() {
|
||||||
@@ -49,10 +47,26 @@ export default function OrderPage() {
|
|||||||
const hasRefetchedRef = useRef(false);
|
const hasRefetchedRef = useRef(false);
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [isRateOrderOpen, setIsRateOrderOpen] = useState(false);
|
const [isRateOrderOpen, setIsRateOrderOpen] = useState(false);
|
||||||
const [
|
|
||||||
isSplitBillParticipantsBottomSheetOpen,
|
// Track order details in state to trigger re-evaluation of polling
|
||||||
setIsSplitBillParticipantsBottomSheetOpen,
|
const [lastOrderDetails, setLastOrderDetails] = useState<any>(null);
|
||||||
] = useState(false);
|
|
||||||
|
// 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(
|
const { data: orderDetails } = useGetOrderDetailsQuery(
|
||||||
{
|
{
|
||||||
orderID: orderId || "",
|
orderID: orderId || "",
|
||||||
@@ -61,11 +75,32 @@ export default function OrderPage() {
|
|||||||
{
|
{
|
||||||
skip: !orderId,
|
skip: !orderId,
|
||||||
// return it t0 60000 after finish testing
|
// return it t0 60000 after finish testing
|
||||||
pollingInterval: 10000,
|
// Stop polling if order is closed or canceled
|
||||||
|
pollingInterval,
|
||||||
refetchOnMountOrArgChange: true,
|
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
|
// Get restaurant subdomain for refetching
|
||||||
const restaurantSubdomain = restaurant?.subdomain;
|
const restaurantSubdomain = restaurant?.subdomain;
|
||||||
const { refetch: refetchRestaurantDetails } = useGetRestaurantDetailsQuery(
|
const { refetch: refetchRestaurantDetails } = useGetRestaurantDetailsQuery(
|
||||||
@@ -74,13 +109,6 @@ export default function OrderPage() {
|
|||||||
skip: !restaurantSubdomain,
|
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
|
// Reset refetch flag when orderId changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -90,7 +118,10 @@ export default function OrderPage() {
|
|||||||
// Refetch restaurant details when order status has alias "closed"
|
// Refetch restaurant details when order status has alias "closed"
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (orderDetails?.status && !hasRefetchedRef.current) {
|
if (orderDetails?.status && !hasRefetchedRef.current) {
|
||||||
if (hasClosedStatus && restaurantSubdomain) {
|
if (
|
||||||
|
(hasClosedStatus || hasCanceledByCustomerStatus) &&
|
||||||
|
restaurantSubdomain
|
||||||
|
) {
|
||||||
refetchRestaurantDetails();
|
refetchRestaurantDetails();
|
||||||
hasRefetchedRef.current = true;
|
hasRefetchedRef.current = true;
|
||||||
}
|
}
|
||||||
@@ -289,7 +320,7 @@ export default function OrderPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isInProgress ? (
|
{isInProgress ? (
|
||||||
<Flex gap="small" wrap justify="center">
|
<Flex gap="small" wrap justify="center" style={{ marginTop: 16 }}>
|
||||||
<Tooltip title="3 done / 3 in progress / 4 to do">
|
<Tooltip title="3 done / 3 in progress / 4 to do">
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -671,7 +702,7 @@ export default function OrderPage() {
|
|||||||
onClose={() => setIsRateOrderOpen(false)}
|
onClose={() => setIsRateOrderOpen(false)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{(!hasClosedStatus && !hasCanceledByCustomerStatus) && (
|
{!hasClosedStatus && !hasCanceledByCustomerStatus && (
|
||||||
<CancelOrderBottomSheet />
|
<CancelOrderBottomSheet />
|
||||||
)}
|
)}
|
||||||
</Layout.Content>
|
</Layout.Content>
|
||||||
|
|||||||
Reference in New Issue
Block a user