Files
edr-platform/apps/edr-freight-web/backoffice/src/components/trainScheduling/trackPrimitives.tsx
2026-08-27 07:45:32 +00:00

150 lines
3.1 KiB
TypeScript

import { Box, Group, Stack, Text } from "@mantine/core";
import type { ReactNode } from "react";
import type { StationWorkPhaseLog } from "@/types/trainScheduling";
import { PHASE_TONE, track, type PhaseState } from "./trackTheme";
/** Small uppercase tag — the design's one chip shape, tinted per use. */
export function Chip({
children,
bg,
fg,
border,
}: {
children: ReactNode;
bg: string;
fg: string;
border?: string;
}) {
return (
<Box
component="span"
style={{
display: "inline-flex",
alignItems: "center",
gap: 6,
padding: "4px 9px",
borderRadius: 6,
background: bg,
border: border ? `1px solid ${border}` : undefined,
color: fg,
fontSize: 9.5,
fontWeight: 700,
letterSpacing: 0.6,
lineHeight: 1.4,
whiteSpace: "nowrap",
flexShrink: 0,
}}
>
{children}
</Box>
);
}
/** Card header: tinted icon chip + title + one-line hint, optional right slot. */
export function SectionHead({
icon,
title,
hint,
right,
}: {
icon: ReactNode;
title: string;
hint: string;
right?: ReactNode;
}) {
return (
<Group
gap={13}
align="center"
wrap="nowrap"
px={24}
py={18}
style={{ borderBottom: `1px solid ${track.borderSoft}` }}
>
<Box
style={{
width: 38,
height: 38,
borderRadius: 11,
display: "flex",
alignItems: "center",
justifyContent: "center",
background: track.brandDim,
color: track.brand,
flexShrink: 0,
}}
>
{icon}
</Box>
<Stack gap={3} style={{ minWidth: 0, flex: 1 }}>
<Text fw={700} size="15px" c={track.text}>
{title}
</Text>
<Text size="12px" c={track.muted}>
{hint}
</Text>
</Stack>
{right}
</Group>
);
}
/** Which of the three window states a phase log is in. */
export function phaseState(log?: StationWorkPhaseLog | null): PhaseState {
if (log?.endedAt) return "done";
if (log?.startedAt) return "active";
return "idle";
}
export function phaseChipLabel(
phase: "loading" | "unloading",
state: PhaseState,
) {
const title = phase === "loading" ? "Loading" : "Unloading";
const suffix =
state === "done"
? "done"
: state === "active"
? "in progress"
: "not started";
return `${title} ${suffix}`;
}
export function PhaseChip({
phase,
state,
}: {
phase: "loading" | "unloading";
state: PhaseState;
}) {
const tone = PHASE_TONE[state];
return (
<Box
style={{
display: "inline-flex",
alignItems: "center",
gap: 6,
padding: "5px 10px",
borderRadius: 7,
background: tone.bg,
width: 150,
flexShrink: 0,
}}
>
<Box
style={{
width: 6,
height: 6,
borderRadius: 999,
background: tone.fg,
flexShrink: 0,
}}
/>
<Text size="10.5px" fw={700} c={tone.fg} style={{ lineHeight: 1.4 }}>
{phaseChipLabel(phase, state)}
</Text>
</Box>
);
}