Files
edr-platform/apps/edr-freight-web/backoffice/src/pages/fleet/config/resources.ts
yaschalew d080f4cf98 fix
2026-06-20 10:14:03 +03:00

512 lines
20 KiB
TypeScript

import { Freight } from "@edr/types";
import type { ColumnFormat, FormFieldDef } from "@/pages/ruleEngine/config/resources";
export type FleetResourceSlug =
| "locomotives"
| "trains"
| "wagons"
| "containers"
| "cargoes"
| "vehicles"
| "drivers";
export const FLEET_SELECT_NONE = "__none__";
import type { WagonListFilters } from "@/services/wagon.service";
export type FleetListFilters = WagonListFilters;
export type FleetDynamicOptions =
| "wagonTypes"
| "containerTypes"
| "cargoTypes"
| "wagons"
| "containers"
| "yards";
export interface FleetResourceColumn {
id: string;
header: string;
accessorKey: string;
format?: ColumnFormat | "statusBadge";
size?: number;
}
export interface FleetFormFieldDef extends FormFieldDef {
dynamicOptions?: FleetDynamicOptions;
noneOption?: boolean;
}
export interface FleetListFilterDef {
key: "status" | "currentYardId" | "wagonTypeId" | "trainId";
label: string;
options?: Array<{ value: string; label: string }>;
allLabel?: string;
dynamicOptions?: FleetDynamicOptions;
}
export interface FleetResourceConfig {
slug: FleetResourceSlug;
label: string;
subtitle: string;
basePath: string;
addLabel: string;
entityLabel: string;
searchPlaceholder: string;
supportsSearch: boolean;
/** Server-side list filters (e.g. wagon status / readiness). */
listFilters?: FleetListFilterDef[];
columns: FleetResourceColumn[];
formFields: FleetFormFieldDef[];
emptyValues: Record<string, unknown>;
removeAction: "delete" | "decommission";
removeActionLabel?: string;
removeConfirmMessage?: string;
removeSuccessMessage?: string;
detailPath?: string;
cardTitleKey?: string;
cardCodeKey?: string;
cardSubtitleKey?: string;
searchKeys: string[];
}
export const FLEET_BASE_PATH_BY_SLUG: Record<FleetResourceSlug, string> = {
locomotives: "/dashboard/locomotives",
trains: "/dashboard/trains",
wagons: "/dashboard/wagons",
containers: "/dashboard/containers",
cargoes: "/dashboard/cargoes",
vehicles: "/dashboard/vehicles",
drivers: "/dashboard/drivers",
};
const LOCOMOTIVE_TYPE_OPTIONS = [
{ label: "Diesel", value: "DIESEL" },
{ label: "Electric", value: "ELECTRIC" },
];
const LOCOMOTIVE_STATUS_OPTIONS = [
{ label: "Available", value: "AVAILABLE" },
{ label: "Maintenance", value: "MAINTENANCE" },
{ label: "Assigned", value: "ASSIGNED" },
{ label: "Out of service", value: "OUT_OF_SERVICE" },
];
const WAGON_STATUS_OPTIONS = [
{ label: "Available", value: Freight.WagonStatus.Available },
{ label: "Assigned", value: Freight.WagonStatus.Assigned },
{ label: "Maintenance", value: Freight.WagonStatus.Maintenance },
{ label: "Retired", value: Freight.WagonStatus.Retired },
];
const VEHICLE_TYPE_OPTIONS = [
{ label: "Truck", value: "TRUCK" },
{ label: "Van", value: "VAN" },
{ label: "Car", value: "CAR" },
{ label: "Bus", value: "BUS" },
{ label: "Trailer", value: "TRAILER" },
{ label: "Tanker", value: "TANKER" },
{ label: "Flatbed", value: "FLATBED" },
];
const FUEL_TYPE_OPTIONS = [
{ label: "Petrol", value: "PETROL" },
{ label: "Diesel", value: "DIESEL" },
{ label: "Electric", value: "ELECTRIC" },
{ label: "Hybrid", value: "HYBRID" },
];
const VEHICLE_STATUS_OPTIONS = [
{ label: "Active", value: "ACTIVE" },
{ label: "Maintenance", value: "MAINTENANCE" },
{ label: "Retired", value: "RETIRED" },
{ label: "Out of service", value: "OUT_OF_SERVICE" },
];
const DRIVER_STATUS_OPTIONS = [
{ label: "Active", value: "ACTIVE" },
{ label: "Inactive", value: "INACTIVE" },
{ label: "Suspended", value: "SUSPENDED" },
{ label: "On leave", value: "ON_LEAVE" },
];
export const FLEET_RESOURCES: FleetResourceConfig[] = [
{
slug: "locomotives",
label: "Locomotives",
subtitle: "Manage locomotive master data used by train scheduling and fleet operations",
basePath: "/dashboard/locomotives",
addLabel: "Add Locomotive",
entityLabel: "Locomotive",
searchPlaceholder: "Search locomotives…",
supportsSearch: true,
removeAction: "decommission",
removeActionLabel: "Decommission",
removeConfirmMessage: "Decommission this locomotive?",
removeSuccessMessage: "Locomotive decommissioned",
cardTitleKey: "name",
cardCodeKey: "code",
listFilters: [
{
key: "status",
label: "Status",
allLabel: "All statuses",
options: LOCOMOTIVE_STATUS_OPTIONS,
},
{
key: "currentYardId",
label: "Current Yard",
allLabel: "All yards",
dynamicOptions: "yards",
},
],
cardSubtitleKey: "currentYard",
searchKeys: ["code", "name", "locomotiveType", "status", "currentYardId"],
columns: [
{ id: "code", header: "Code", accessorKey: "code", format: "code" },
{ id: "name", header: "Name", accessorKey: "name" },
{ id: "locomotiveType", header: "Type", accessorKey: "locomotiveType" },
{ id: "currentYard", header: "Current Yard", accessorKey: "currentYard", format: "entityLabel" },
{ id: "status", header: "Status", accessorKey: "status", format: "statusBadge" },
{ id: "maxPullWeightTons", header: "Max pull (tons)", accessorKey: "maxPullWeightTons", format: "number" },
{ id: "maxTrainLengthMeters", header: "Max length (m)", accessorKey: "maxTrainLengthMeters", format: "number" },
],
formFields: [
{ name: "code", label: "Code", type: "text", required: true },
{ name: "name", label: "Name", type: "text" },
{ name: "locomotiveType", label: "Locomotive type", type: "select", required: true, options: LOCOMOTIVE_TYPE_OPTIONS },
{ name: "status", label: "Status", type: "select", required: true, options: LOCOMOTIVE_STATUS_OPTIONS },
{ name: "currentYardId", label: "Current Yard", type: "select", dynamicOptions: "yards" },
{ name: "maxPullWeightTons", label: "Max pulling weight (tons)", type: "number", required: true },
{ name: "maxTrainLengthMeters", label: "Max train length (meters)", type: "number", required: true },
{ name: "powerKw", label: "Power (kW)", type: "number" },
{ name: "tractionForceKn", label: "Traction force (kN)", type: "number" },
{ name: "maxSpeedKmh", label: "Max speed (km/h)", type: "number" },
],
emptyValues: {
code: "",
name: "",
locomotiveType: "DIESEL",
status: "AVAILABLE",
currentYardId: "",
maxPullWeightTons: 0,
maxTrainLengthMeters: 760,
powerKw: "",
tractionForceKn: "",
maxSpeedKmh: "",
},
},
{
slug: "trains",
label: "Trains",
subtitle: "Manage train master data independently from train scheduling",
basePath: "/dashboard/trains",
addLabel: "Add Train",
entityLabel: "Train",
searchPlaceholder: "Search trains…",
supportsSearch: true,
removeAction: "delete",
detailPath: "/dashboard/trains/:id",
cardTitleKey: "trainName",
cardCodeKey: "code",
cardSubtitleKey: "trainNumber",
searchKeys: ["code", "trainNumber", "trainName", "status"],
columns: [
{ id: "code", header: "Code", accessorKey: "code", format: "code" },
{ id: "trainNumber", header: "Number", accessorKey: "trainNumber" },
{ id: "trainName", header: "Name", accessorKey: "trainName" },
{ id: "capacityTons", header: "Capacity (tons)", accessorKey: "capacityTons", format: "number" },
{ id: "status", header: "Status", accessorKey: "status", format: "statusBadge" },
],
formFields: [
{ name: "code", label: "Code", type: "text", required: true },
{ name: "capacityTons", label: "Capacity (tons)", type: "number", required: true },
{ name: "trainNumber", label: "Train number", type: "text" },
{ name: "trainName", label: "Train name", type: "text" },
{ name: "locomotiveNumber", label: "Locomotive number", type: "text" },
{ name: "status", label: "Status", type: "text" },
{ name: "notes", label: "Notes", type: "textarea" },
{ name: "remarks", label: "Remarks", type: "textarea" },
],
emptyValues: {
code: "",
capacityTons: 0,
trainNumber: "",
trainName: "",
locomotiveNumber: "",
status: "AVAILABLE",
notes: "",
remarks: "",
},
},
{
slug: "wagons",
label: "Wagons",
subtitle: "Manage wagon master data. Operational scheduling uses train schedules separately",
basePath: "/dashboard/wagons",
addLabel: "Add Wagon",
entityLabel: "Wagon",
searchPlaceholder: "Search wagons…",
supportsSearch: true,
removeAction: "delete",
listFilters: [
{
key: "status",
label: "Status",
allLabel: "All statuses",
options: WAGON_STATUS_OPTIONS,
},
{
key: "currentYardId",
label: "Current Yard",
allLabel: "All yards",
dynamicOptions: "yards",
},
],
cardTitleKey: "wagonNumber",
cardSubtitleKey: "currentYard",
searchKeys: ["wagonNumber", "wagonTypeId", "trainId", "status", "currentYardId"],
columns: [
{ id: "wagonNumber", header: "Number", accessorKey: "wagonNumber", format: "code" },
{ id: "wagonTypeId", header: "Type", accessorKey: "wagonTypeId", format: "entityLabel" },
{ id: "maxPayloadWeight", header: "Max payload", accessorKey: "maxPayloadWeight", format: "number" },
{ id: "currentYard", header: "Current Yard", accessorKey: "currentYard", format: "entityLabel" },
{ id: "status", header: "Status", accessorKey: "status", format: "statusBadge" },
],
formFields: [
{ name: "wagonNumber", label: "Wagon number", type: "text", required: true },
{ name: "wagonTypeId", label: "Wagon type", type: "select", required: true, dynamicOptions: "wagonTypes" },
{ name: "tareWeight", label: "Tare weight", type: "number", required: true },
{ name: "maxPayloadWeight", label: "Max payload weight", type: "number", required: true },
{ name: "currentYardId", label: "Current Yard", type: "select", dynamicOptions: "yards" },
{ name: "status", label: "Status", type: "select", required: true, options: WAGON_STATUS_OPTIONS },
{ name: "notes", label: "Notes", type: "textarea" },
],
emptyValues: {
wagonNumber: "",
wagonTypeId: "",
tareWeight: 0,
maxPayloadWeight: 0,
currentYardId: "",
status: Freight.WagonStatus.Available,
notes: "",
},
},
{
slug: "containers",
label: "Containers",
subtitle: "Manage container master data and wagon assignments",
basePath: "/dashboard/containers",
addLabel: "Add Container",
entityLabel: "Container",
searchPlaceholder: "Search containers…",
supportsSearch: true,
removeAction: "delete",
cardTitleKey: "containerNumber",
cardSubtitleKey: "status",
searchKeys: ["containerNumber", "containerTypeId", "wagonId", "status"],
columns: [
{ id: "containerNumber", header: "Number", accessorKey: "containerNumber", format: "code" },
{ id: "containerTypeId", header: "Type", accessorKey: "containerTypeId", format: "entityLabel" },
{ id: "wagonId", header: "Wagon", accessorKey: "wagonId", format: "entityLabel" },
{ id: "maxGrossWeight", header: "Max gross", accessorKey: "maxGrossWeight", format: "number" },
{ id: "status", header: "Status", accessorKey: "status", format: "statusBadge" },
],
formFields: [
{ name: "containerNumber", label: "Container number", type: "text", required: true },
{ name: "containerTypeId", label: "Container type", type: "select", required: true, dynamicOptions: "containerTypes" },
{ name: "wagonId", label: "Wagon", type: "select", dynamicOptions: "wagons", noneOption: true },
{ name: "position", label: "Position", type: "number" },
{ name: "tareWeight", label: "Tare weight", type: "number", required: true },
{ name: "maxGrossWeight", label: "Max gross weight", type: "number", required: true },
{ name: "sealNumber", label: "Seal number", type: "text" },
{ name: "status", label: "Status", type: "text" },
],
emptyValues: {
containerNumber: "",
containerTypeId: "",
wagonId: "",
position: "",
tareWeight: 0,
maxGrossWeight: 0,
sealNumber: "",
status: "AVAILABLE",
},
},
{
slug: "cargoes",
label: "Cargoes",
subtitle: "Manage cargo records linked to containers",
basePath: "/dashboard/cargoes",
addLabel: "Add Cargo",
entityLabel: "Cargo",
searchPlaceholder: "Search cargoes…",
supportsSearch: true,
removeAction: "delete",
cardTitleKey: "cargoReference",
cardSubtitleKey: "status",
searchKeys: ["cargoReference", "description", "containerId", "status"],
columns: [
{ id: "cargoReference", header: "Reference", accessorKey: "cargoReference", format: "code" },
{ id: "cargoTypeId", header: "Cargo type", accessorKey: "cargoTypeId", format: "entityLabel" },
{ id: "containerId", header: "Container", accessorKey: "containerId", format: "entityLabel" },
{ id: "quantity", header: "Quantity", accessorKey: "quantity", format: "number" },
{ id: "weight", header: "Weight", accessorKey: "weight", format: "number" },
{ id: "status", header: "Status", accessorKey: "status", format: "statusBadge" },
],
formFields: [
{ name: "cargoReference", label: "Cargo reference", type: "text", required: true },
{ name: "shipmentId", label: "Shipment ID", type: "text", required: true },
{ name: "containerId", label: "Container", type: "select", required: true, dynamicOptions: "containers" },
{ name: "cargoTypeId", label: "Cargo type", type: "select", dynamicOptions: "cargoTypes", noneOption: true },
{ name: "description", label: "Description", type: "textarea" },
{ name: "quantity", label: "Quantity", type: "number", required: true },
{ name: "weight", label: "Weight", type: "number", required: true },
{ name: "volume", label: "Volume", type: "number" },
{ name: "status", label: "Status", type: "text" },
],
emptyValues: {
cargoReference: "",
shipmentId: "",
containerId: "",
cargoTypeId: "",
description: "",
quantity: 0,
weight: 0,
volume: "",
status: "PENDING",
},
},
{
slug: "vehicles",
label: "Vehicles",
subtitle: "Manage vehicle master data for fleet operations",
basePath: "/dashboard/vehicles",
addLabel: "Add Vehicle",
entityLabel: "Vehicle",
searchPlaceholder: "Search vehicles…",
supportsSearch: true,
removeAction: "delete",
cardTitleKey: "plateNumber",
cardCodeKey: "plateNumber",
cardSubtitleKey: "status",
listFilters: [
{
key: "status",
label: "Status",
allLabel: "All statuses",
options: VEHICLE_STATUS_OPTIONS,
},
],
searchKeys: ["plateNumber", "registrationNumber", "manufacturer", "model", "vehicleType", "status"],
columns: [
{ id: "plateNumber", header: "Plate Number", accessorKey: "plateNumber", format: "code", size: 130 },
{ id: "registrationNumber", header: "Registration", accessorKey: "registrationNumber", format: "code", size: 130 },
{ id: "registrationNumber", header: "Manufacturer", accessorKey: "manufacturer", format: "code", size: 130 },
{ id: "model", header: "Model", accessorKey: "model",format: "code", size: 120 },
{ id: "vehicleType", header: "Type", accessorKey: "vehicleType",format: "code", size: 100 },
{ id: "year", header: "Year", accessorKey: "year", format: "code", size: 80 },
{ id: "fuelType", header: "Fuel Type", accessorKey: "fuelType", format: "code", size: 110 },
{ id: "capacity", header: "Capacity (tons)", accessorKey: "capacity", format: "code", size: 130 },
{ id: "status", header: "Status", accessorKey: "status", format: "statusBadge", size: 100 },
],
formFields: [
{ name: "plateNumber", label: "Plate Number", type: "text", required: true },
{ name: "vehicleType", label: "Vehicle Type", type: "select", required: true, options: VEHICLE_TYPE_OPTIONS },
{ name: "manufacturer", label: "Manufacturer", type: "text", required: true },
{ name: "model", label: "Model", type: "text", required: true },
{ name: "year", label: "Year", type: "number", required: true },
{ name: "fuelType", label: "Fuel Type", type: "select", required: true, options: FUEL_TYPE_OPTIONS },
{ name: "capacity", label: "Capacity", type: "number", required: true },
{ name: "status", label: "Status", type: "select", required: true, options: VEHICLE_STATUS_OPTIONS },
{ name: "description", label: "Description", type: "textarea" },
],
emptyValues: {
plateNumber: "",
vehicleType: "TRUCK",
manufacturer: "",
model: "",
year: new Date().getFullYear(),
fuelType: "DIESEL",
capacity: 0,
status: "ACTIVE",
description: "",
},
},
{
slug: "drivers",
label: "Drivers",
subtitle: "Manage driver records and licenses",
basePath: "/dashboard/drivers",
addLabel: "Add Driver",
entityLabel: "Driver",
searchPlaceholder: "Search drivers…",
supportsSearch: true,
removeAction: "delete",
cardTitleKey: "firstName",
cardCodeKey: "licenseNumber",
cardSubtitleKey: "status",
listFilters: [
{
key: "status",
label: "Status",
allLabel: "All statuses",
options: DRIVER_STATUS_OPTIONS,
},
],
searchKeys: ["firstName", "lastName", "email", "phoneNumber", "licenseNumber", "status"],
columns: [
{ id: "licenseNumber", header: "License Number", accessorKey: "licenseNumber", format: "code", size: 140 },
{ id: "firstName", header: "First Name", accessorKey: "firstName",format: "code", size: 120 },
{ id: "lastName", header: "Last Name", accessorKey: "lastName", format: "code", size: 120 },
{ id: "email", header: "Email", accessorKey: "email",format: "code", size: 180 },
{ id: "phoneNumber", header: "Phone", accessorKey: "phoneNumber",format: "code", size: 120 },
{ id: "licenseExpiryDate", header: "License Expiry", accessorKey: "licenseExpiryDate",format: "code", size: 130 },
{ id: "status", header: "Status", accessorKey: "status", format: "statusBadge", size: 100 },
],
formFields: [
{ name: "licenseNumber", label: "License Number", type: "text", required: true },
{ name: "firstName", label: "First Name", type: "text", required: true },
{ name: "lastName", label: "Last Name", type: "text", required: true },
{ name: "email", label: "Email", type: "email", required: true },
{ name: "phoneNumber", label: "Phone Number", type: "text", required: true },
{ name: "dateOfBirth", label: "Date of Birth", type: "date", required: true },
{ name: "licenseExpiryDate", label: "License Expiry Date", type: "date", required: true },
{ name: "status", label: "Status", type: "select", required: true, options: DRIVER_STATUS_OPTIONS },
{ name: "vehicleTypesAuthorized", label: "Authorized Vehicle Types", type: "multiselect", options: VEHICLE_TYPE_OPTIONS },
{ name: "address", label: "Address", type: "textarea" },
{ name: "emergencyContact", label: "Emergency Contact", type: "text" },
{ name: "notes", label: "Notes", type: "textarea" },
],
emptyValues: {
licenseNumber: "",
firstName: "",
lastName: "",
email: "",
phoneNumber: "",
dateOfBirth: "",
licenseExpiryDate: "",
status: "ACTIVE",
vehicleTypesAuthorized: [],
address: "",
emergencyContact: "",
notes: "",
},
},
];
export const getFleetResource = (slug: string): FleetResourceConfig | undefined =>
FLEET_RESOURCES.find((resource) => resource.slug === slug);
export const getFleetSlugFromPath = (pathname: string): FleetResourceSlug | undefined => {
const normalized = pathname.toLowerCase();
return FLEET_RESOURCES.find((resource) => normalized === resource.basePath.toLowerCase())?.slug;
};
export const getFleetRouteMeta = () =>
FLEET_RESOURCES.map((resource) => ({
prefix: resource.basePath,
meta: { title: resource.label, subtitle: resource.subtitle },
}));