mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 14:38:12 +00:00
feat: implement wagon transfer management modals and page
- Add TransferFulfillModal for fulfilling wagon transfer requests. - Create TransferRequestFormModal for filing new wagon transfer requests. - Introduce TransferCloseShortModal for closing requests that cannot be fully fulfilled. - Develop WagonTransfersPage to manage and display wagon transfer requests. - Implement utility functions for handling wagon transfer request data and UI components. - Enhance UI with Mantine components for better user experience.
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import type { PaginatedResponse } from "@edr/types";
|
||||
|
||||
import { QUERY_KEYS } from "@/constants/QUERY_KEYS";
|
||||
import type { FleetResourceSlug } from "@/pages/fleet/config/resources";
|
||||
import type { BookingDetail } from "@/types/booking";
|
||||
@@ -208,6 +210,7 @@ import {
|
||||
type CreateTransferRequestPayload,
|
||||
type BulkFulfillResult,
|
||||
type TransferHistory,
|
||||
type TransferRequestListFilter,
|
||||
} from "./wagon.service";
|
||||
import { warehouseService } from "./warehouse.service";
|
||||
|
||||
@@ -1719,14 +1722,14 @@ export const api = {
|
||||
|
||||
wagonTransferRequests: {
|
||||
list: endpoint<
|
||||
{ status?: WagonTransferRequest["status"] },
|
||||
WagonTransferRequest[]
|
||||
{ filter?: TransferRequestListFilter },
|
||||
PaginatedResponse<WagonTransferRequest>
|
||||
>(
|
||||
"wagonTransferRequests",
|
||||
"list",
|
||||
({ status }) =>
|
||||
wagonTransferRequestService.list(status).then((r) => r.data),
|
||||
({ status }) => ["wagonTransferRequests", "list", status ?? "ALL"],
|
||||
({ filter }) =>
|
||||
wagonTransferRequestService.list(filter).then((r) => r.data),
|
||||
({ filter }) => ["wagonTransferRequests", "list", filter ?? {}],
|
||||
),
|
||||
|
||||
getById: endpoint<{ id: string }, WagonTransferRequest>(
|
||||
@@ -1774,19 +1777,47 @@ export const api = {
|
||||
() => [["wagonTransferRequests"]],
|
||||
),
|
||||
|
||||
history: endpoint<void, TransferHistory>(
|
||||
closeShort: endpoint<{ id: string; note?: string }, WagonTransferRequest>(
|
||||
"wagonTransferRequests",
|
||||
"history",
|
||||
() => wagonTransferRequestService.myHistory().then((r) => r.data),
|
||||
() => ["wagonTransferRequests", "history", "mine"],
|
||||
"closeShort",
|
||||
({ id, note }) =>
|
||||
wagonTransferRequestService.closeShort(id, note).then((r) => r.data),
|
||||
undefined,
|
||||
() => [["wagonTransferRequests"]],
|
||||
),
|
||||
|
||||
historyAll: endpoint<{ userId?: string }, TransferHistory>(
|
||||
history: endpoint<{ page?: number; pageSize?: number }, TransferHistory>(
|
||||
"wagonTransferRequests",
|
||||
"history",
|
||||
({ page, pageSize }) =>
|
||||
wagonTransferRequestService.myHistory(page, pageSize).then((r) => r.data),
|
||||
({ page, pageSize }) => [
|
||||
"wagonTransferRequests",
|
||||
"history",
|
||||
"mine",
|
||||
page ?? 1,
|
||||
pageSize ?? 20,
|
||||
],
|
||||
),
|
||||
|
||||
historyAll: endpoint<
|
||||
{ userId?: string; page?: number; pageSize?: number },
|
||||
TransferHistory
|
||||
>(
|
||||
"wagonTransferRequests",
|
||||
"historyAll",
|
||||
({ userId }) =>
|
||||
wagonTransferRequestService.allHistory(userId).then((r) => r.data),
|
||||
({ userId }) => ["wagonTransferRequests", "history", "all", userId ?? ""],
|
||||
({ userId, page, pageSize }) =>
|
||||
wagonTransferRequestService
|
||||
.allHistory(userId, page, pageSize)
|
||||
.then((r) => r.data),
|
||||
({ userId, page, pageSize }) => [
|
||||
"wagonTransferRequests",
|
||||
"history",
|
||||
"all",
|
||||
userId ?? "",
|
||||
page ?? 1,
|
||||
pageSize ?? 20,
|
||||
],
|
||||
),
|
||||
},
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Freight } from "@edr/types";
|
||||
import type { Freight, PaginatedResponse } from "@edr/types";
|
||||
|
||||
import { api as apiClient } from "../auth/http";
|
||||
|
||||
@@ -109,10 +109,15 @@ export interface WagonTransferRequest {
|
||||
toYardId: string;
|
||||
wagonTypeId: string;
|
||||
quantity: number;
|
||||
/** How many have actually moved so far — OCC delivers in instalments. */
|
||||
fulfilledQuantity: number;
|
||||
status: Freight.WagonTransferRequestStatus;
|
||||
requestedByUserId: string | null;
|
||||
fulfilledByUserId: string | null;
|
||||
/** When the LAST instalment ran, not necessarily the full count. */
|
||||
fulfilledAt: string | null;
|
||||
closedShortAt?: string | null;
|
||||
closedShortByUserId?: string | null;
|
||||
/** Why the wagons are needed — required for new requests, shown on the queue. */
|
||||
reason?: string | null;
|
||||
note: string | null;
|
||||
@@ -132,7 +137,7 @@ export interface CreateTransferRequestPayload {
|
||||
note?: string;
|
||||
}
|
||||
|
||||
/** Bulk accept-and-execute result: what ran, what stayed PENDING and why. */
|
||||
/** Bulk accept-and-execute result: what ran, what stayed open and why. */
|
||||
export interface BulkFulfillResult {
|
||||
fulfilled: WagonTransferRequest[];
|
||||
skipped: Array<{ id: string; reason: string }>;
|
||||
@@ -142,20 +147,52 @@ export interface BulkFulfillResult {
|
||||
export interface TransferHistory {
|
||||
requests: WagonTransferRequest[];
|
||||
movements: WagonMovementRecord[];
|
||||
meta: {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
requestsTotal: number;
|
||||
movementsTotal: number;
|
||||
totalPages: number;
|
||||
};
|
||||
}
|
||||
|
||||
/** Desk list filters — `status` may be a comma-separated set ("open" tab). */
|
||||
export interface TransferRequestListFilter {
|
||||
status?: string;
|
||||
fromYardId?: string;
|
||||
toYardId?: string;
|
||||
wagonTypeId?: string;
|
||||
search?: string;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
}
|
||||
|
||||
const listQuery = (filter: TransferRequestListFilter = {}): string => {
|
||||
const params = new URLSearchParams();
|
||||
for (const [key, value] of Object.entries(filter)) {
|
||||
if (value !== undefined && value !== null && value !== '') {
|
||||
params.set(key, String(value));
|
||||
}
|
||||
}
|
||||
const qs = params.toString();
|
||||
return qs ? `?${qs}` : '';
|
||||
};
|
||||
|
||||
export const wagonTransferRequestService = {
|
||||
list: (status?: Freight.WagonTransferRequestStatus) =>
|
||||
apiClient.get<WagonTransferRequest[]>(
|
||||
`/wagon-transfer-requests${status ? `?status=${status}` : ''}`,
|
||||
list: (filter: TransferRequestListFilter = {}) =>
|
||||
apiClient.get<PaginatedResponse<WagonTransferRequest>>(
|
||||
`/wagon-transfer-requests${listQuery(filter)}`,
|
||||
),
|
||||
/** The caller's own history (both roles: requests they filed and fulfilled). */
|
||||
myHistory: () =>
|
||||
apiClient.get<TransferHistory>('/wagon-transfer-requests/history'),
|
||||
/** Admin: any/all staff's history (optional userId filter). */
|
||||
allHistory: (userId?: string) =>
|
||||
myHistory: (page = 1, pageSize = 20) =>
|
||||
apiClient.get<TransferHistory>(
|
||||
`/wagon-transfer-requests/history/all${userId ? `?userId=${userId}` : ''}`,
|
||||
`/wagon-transfer-requests/history?page=${page}&pageSize=${pageSize}`,
|
||||
),
|
||||
/** Admin: any/all staff's history (optional userId filter). */
|
||||
allHistory: (userId?: string, page = 1, pageSize = 20) =>
|
||||
apiClient.get<TransferHistory>(
|
||||
`/wagon-transfer-requests/history/all?page=${page}&pageSize=${pageSize}` +
|
||||
`${userId ? `&userId=${userId}` : ''}`,
|
||||
),
|
||||
getById: (id: string) =>
|
||||
apiClient.get<WagonTransferRequest>(`/wagon-transfer-requests/${id}`),
|
||||
@@ -176,4 +213,10 @@ export const wagonTransferRequestService = {
|
||||
apiClient.post<WagonTransferRequest>(
|
||||
`/wagon-transfer-requests/${id}/cancel`,
|
||||
),
|
||||
/** OCC: end the request short — the source yard has no more to give. */
|
||||
closeShort: (id: string, note?: string) =>
|
||||
apiClient.post<WagonTransferRequest>(
|
||||
`/wagon-transfer-requests/${id}/close-short`,
|
||||
{ note },
|
||||
),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user