mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 19:58:11 +00:00
ui fix
This commit is contained in:
@@ -13,14 +13,12 @@ import {
|
||||
Stack,
|
||||
Text,
|
||||
ThemeIcon,
|
||||
Title,
|
||||
} from "@mantine/core";
|
||||
import {
|
||||
AlertTriangle,
|
||||
ArrowRight,
|
||||
CalendarDays,
|
||||
Inbox,
|
||||
LayoutGrid,
|
||||
Package,
|
||||
RefreshCw,
|
||||
Ruler,
|
||||
@@ -323,82 +321,38 @@ export default function BatchBoardPage() {
|
||||
<Container fluid py="lg" px="xl">
|
||||
<Breadcrumbs items={[{ label: "Operations" }, { label: "Batch board" }]} />
|
||||
|
||||
{/* Hero — clean white */}
|
||||
<Paper
|
||||
radius="xl"
|
||||
p="xl"
|
||||
mt="md"
|
||||
withBorder
|
||||
style={{
|
||||
borderColor: "var(--mantine-color-gray-2)",
|
||||
background: "white",
|
||||
boxShadow: "0 1px 3px rgba(15,23,42,0.04)",
|
||||
}}
|
||||
>
|
||||
<Group justify="space-between" align="flex-start" wrap="wrap" gap="md">
|
||||
<Group gap="md" align="center" wrap="nowrap">
|
||||
<ThemeIcon size={56} radius="lg" variant="light" color="green">
|
||||
<LayoutGrid size={28} />
|
||||
</ThemeIcon>
|
||||
<Stack gap={2}>
|
||||
<Group gap={8}>
|
||||
<Text
|
||||
size="xs"
|
||||
fw={700}
|
||||
c="green.7"
|
||||
tt="uppercase"
|
||||
style={{ letterSpacing: 1.2 }}
|
||||
>
|
||||
Allocation · Live
|
||||
</Text>
|
||||
<Box
|
||||
w={7}
|
||||
h={7}
|
||||
className="bb-pulse-dot"
|
||||
style={{ borderRadius: 999, background: FREIGHT_BRAND }}
|
||||
/>
|
||||
</Group>
|
||||
<Title order={2} fw={800} style={{ color: "#0f172a", letterSpacing: 0.2 }}>
|
||||
Batch board
|
||||
</Title>
|
||||
<Text size="sm" c="dimmed" maw={580}>
|
||||
Active schedules — open a card to see EAT 3-hour batch windows, bookings,
|
||||
and live wagon allocation.
|
||||
</Text>
|
||||
</Stack>
|
||||
</Group>
|
||||
<Button
|
||||
variant="default"
|
||||
radius="lg"
|
||||
leftSection={<RefreshCw size={16} />}
|
||||
loading={isFetching}
|
||||
onClick={() => void refetch()}
|
||||
>
|
||||
Refresh
|
||||
</Button>
|
||||
</Group>
|
||||
<Group justify="flex-end" mt="md">
|
||||
<Button
|
||||
variant="default"
|
||||
radius="lg"
|
||||
leftSection={<RefreshCw size={16} />}
|
||||
loading={isFetching}
|
||||
onClick={() => void refetch()}
|
||||
>
|
||||
Refresh
|
||||
</Button>
|
||||
</Group>
|
||||
|
||||
<SimpleGrid cols={{ base: 1, xs: 3 }} spacing="md" mt="lg">
|
||||
<StatTile
|
||||
icon={Train}
|
||||
label="Active schedules"
|
||||
value={isLoading ? "…" : schedules.length}
|
||||
hint="on the board right now"
|
||||
/>
|
||||
<StatTile
|
||||
icon={CalendarDays}
|
||||
label="Open windows"
|
||||
value={isLoading ? "…" : summary.openWindows}
|
||||
hint="accepting bookings"
|
||||
/>
|
||||
<StatTile
|
||||
icon={Package}
|
||||
label="Bookings in play"
|
||||
value={isLoading ? "…" : summary.totalBookings}
|
||||
hint={`${summary.totalWagons} wagons allocated`}
|
||||
/>
|
||||
</SimpleGrid>
|
||||
</Paper>
|
||||
<SimpleGrid cols={{ base: 1, xs: 3 }} spacing="md" mt="md">
|
||||
<StatTile
|
||||
icon={Train}
|
||||
label="Active schedules"
|
||||
value={isLoading ? "…" : schedules.length}
|
||||
hint="on the board right now"
|
||||
/>
|
||||
<StatTile
|
||||
icon={CalendarDays}
|
||||
label="Open windows"
|
||||
value={isLoading ? "…" : summary.openWindows}
|
||||
hint="accepting bookings"
|
||||
/>
|
||||
<StatTile
|
||||
icon={Package}
|
||||
label="Bookings in play"
|
||||
value={isLoading ? "…" : summary.totalBookings}
|
||||
hint={`${summary.totalWagons} wagons allocated`}
|
||||
/>
|
||||
</SimpleGrid>
|
||||
|
||||
{isLoading ? (
|
||||
<SimpleGrid cols={{ base: 1, md: 2, lg: 3, xl: 4 }} spacing="lg" mt="lg">
|
||||
|
||||
@@ -33,7 +33,6 @@ import {
|
||||
PlayCircle,
|
||||
RefreshCw,
|
||||
Ruler,
|
||||
Train,
|
||||
TrainFront,
|
||||
Weight,
|
||||
XCircle,
|
||||
@@ -540,69 +539,50 @@ export default function BatchScheduleDetailPage() {
|
||||
]}
|
||||
/>
|
||||
|
||||
{/* Hero — clean white */}
|
||||
<Paper
|
||||
radius="xl"
|
||||
p="xl"
|
||||
mt="md"
|
||||
withBorder
|
||||
style={{
|
||||
borderColor: "var(--mantine-color-gray-2)",
|
||||
background: "white",
|
||||
boxShadow: "0 1px 3px rgba(15,23,42,0.04)",
|
||||
}}
|
||||
>
|
||||
<Stack gap="lg">
|
||||
<Stack gap="lg" mt="md">
|
||||
<Group justify="space-between" align="flex-start" wrap="wrap" gap="md">
|
||||
<Group gap="md" align="flex-start" wrap="nowrap" style={{ minWidth: 0 }}>
|
||||
<Button
|
||||
variant="subtle"
|
||||
color="gray"
|
||||
radius="md"
|
||||
px="sm"
|
||||
leftSection={<ArrowLeft size={16} />}
|
||||
onClick={() => navigate("/dashboard/operations/batch-board")}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
<Group gap="sm" wrap="nowrap" style={{ minWidth: 0 }}>
|
||||
<ThemeIcon size={52} radius="md" variant="light" color="green">
|
||||
<Train size={26} />
|
||||
</ThemeIcon>
|
||||
<Stack gap={7} style={{ minWidth: 0 }}>
|
||||
<Group gap="sm" wrap="wrap">
|
||||
<Title order={2} fw={800} style={{ color: "#0f172a", letterSpacing: 0.2 }}>
|
||||
{data.trainNumber ?? data.routeName ?? "Schedule"}
|
||||
</Title>
|
||||
<WindowStatusPill status={data.bookingWindowStatus} />
|
||||
<HeroChip>{data.status}</HeroChip>
|
||||
</Group>
|
||||
<RouteCorridor origin={data.origin} destination={data.destination} />
|
||||
<Group gap={6} wrap="wrap">
|
||||
<HeroChip icon={<CalendarDays size={12} />}>
|
||||
{data.scheduleDate
|
||||
? new Intl.DateTimeFormat("en-GB", {
|
||||
weekday: "short",
|
||||
day: "2-digit",
|
||||
month: "short",
|
||||
year: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
hour12: false,
|
||||
timeZone: "Africa/Addis_Ababa",
|
||||
}).format(new Date(data.scheduleDate)) + " EAT"
|
||||
: "No date"}
|
||||
</HeroChip>
|
||||
{data.locomotive ? (
|
||||
<HeroChip icon={<TrainFront size={12} />}>
|
||||
Loco {data.locomotive.code} · {fmtTons(data.locomotive.maxPullWeightTons)} ·{" "}
|
||||
{data.locomotive.maxTrainLengthMeters} m
|
||||
</HeroChip>
|
||||
) : null}
|
||||
</Group>
|
||||
</Stack>
|
||||
<Stack gap={9} style={{ minWidth: 0 }}>
|
||||
<Group gap="sm" wrap="wrap" align="center">
|
||||
<Button
|
||||
variant="subtle"
|
||||
color="gray"
|
||||
radius="md"
|
||||
px="sm"
|
||||
leftSection={<ArrowLeft size={16} />}
|
||||
onClick={() => navigate("/dashboard/operations/batch-board")}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
<Title order={2} fw={800} style={{ color: "#0f172a", letterSpacing: 0.2 }}>
|
||||
{data.trainNumber ?? data.routeName ?? "Schedule"}
|
||||
</Title>
|
||||
<WindowStatusPill status={data.bookingWindowStatus} />
|
||||
<HeroChip>{data.status}</HeroChip>
|
||||
</Group>
|
||||
</Group>
|
||||
<RouteCorridor origin={data.origin} destination={data.destination} />
|
||||
<Group gap={6} wrap="wrap">
|
||||
<HeroChip icon={<CalendarDays size={12} />}>
|
||||
{data.scheduleDate
|
||||
? new Intl.DateTimeFormat("en-GB", {
|
||||
weekday: "short",
|
||||
day: "2-digit",
|
||||
month: "short",
|
||||
year: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
hour12: false,
|
||||
timeZone: "Africa/Addis_Ababa",
|
||||
}).format(new Date(data.scheduleDate)) + " EAT"
|
||||
: "No date"}
|
||||
</HeroChip>
|
||||
{data.locomotive ? (
|
||||
<HeroChip icon={<TrainFront size={12} />}>
|
||||
Loco {data.locomotive.code} · {fmtTons(data.locomotive.maxPullWeightTons)} ·{" "}
|
||||
{data.locomotive.maxTrainLengthMeters} m
|
||||
</HeroChip>
|
||||
) : null}
|
||||
</Group>
|
||||
</Stack>
|
||||
|
||||
<Group gap="sm">
|
||||
<Button
|
||||
@@ -677,8 +657,7 @@ export default function BatchScheduleDetailPage() {
|
||||
sub={`${data.counts.allocated} allocated · ${data.counts.expired} expired`}
|
||||
/>
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Stack>
|
||||
|
||||
{/* Booking pipeline */}
|
||||
<Paper
|
||||
|
||||
@@ -8,14 +8,12 @@ import {
|
||||
Card,
|
||||
Group,
|
||||
Modal,
|
||||
Paper,
|
||||
Select,
|
||||
SimpleGrid,
|
||||
Stack,
|
||||
Text,
|
||||
TextInput,
|
||||
ThemeIcon,
|
||||
Title,
|
||||
} from "@mantine/core";
|
||||
import { ArrowRight, CalendarClock, Navigation, Send, Train, Weight } from "lucide-react";
|
||||
|
||||
@@ -345,53 +343,24 @@ export default function TrainScheduleV2ListPage() {
|
||||
|
||||
return (
|
||||
<Stack gap="lg">
|
||||
{/* Hero banner */}
|
||||
<Paper
|
||||
radius="xl"
|
||||
p="xl"
|
||||
style={{
|
||||
position: "relative",
|
||||
overflow: "hidden",
|
||||
background: "#ffffff",
|
||||
border: "1px solid var(--mantine-color-gray-2)",
|
||||
boxShadow: "0 1px 3px rgba(15,23,42,0.04)",
|
||||
}}
|
||||
>
|
||||
<Stack gap="lg" style={{ position: "relative" }}>
|
||||
<Group justify="space-between" align="flex-start" wrap="wrap">
|
||||
<Group gap="md" align="center" wrap="nowrap">
|
||||
<ThemeIcon size={56} radius="lg" variant="light" color="green">
|
||||
<Train size={28} />
|
||||
</ThemeIcon>
|
||||
<Stack gap={4}>
|
||||
<Title order={2} fw={700} style={{ color: "#0f172a" }}>
|
||||
Train Schedules
|
||||
</Title>
|
||||
<Text size="sm" c="dimmed" maw={520}>
|
||||
Plan departures, allocate bookings, and dispatch trains across
|
||||
every corridor.
|
||||
</Text>
|
||||
</Stack>
|
||||
</Group>
|
||||
<Button
|
||||
size="md"
|
||||
radius="lg"
|
||||
color="green"
|
||||
leftSection={<Train size={18} />}
|
||||
onClick={() => setCreateOpen(true)}
|
||||
>
|
||||
New schedule
|
||||
</Button>
|
||||
</Group>
|
||||
<Group justify="flex-end">
|
||||
<Button
|
||||
size="md"
|
||||
radius="lg"
|
||||
color="green"
|
||||
leftSection={<Train size={18} />}
|
||||
onClick={() => setCreateOpen(true)}
|
||||
>
|
||||
New schedule
|
||||
</Button>
|
||||
</Group>
|
||||
|
||||
<SimpleGrid cols={{ base: 2, sm: 4 }} spacing="md">
|
||||
<StatTile icon={Train} label="Total trains" value={stats.total} />
|
||||
<StatTile icon={CalendarClock} label="Scheduled" value={stats.scheduled} />
|
||||
<StatTile icon={Send} label="Dispatched" value={stats.dispatched} />
|
||||
<StatTile icon={Weight} label="Planned load" value={`${Math.round(stats.weight)}T`} />
|
||||
</SimpleGrid>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<SimpleGrid cols={{ base: 2, sm: 4 }} spacing="md">
|
||||
<StatTile icon={Train} label="Total trains" value={stats.total} />
|
||||
<StatTile icon={CalendarClock} label="Scheduled" value={stats.scheduled} />
|
||||
<StatTile icon={Send} label="Dispatched" value={stats.dispatched} />
|
||||
<StatTile icon={Weight} label="Planned load" value={`${Math.round(stats.weight)}T`} />
|
||||
</SimpleGrid>
|
||||
|
||||
<Card radius="lg" padding={0} withBorder style={{ borderColor: "var(--mantine-color-gray-2)" }}>
|
||||
<Stack gap={0}>
|
||||
|
||||
Reference in New Issue
Block a user