add loading status management for bookings

This commit is contained in:
Marshal
2026-07-05 19:56:21 +00:00
parent 048dd05292
commit 1433796db0
8 changed files with 222 additions and 11 deletions

View File

@@ -23,6 +23,7 @@ import {
CheckCircle2,
Inbox,
PackageCheck,
PackageX,
Repeat,
Train,
Weight,
@@ -152,6 +153,9 @@ export function ScheduleWorkspacePanel({
// ── Mutations (reuse the existing endpoints) ───────────────────────────────
const assign = useMutation(api.trainScheduling.assignBookings.mutationOptions());
const unassign = useMutation(api.trainScheduling.unassignBooking.mutationOptions());
const setLoading = useMutation(
api.trainScheduling.setLoadingStatus.mutationOptions(),
);
const moveSchedule = useMutation(
api.trainScheduling.moveBookingSchedule.mutationOptions(),
);
@@ -237,6 +241,31 @@ export function ScheduleWorkspacePanel({
);
};
const toggleLoaded = (
bookingId: string,
ref: string,
next: "LOADED" | "UNLOADED",
) => {
setLoading
.mutateAsync({ id: schedule.id, bookingIds: [bookingId], loadingStatus: next })
.then(() => {
toast({
title:
next === "LOADED"
? `${ref} marked loaded`
: `${ref} marked unloaded`,
});
onChanged();
})
.catch((error) =>
toast({
title: "Could not update loading status",
description: apiErrorMessage(error, "Please try again."),
variant: "destructive",
}),
);
};
const doMove = () => {
if (!moveBookingId || !moveTarget) return;
moveSchedule
@@ -268,7 +297,7 @@ export function ScheduleWorkspacePanel({
<div>
<Text fw={700}>Allocation workspace</Text>
<Text size="xs" c="dimmed">
Manually add ready-to-pay bookings, remove, or reassign them
Manually add paid, unassigned bookings, remove, or reassign them
</Text>
</div>
</Group>
@@ -351,13 +380,13 @@ export function ScheduleWorkspacePanel({
<Group align="stretch" gap="lg" grow wrap="wrap">
{/* Pool */}
<PanelColumn
title="Ready to pay"
hint="Accepted · this route & day"
title="Paid · unassigned"
hint="Paid · this route & day · not on a train"
count={pool.length}
accent="#F2A516"
loading={poolQuery.isLoading}
emptyIcon={Inbox}
emptyText="No ready-to-pay bookings waiting for this train."
emptyText="No paid, unassigned bookings waiting for this train."
>
{pool.map((b) => (
<BookingCard
@@ -402,9 +431,52 @@ export function ScheduleWorkspacePanel({
customer={b.customer}
weightTons={b.weightTons}
status={b.status}
loadingStatus={b.wagonAssigned ? b.loadingStatus ?? "UNLOADED" : undefined}
right={
canManage ? (
<Group gap={6} wrap="nowrap" justify="flex-end">
{b.wagonAssigned ? (
<Tooltip
label={
(b.loadingStatus ?? "UNLOADED") === "LOADED"
? "Mark cargo unloaded from wagon"
: "Mark cargo loaded onto wagon"
}
withArrow
>
<Button
size="compact-sm"
variant={
(b.loadingStatus ?? "UNLOADED") === "LOADED"
? "light"
: "filled"
}
color="edr-green"
radius="md"
leftSection={
(b.loadingStatus ?? "UNLOADED") === "LOADED" ? (
<PackageX size={13} />
) : (
<PackageCheck size={13} />
)
}
loading={setLoading.isPending}
onClick={() =>
toggleLoaded(
b.id,
b.reference ?? b.id.slice(0, 8),
(b.loadingStatus ?? "UNLOADED") === "LOADED"
? "UNLOADED"
: "LOADED",
)
}
>
{(b.loadingStatus ?? "UNLOADED") === "LOADED"
? "Unload"
: "Load"}
</Button>
</Tooltip>
) : null}
<Tooltip label="Reassign to another train" withArrow>
<Button
size="compact-sm"
@@ -565,12 +637,14 @@ function BookingCard({
customer,
weightTons,
status,
loadingStatus,
right,
}: {
reference: string;
customer?: string | null;
weightTons?: number | null;
status?: string | null;
loadingStatus?: "LOADED" | "UNLOADED";
right?: React.ReactNode;
}) {
return (
@@ -596,6 +670,16 @@ function BookingCard({
{reference}
</Text>
{status ? <BookingStatusBadge status={status} /> : null}
{loadingStatus ? (
<Badge
size="sm"
radius="sm"
variant={loadingStatus === "LOADED" ? "filled" : "light"}
color={loadingStatus === "LOADED" ? "edr-green" : "gray"}
>
{loadingStatus === "LOADED" ? "Loaded" : "Unloaded"}
</Badge>
) : null}
</Group>
<Group gap={10} align="center" wrap="nowrap">
<Text size="xs" c="dimmed" truncate>