199 lines
5.8 KiB
TypeScript
199 lines
5.8 KiB
TypeScript
import { Col, Row } from "antd";
|
|
import ProText from "components/ProText";
|
|
import { Status } from "pages/checkout/hooks/types";
|
|
import type { CSSProperties } from "react";
|
|
import { Fragment, useMemo } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { colors } from "ThemeConstants";
|
|
|
|
interface StepperProps {
|
|
statuses?: Status[];
|
|
}
|
|
|
|
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, hasCanceledStatus]);
|
|
|
|
const steps = useMemo(
|
|
() =>
|
|
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, stepCount, hasCanceledStatus, canceledStatus, t],
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
}}
|
|
>
|
|
<Row
|
|
align={"middle"}
|
|
style={{
|
|
width: 330,
|
|
maxWidth: "100%",
|
|
position: "relative",
|
|
padding: "12px",
|
|
}}
|
|
>
|
|
{steps.map((step, index) => {
|
|
// 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,
|
|
borderRadius: "50%",
|
|
backgroundColor: "#FFF",
|
|
border: "2px solid #BDBDBD",
|
|
}
|
|
: {
|
|
width: 12,
|
|
height: 12,
|
|
borderRadius: "50%",
|
|
backgroundColor: colors.primary,
|
|
};
|
|
|
|
// 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 (
|
|
<Fragment key={step.key}>
|
|
<Col>
|
|
<div style={circleStyle}></div>
|
|
</Col>
|
|
{index < steps.length - 1 && (
|
|
<Col flex={"auto"}>
|
|
<div style={lineStyle}></div>
|
|
</Col>
|
|
)}
|
|
</Fragment>
|
|
);
|
|
})}
|
|
</Row>
|
|
</div>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
justifyContent: "center",
|
|
alignItems: "center",
|
|
}}
|
|
>
|
|
<Row
|
|
align={"middle"}
|
|
style={{
|
|
width: 330,
|
|
maxWidth: "100%",
|
|
position: "relative",
|
|
padding: "12px",
|
|
}}
|
|
>
|
|
{steps.map((step, index) => (
|
|
<Fragment key={`label-${step.key}`}>
|
|
<Col>
|
|
<ProText
|
|
style={{
|
|
fontWeight: 400,
|
|
fontStyle: "Regular",
|
|
fontSize: 14,
|
|
lineHeight: "140%",
|
|
letterSpacing: "0%",
|
|
textAlign: "center",
|
|
color: step.isCanceled
|
|
? "#EF4444" // Red for canceled
|
|
: step.isPending
|
|
? "#99A2AE"
|
|
: "#333333",
|
|
}}
|
|
>
|
|
{step.label}
|
|
</ProText>
|
|
</Col>
|
|
{index < steps.length - 1 && <Col flex={"auto"}></Col>}
|
|
</Fragment>
|
|
))}
|
|
</Row>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|