diff --git a/apps/edr-freight-web/backoffice/src/pages/trainScheduling/BatchBoardPage.tsx b/apps/edr-freight-web/backoffice/src/pages/trainScheduling/BatchBoardPage.tsx
index 4ee2a7d96..32ef990d9 100644
--- a/apps/edr-freight-web/backoffice/src/pages/trainScheduling/BatchBoardPage.tsx
+++ b/apps/edr-freight-web/backoffice/src/pages/trainScheduling/BatchBoardPage.tsx
@@ -1,12 +1,13 @@
import { useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
import {
+ ActionIcon,
Alert,
Box,
Button,
Card,
- Container,
Group,
+ Menu,
Paper,
RingProgress,
Select,
@@ -21,7 +22,9 @@ import {
ArrowRight,
CalendarClock,
CalendarDays,
+ Eye,
Inbox,
+ MoreHorizontal,
Package,
Ruler,
Train,
@@ -31,7 +34,7 @@ import {
import type { ColumnDef } from "@edr/ui-common";
import { DataTable, DataTableFooter, usePagination } from "@edr/ui-common";
-import Breadcrumbs from "@/components/ui/Breadcrumbs";
+import { KpiStrip, PageContainer, PageHeader } from "@/components/page";
import FleetToolbar from "@/components/fleet/FleetToolbar";
import { useFleetViewMode } from "@/components/fleet/useFleetViewMode";
import {
@@ -40,7 +43,7 @@ import {
totalBookingCount,
WindowStatusPill,
} from "@/components/trainScheduling/batchVisuals";
-import { RouteCorridor, StatTile } from "@/components/trainScheduling/scheduleVisuals";
+import { RouteCorridor } from "@/components/trainScheduling/scheduleVisuals";
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
import { FREIGHT_BRAND, FREIGHT_BRAND_DARK } from "@/theme/freight-brand";
import { useBatchBoard } from "@/hooks/trainScheduling/useTrainScheduling";
@@ -365,7 +368,7 @@ function CardSkeleton() {
export default function BatchBoardPage() {
const navigate = useNavigate();
- const { data, isLoading, isFetching, refetch } = useBatchBoard();
+ const { data, isLoading, isError, isFetching, refetch } = useBatchBoard();
const { viewMode, setViewMode } = useFleetViewMode("batch-board");
const { pagination, setPagination } = usePagination({ pageSize: 10 });
const [search, setSearch] = useState("");
@@ -549,72 +552,69 @@ export default function BatchBoardPage() {
header: "",
meta: { headerClassName, cellClassName: `${cellClassName} whitespace-nowrap` },
cell: ({ row }) => (
-
- }
- onClick={() =>
- navigate(`/dashboard/operations/batch-board/${row.original.scheduleId}`)
- }
- >
- View windows
-
+ e.stopPropagation()}>
+
),
},
];
}, [navigate]);
- const tableStatus = isLoading ? "loading" : "success";
+ const tableStatus = isLoading ? "loading" : isError ? "error" : "success";
return (
-
-
+
+ void refetch()}>
+ Refresh
+
+ }
+ />
-
-
-
-
-
+
-
+
+ navigate(`/dashboard/operations/batch-board/${schedule.scheduleId}`)
+ }
+ error={
+ isError
+ ? {
+ message: "Failed to load the batch board.",
+ onRetry: () => void refetch(),
+ }
+ : undefined
+ }
emptyMessage="No active schedules"
pagination={{
pageIndex: pagination.pageIndex,
@@ -688,7 +699,6 @@ export default function BatchBoardPage() {
borderRadius: 20,
background: "white",
border: "1px solid var(--mantine-color-gray-2)",
- boxShadow: "0 4px 12px rgba(15,23,42,0.06)",
}}
>
@@ -711,18 +721,6 @@ export default function BatchBoardPage() {
)}
-
-
-
-
-
+
);
}
diff --git a/apps/edr-freight-web/backoffice/src/pages/trainScheduling/TrainScheduleV2ListPage.tsx b/apps/edr-freight-web/backoffice/src/pages/trainScheduling/TrainScheduleV2ListPage.tsx
index 6a2e77287..7d5c49270 100644
--- a/apps/edr-freight-web/backoffice/src/pages/trainScheduling/TrainScheduleV2ListPage.tsx
+++ b/apps/edr-freight-web/backoffice/src/pages/trainScheduling/TrainScheduleV2ListPage.tsx
@@ -3,10 +3,12 @@ import { useNavigate } from "react-router-dom";
import { isAxiosError } from "axios";
import type { ColumnDef } from "@edr/ui-common";
import {
+ ActionIcon,
Box,
Button,
Card,
Group,
+ Menu,
Modal,
Select,
SimpleGrid,
@@ -15,16 +17,25 @@ import {
TextInput,
ThemeIcon,
} from "@mantine/core";
-import { ArrowRight, CalendarClock, Navigation, Send, Train, Weight } from "lucide-react";
+import {
+ ArrowRight,
+ Ban,
+ CalendarClock,
+ Eye,
+ MoreHorizontal,
+ Navigation,
+ Send,
+ Train,
+ Weight,
+} from "lucide-react";
+import { KpiStrip, PageContainer, PageHeader } from "@/components/page";
import FleetToolbar from "@/components/fleet/FleetToolbar";
import { useFleetViewMode } from "@/components/fleet/useFleetViewMode";
import { FreightTypeBadge } from "@/components/trainScheduling/ScheduleStatusBadge";
import {
RouteCorridor,
- StatTile,
StatusPill,
- scheduleBrand,
} from "@/components/trainScheduling/scheduleVisuals";
import RuleEngineListFooter from "@/components/ruleEngine/RuleEngineListFooter";
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
@@ -253,61 +264,65 @@ export default function TrainScheduleV2ListPage() {
id: "actions",
header: "Actions",
meta: { headerClassName, cellClassName: `${cellClassName} whitespace-nowrap` },
- cell: ({ row }) => (
-
- }
- onClick={() =>
- navigate(`/dashboard/operations/train-scheduling-v2/${row.original.id}`)
- }
- >
- Open
-
- {["DISPATCHED", "ARRIVED"].includes(row.original.status) ? (
- }
- onClick={() =>
- navigate(
- `/dashboard/operations/train-scheduling-v2/${row.original.id}/track`,
- )
- }
- >
- Track
-
- ) : null}
- {["DRAFT", "SCHEDULED"].includes(row.original.status) ? (
-
- ) : null}
-
- ),
+ cell: ({ row }) => {
+ const schedule = row.original;
+ return (
+ e.stopPropagation()}>
+
+
+ );
+ },
},
];
}, [navigate, cancel.isPending, cancel, toast]);
@@ -340,65 +355,33 @@ export default function TrainScheduleV2ListPage() {
: "success";
return (
-
-
- }
- onClick={() => setCreateOpen(true)}
- >
- New schedule
-
-
+
+ } onClick={() => setCreateOpen(true)}>
+ New schedule
+
+ }
+ />
-
-
-
-
-
-
+
-
+
setCreateOpen(true)}
viewMode={viewMode}
onViewModeChange={setViewMode}
filters={
@@ -442,6 +425,17 @@ export default function TrainScheduleV2ListPage() {
columns={columns}
data={paged}
status={tableStatus}
+ onRowClick={(schedule) =>
+ navigate(`/dashboard/operations/train-scheduling-v2/${schedule.id}`)
+ }
+ error={
+ schedulesQuery.isError
+ ? {
+ message: "Failed to load train schedules.",
+ onRetry: () => void schedulesQuery.refetch(),
+ }
+ : undefined
+ }
emptyMessage="No train schedules found"
pagination={{
pageIndex: pagination.pageIndex,
@@ -554,13 +548,13 @@ export default function TrainScheduleV2ListPage() {
-
-
+
);
}
@@ -613,31 +607,15 @@ function ScheduleCard({
const canTrack = ["DISPATCHED", "ARRIVED"].includes(schedule.status);
return (
{
- e.currentTarget.style.boxShadow = scheduleBrand.shadowSm;
- e.currentTarget.style.transform = "translateY(-2px)";
- }}
- onMouseLeave={(e) => {
- e.currentTarget.style.boxShadow = "";
- e.currentTarget.style.transform = "";
- }}
+ className="cursor-pointer overflow-hidden transition-[transform,border-color] duration-150 hover:-translate-y-0.5 hover:border-edr-primary!"
>
- {/* accent strip */}
-
-
+
diff --git a/apps/edr-freight-web/backoffice/src/pages/trainScheduling/TrainSchedulingGlobalRulesPage.tsx b/apps/edr-freight-web/backoffice/src/pages/trainScheduling/TrainSchedulingGlobalRulesPage.tsx
index 65d3e4c21..e72dc5d41 100644
--- a/apps/edr-freight-web/backoffice/src/pages/trainScheduling/TrainSchedulingGlobalRulesPage.tsx
+++ b/apps/edr-freight-web/backoffice/src/pages/trainScheduling/TrainSchedulingGlobalRulesPage.tsx
@@ -1,6 +1,7 @@
import { useEffect, useState } from "react";
-import { Button, Card, Group, NumberInput, Stack, Text, Title } from "@mantine/core";
+import { Button, Card, Group, NumberInput, Stack } from "@mantine/core";
+import { PageContainer, PageHeader } from "@/components/page";
import { trainSchedulingService } from "@/services/trainScheduling.service";
import { useToast } from "@/hooks/use-toast";
import type { TrainSchedulingGlobalRules } from "@/types/trainScheduling";
@@ -44,15 +45,13 @@ export default function TrainSchedulingGlobalRulesPage() {
};
return (
-
-
- Train scheduling rules
-
- Global limits applied when previewing and assigning bookings to trains.
-
-
+
+
-
+
- void handleSave()}>
+ void handleSave()}>
Save rules
-
+
);
}