Files
edr-platform/apps/edr-freight-web/backoffice/src/components/contracts/ContractWorkflowStepper.tsx
2026-06-26 23:24:48 +00:00

143 lines
4.2 KiB
TypeScript

import {
Check,
FileSignature,
FileText,
ShieldCheck,
Truck,
Workflow,
type LucideIcon,
} from "lucide-react";
import { Paper, Group, Stack, Text, Box } from "@mantine/core";
import {
CONTRACT_WORKFLOW_STAGES,
getContractWorkflowStageIndex,
} from "@/features/contracts/contract-status.config";
import { SectionCard } from "@/components/bookings/detail/SectionCard";
import {
BRAND_GREEN,
detailStyles,
} from "@/components/bookings/detail/booking-detail.styles";
const STAGE_ICONS: LucideIcon[] = [
FileText,
FileSignature,
FileSignature,
ShieldCheck,
Truck,
Check,
];
interface ContractWorkflowStepperProps {
status: string;
title: string;
description: string;
}
export function ContractWorkflowStepper({
status,
title,
description,
}: ContractWorkflowStepperProps) {
const currentStage = getContractWorkflowStageIndex(status);
const isTerminal = currentStage < 0;
return (
<SectionCard icon={Workflow} title="Workflow progress">
<Group gap={0} wrap="nowrap" align="flex-start" mb="lg">
{CONTRACT_WORKFLOW_STAGES.map((stage, index) => {
const Icon = STAGE_ICONS[index] ?? FileText;
const isComplete = !isTerminal && index < currentStage;
const isActive = !isTerminal && index === currentStage;
const isLast = index === CONTRACT_WORKFLOW_STAGES.length - 1;
return (
<Box
key={stage.label}
style={{ flex: isLast ? "0 0 auto" : 1, minWidth: 0 }}
>
<Group gap={0} wrap="nowrap" align="center">
<Stack gap={6} align="center" style={{ flexShrink: 0 }}>
<Box
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
width: 34,
height: 34,
borderRadius: "50%",
background: isComplete
? BRAND_GREEN
: isActive
? "white"
: "var(--mantine-color-gray-1)",
border: isActive
? `2px solid ${BRAND_GREEN}`
: isComplete
? "2px solid transparent"
: "2px solid var(--mantine-color-gray-2)",
color: isComplete
? "white"
: isActive
? "var(--freight-brand-dark)"
: "var(--mantine-color-gray-5)",
transition: "all 0.2s ease",
}}
>
{isComplete ? (
<Check size={16} strokeWidth={3} />
) : (
<Icon size={15} />
)}
</Box>
<Text
size="xs"
fw={isActive ? 600 : 500}
c={isActive ? "edr-green.7" : isComplete ? "dark" : "dimmed"}
ta="center"
style={{ whiteSpace: "nowrap" }}
>
{stage.label}
</Text>
</Stack>
{!isLast && (
<Box
style={{
flex: 1,
height: 2,
marginInline: 8,
marginBottom: 20,
borderRadius: 2,
background: isComplete
? BRAND_GREEN
: "var(--mantine-color-gray-2)",
}}
/>
)}
</Group>
</Box>
);
})}
</Group>
<Paper
radius="md"
withBorder
p="md"
style={
isTerminal
? detailStyles.statusBannerTerminal
: detailStyles.statusBanner
}
>
<Text size="sm" fw={600} c={isTerminal ? "red.7" : "dark"}>
{title}
</Text>
<Text size="sm" c="dimmed" mt={4}>
{description}
</Text>
</Paper>
</SectionCard>
);
}