mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-28 02:00:56 +00:00
ui fix
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { useMemo } from "react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import type { ReactNode } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import {
|
||||
Accordion,
|
||||
ActionIcon,
|
||||
Alert,
|
||||
Badge,
|
||||
Box,
|
||||
@@ -25,6 +26,8 @@ import {
|
||||
Boxes,
|
||||
CalendarDays,
|
||||
CheckCircle2,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Clock,
|
||||
FileSignature,
|
||||
Hourglass,
|
||||
@@ -551,22 +554,35 @@ export default function BatchScheduleDetailPage() {
|
||||
[data],
|
||||
);
|
||||
|
||||
// Open today's day, any day with bookings, and pending-contract; else the last day.
|
||||
const openDays = useMemo(() => {
|
||||
if (!dayGroups.length && !data?.pendingContract.bookings.length) return [];
|
||||
const todayEat = new Intl.DateTimeFormat("en-CA", {
|
||||
timeZone: "Africa/Addis_Ababa",
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
}).format(new Date());
|
||||
const open = dayGroups
|
||||
.filter((d) => d.totalBookings > 0 || d.date === todayEat)
|
||||
.map((d) => d.date);
|
||||
if (!open.length && dayGroups.length) open.push(dayGroups[dayGroups.length - 1].date);
|
||||
if (data?.pendingContract.bookings.length) open.push("pending-contract");
|
||||
return open;
|
||||
}, [dayGroups, data]);
|
||||
const todayEat = useMemo(
|
||||
() =>
|
||||
new Intl.DateTimeFormat("en-CA", {
|
||||
timeZone: "Africa/Addis_Ababa",
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
}).format(new Date()),
|
||||
[],
|
||||
);
|
||||
|
||||
// Date-stepper: which day is currently shown. Default to today, else the first
|
||||
// day with bookings, else the first day. Keep the selection if still valid.
|
||||
const [selectedDate, setSelectedDate] = useState<string | null>(null);
|
||||
useEffect(() => {
|
||||
if (!dayGroups.length) return;
|
||||
if (selectedDate && dayGroups.some((d) => d.date === selectedDate)) return;
|
||||
const preferred =
|
||||
dayGroups.find((d) => d.date === todayEat) ??
|
||||
dayGroups.find((d) => d.totalBookings > 0) ??
|
||||
dayGroups[0];
|
||||
setSelectedDate(preferred.date);
|
||||
}, [dayGroups, selectedDate, todayEat]);
|
||||
|
||||
const selectedIndex = Math.max(
|
||||
0,
|
||||
dayGroups.findIndex((d) => d.date === selectedDate),
|
||||
);
|
||||
const selectedDay = dayGroups[selectedIndex];
|
||||
|
||||
const handleRunAllocation = () => {
|
||||
runAllocation
|
||||
@@ -815,79 +831,119 @@ export default function BatchScheduleDetailPage() {
|
||||
</Box>
|
||||
</Group>
|
||||
|
||||
<Accordion
|
||||
multiple
|
||||
defaultValue={openDays}
|
||||
variant="separated"
|
||||
radius="md"
|
||||
mt="md"
|
||||
className="bb-window-accordion"
|
||||
>
|
||||
{dayGroups.map((day) => (
|
||||
<Accordion.Item key={day.date} value={day.date}>
|
||||
<Accordion.Control>
|
||||
<Group justify="space-between" wrap="nowrap" pr="md" gap="sm">
|
||||
<Group gap="sm" wrap="nowrap" style={{ minWidth: 0 }}>
|
||||
<Box
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: 34,
|
||||
height: 34,
|
||||
borderRadius: 10,
|
||||
flexShrink: 0,
|
||||
background: day.totalBookings ? "#FEF1D5" : "var(--mantine-color-gray-0)",
|
||||
border: day.totalBookings
|
||||
? "1px solid #FBD171"
|
||||
: "1px solid var(--mantine-color-gray-2)",
|
||||
color: day.totalBookings ? "#B26C09" : "var(--mantine-color-gray-5)",
|
||||
}}
|
||||
>
|
||||
<CalendarDays size={16} />
|
||||
</Box>
|
||||
<Box style={{ minWidth: 0 }}>
|
||||
<Text fw={700} size="sm" truncate>
|
||||
{day.dateLabel}
|
||||
</Text>
|
||||
<Text size="xs" c="dimmed">
|
||||
{day.totalBookings
|
||||
? `${day.totalBookings} booking${day.totalBookings === 1 ? "" : "s"} · ${day.windows.length} windows`
|
||||
: `${day.windows.length} windows · no bookings`}
|
||||
</Text>
|
||||
</Box>
|
||||
</Group>
|
||||
<Group gap={6} wrap="nowrap">
|
||||
{day.hasIssues ? (
|
||||
<Badge
|
||||
variant="light"
|
||||
color="red"
|
||||
size="sm"
|
||||
leftSection={<AlertTriangle size={10} />}
|
||||
>
|
||||
Issues
|
||||
</Badge>
|
||||
) : null}
|
||||
<WindowCountChips counts={day.counts} />
|
||||
</Group>
|
||||
{dayGroups.length && selectedDay ? (
|
||||
<>
|
||||
{/* Date stepper — page back/forward through each day in the range */}
|
||||
<Group justify="center" align="center" wrap="nowrap" gap="md" mt="md">
|
||||
<ActionIcon
|
||||
variant="light"
|
||||
color="#F2A516"
|
||||
size="xl"
|
||||
radius="xl"
|
||||
aria-label="Previous day"
|
||||
disabled={selectedIndex <= 0}
|
||||
onClick={() => setSelectedDate(dayGroups[selectedIndex - 1]?.date ?? null)}
|
||||
>
|
||||
<ChevronLeft size={20} />
|
||||
</ActionIcon>
|
||||
|
||||
<Paper
|
||||
withBorder
|
||||
radius="xl"
|
||||
px="xl"
|
||||
py="xs"
|
||||
style={{
|
||||
flex: 1,
|
||||
maxWidth: 360,
|
||||
textAlign: "center",
|
||||
background: selectedDay.totalBookings ? "#FEF1D5" : "white",
|
||||
borderColor: selectedDay.totalBookings
|
||||
? "#FBD171"
|
||||
: "var(--mantine-color-gray-2)",
|
||||
}}
|
||||
>
|
||||
<Group justify="center" gap={8} wrap="nowrap">
|
||||
<CalendarDays size={15} color="#B26C09" />
|
||||
<Text
|
||||
fw={800}
|
||||
style={{ color: selectedDay.totalBookings ? "#8A5304" : "#0f172a" }}
|
||||
>
|
||||
{selectedDay.dateLabel}
|
||||
</Text>
|
||||
{selectedDay.date === todayEat ? (
|
||||
<Badge size="xs" variant="light" color="#F2A516">
|
||||
Today
|
||||
</Badge>
|
||||
) : null}
|
||||
</Group>
|
||||
</Accordion.Control>
|
||||
<Accordion.Panel>
|
||||
<Accordion
|
||||
multiple
|
||||
defaultValue={openWindowKeys}
|
||||
variant="separated"
|
||||
radius="md"
|
||||
className="bb-window-accordion"
|
||||
>
|
||||
{day.windows.map((window) => (
|
||||
<WindowAccordionItem key={window.key} window={window} />
|
||||
))}
|
||||
</Accordion>
|
||||
</Accordion.Panel>
|
||||
</Accordion.Item>
|
||||
))}
|
||||
{data.pendingContract.bookings.length ? (
|
||||
<Text size="xs" c="dimmed" mt={2}>
|
||||
{selectedDay.totalBookings
|
||||
? `${selectedDay.totalBookings} booking${selectedDay.totalBookings === 1 ? "" : "s"} · ${selectedDay.windows.length} windows`
|
||||
: `${selectedDay.windows.length} windows · no bookings`}
|
||||
</Text>
|
||||
</Paper>
|
||||
|
||||
<ActionIcon
|
||||
variant="light"
|
||||
color="#F2A516"
|
||||
size="xl"
|
||||
radius="xl"
|
||||
aria-label="Next day"
|
||||
disabled={selectedIndex >= dayGroups.length - 1}
|
||||
onClick={() => setSelectedDate(dayGroups[selectedIndex + 1]?.date ?? null)}
|
||||
>
|
||||
<ChevronRight size={20} />
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
|
||||
<Group justify="space-between" align="center" mt="sm">
|
||||
<Text size="xs" c="dimmed">
|
||||
Day {selectedIndex + 1} of {dayGroups.length}
|
||||
</Text>
|
||||
<Group gap={6} wrap="nowrap">
|
||||
{selectedDay.hasIssues ? (
|
||||
<Badge
|
||||
variant="light"
|
||||
color="red"
|
||||
size="sm"
|
||||
leftSection={<AlertTriangle size={10} />}
|
||||
>
|
||||
Issues
|
||||
</Badge>
|
||||
) : null}
|
||||
<WindowCountChips counts={selectedDay.counts} />
|
||||
</Group>
|
||||
</Group>
|
||||
|
||||
<Accordion
|
||||
key={selectedDay.date}
|
||||
multiple
|
||||
defaultValue={openWindowKeys}
|
||||
variant="separated"
|
||||
radius="md"
|
||||
mt="md"
|
||||
className="bb-window-accordion"
|
||||
>
|
||||
{selectedDay.windows.map((window) => (
|
||||
<WindowAccordionItem key={window.key} window={window} />
|
||||
))}
|
||||
</Accordion>
|
||||
</>
|
||||
) : (
|
||||
<Text size="sm" c="dimmed" ta="center" py="lg">
|
||||
No batch windows for this schedule.
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{data.pendingContract.bookings.length ? (
|
||||
<Accordion
|
||||
multiple
|
||||
defaultValue={["pending-contract"]}
|
||||
variant="separated"
|
||||
radius="md"
|
||||
mt="md"
|
||||
className="bb-window-accordion"
|
||||
>
|
||||
<Accordion.Item value="pending-contract">
|
||||
<Accordion.Control>
|
||||
<Group justify="space-between" wrap="nowrap" pr="md" gap="sm">
|
||||
@@ -927,8 +983,8 @@ export default function BatchScheduleDetailPage() {
|
||||
<BookingTable bookings={data.pendingContract.bookings} />
|
||||
</Accordion.Panel>
|
||||
</Accordion.Item>
|
||||
) : null}
|
||||
</Accordion>
|
||||
</Accordion>
|
||||
) : null}
|
||||
</Paper>
|
||||
|
||||
{/* Train composition */}
|
||||
|
||||
Reference in New Issue
Block a user