import { useState } from "react"; import { Badge, Box, Button, Group, Stack, Text, Textarea, ThemeIcon, } from "@mantine/core"; import { Check, Circle, Clock, MinusCircle } from "lucide-react"; import type { Freight } from "@edr/types"; export interface ClearanceMilestoneTimelineProps { milestones: Freight.IClearanceMilestone[]; /** Complete a milestone by code (omit to render read-only). */ onComplete?: (code: string, note?: string) => void; /** True while a complete mutation is in flight. */ busy?: boolean; } const STATUS_META: Record< Freight.MilestoneStatus, { color: string; label: string } > = { COMPLETED: { color: "edr-green", label: "Completed" }, PENDING: { color: "gray", label: "Pending" }, SKIPPED: { color: "gray", label: "Skipped" }, }; /** Vertical timeline of GL clearance milestones with inline complete actions. */ export function ClearanceMilestoneTimeline({ milestones, onComplete, busy, }: ClearanceMilestoneTimelineProps) { const [openNote, setOpenNote] = useState>({}); const [notes, setNotes] = useState>({}); const sorted = [...milestones].sort((a, b) => a.sortOrder - b.sortOrder); const nextPending = sorted.find((m) => m.status === "PENDING"); if (sorted.length === 0) { return ( No milestones for this shipment yet. ); } return ( {sorted.map((m, index) => { const isLast = index === sorted.length - 1; const meta = STATUS_META[m.status]; const isNext = nextPending?.id === m.id; const Icon = m.status === "COMPLETED" ? Check : m.status === "SKIPPED" ? MinusCircle : isNext ? Clock : Circle; return ( {!isLast && ( )} {m.milestoneLabel} {meta.label} {m.ownerRegion ? ( {m.ownerRegion} ) : null} {m.note ? ( {m.note} ) : null} {onComplete && m.status === "PENDING" && isNext ? ( !openNote[m.milestoneCode] ? ( ) : null ) : null} {onComplete && openNote[m.milestoneCode] && (