diff --git a/apps/edr-freight-api/src/migrations/1810000000002-AddVehicleCodeAndPlates.ts b/apps/edr-freight-api/src/migrations/1810000000002-AddVehicleCodeAndPlates.ts new file mode 100644 index 000000000..a2a1aae17 --- /dev/null +++ b/apps/edr-freight-api/src/migrations/1810000000002-AddVehicleCodeAndPlates.ts @@ -0,0 +1,35 @@ +import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm'; + +export class AddVehicleCodeAndPlates1810000000002 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + const hasCode = await queryRunner.hasColumn('freight.vehicles', 'code'); + if (!hasCode) { + await queryRunner.addColumn( + 'freight.vehicles', + new TableColumn({ name: 'code', type: 'varchar', isNullable: true }), + ); + } + + const hasPower = await queryRunner.hasColumn('freight.vehicles', 'power_plate_no'); + if (!hasPower) { + await queryRunner.addColumn( + 'freight.vehicles', + new TableColumn({ name: 'power_plate_no', type: 'varchar', isNullable: true }), + ); + } + + const hasTrailer = await queryRunner.hasColumn('freight.vehicles', 'trailer_plate_no'); + if (!hasTrailer) { + await queryRunner.addColumn( + 'freight.vehicles', + new TableColumn({ name: 'trailer_plate_no', type: 'varchar', isNullable: true }), + ); + } + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.dropColumn('freight.vehicles', 'trailer_plate_no'); + await queryRunner.dropColumn('freight.vehicles', 'power_plate_no'); + await queryRunner.dropColumn('freight.vehicles', 'code'); + } +} diff --git a/apps/edr-freight-api/src/modules/vehicles/dto/create-vehicle.dto.ts b/apps/edr-freight-api/src/modules/vehicles/dto/create-vehicle.dto.ts index 8a2ad8519..55e12047b 100644 --- a/apps/edr-freight-api/src/modules/vehicles/dto/create-vehicle.dto.ts +++ b/apps/edr-freight-api/src/modules/vehicles/dto/create-vehicle.dto.ts @@ -37,4 +37,16 @@ export class CreateVehicleDto { @IsOptional() @IsString() assignedDriverName?: string; + + @IsOptional() + @IsString() + code?: string; + + @IsOptional() + @IsString() + powerPlateNo?: string; + + @IsOptional() + @IsString() + trailerPlateNo?: string; } diff --git a/apps/edr-freight-api/src/modules/vehicles/entities/vehicle.entity.ts b/apps/edr-freight-api/src/modules/vehicles/entities/vehicle.entity.ts index 005118b0a..713edfc64 100644 --- a/apps/edr-freight-api/src/modules/vehicles/entities/vehicle.entity.ts +++ b/apps/edr-freight-api/src/modules/vehicles/entities/vehicle.entity.ts @@ -62,4 +62,13 @@ export class Vehicle extends BaseEntity { @Column({ name: 'assigned_driver_name', nullable: true }) assignedDriverName?: string; + + @Column({ name: 'code', nullable: true }) + code?: string; + + @Column({ name: 'power_plate_no', nullable: true }) + powerPlateNo?: string; + + @Column({ name: 'trailer_plate_no', nullable: true }) + trailerPlateNo?: string; } diff --git a/apps/edr-freight-web/backoffice/src/pages/fleet/config/vehicles.ts b/apps/edr-freight-web/backoffice/src/pages/fleet/config/vehicles.ts index 689d278a2..3e220040f 100644 --- a/apps/edr-freight-web/backoffice/src/pages/fleet/config/vehicles.ts +++ b/apps/edr-freight-web/backoffice/src/pages/fleet/config/vehicles.ts @@ -47,7 +47,10 @@ export const vehiclesConfig: FleetResourceConfig = { ], searchKeys: ["plateNumber", "registrationNumber", "manufacturer", "model", "vehicleType", "status"], columns: [ + { id: "code", header: "Code", accessorKey: "code", format: "code", size: 110 }, { id: "plateNumber", header: "Plate Number", accessorKey: "plateNumber", format: "code", size: 130 }, + { id: "powerPlateNo", header: "Power Plate No", accessorKey: "powerPlateNo", format: "code", size: 140 }, + { id: "trailerPlateNo", header: "Trailer Plate No", accessorKey: "trailerPlateNo", format: "code", size: 140 }, { id: "registrationNumber", header: "Registration", accessorKey: "registrationNumber", format: "code", size: 140 }, { id: "manufacturer", header: "Manufacturer", accessorKey: "manufacturer", format: "code", size: 140 }, { id: "model", header: "Model", accessorKey: "model", format: "code", size: 120 }, @@ -59,7 +62,10 @@ export const vehiclesConfig: FleetResourceConfig = { { id: "status", header: "Status", accessorKey: "status", format: "statusBadge", size: 100 }, ], formFields: [ + { name: "code", label: "Code", type: "text" }, { name: "plateNumber", label: "Plate Number", type: "text", required: true }, + { name: "powerPlateNo", label: "Power Plate No", type: "text" }, + { name: "trailerPlateNo", label: "Trailer Plate No", type: "text" }, { 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 }, @@ -70,7 +76,10 @@ export const vehiclesConfig: FleetResourceConfig = { { name: "description", label: "Description", type: "textarea" }, ], emptyValues: { + code: "", plateNumber: "", + powerPlateNo: "", + trailerPlateNo: "", vehicleType: "TRUCK", manufacturer: "", model: "", diff --git a/apps/edr-freight-web/backoffice/src/pages/operations/FirstMilePage.tsx b/apps/edr-freight-web/backoffice/src/pages/operations/FirstMilePage.tsx index c7b7f5f8a..ccd94137e 100644 --- a/apps/edr-freight-web/backoffice/src/pages/operations/FirstMilePage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/operations/FirstMilePage.tsx @@ -75,7 +75,11 @@ const FILTER_OPTIONS: { value: StatusFilter; label: string }[] = [ const vehicleLabel = (record: FirstMileRecord) => { if (!record.vehicle) return null; const v = record.vehicle; - return `${v.manufacturer} ${v.model} (${v.plateNumber})`; + const parts = [`${v.manufacturer} ${v.model}`, v.plateNumber]; + if (v.code) parts.unshift(v.code); + const plates = [v.powerPlateNo, v.trailerPlateNo].filter(Boolean).join(" / "); + if (plates) parts.push(plates); + return parts.join(" · "); }; const isAssigned = (record: FirstMileRecord) => Boolean(record.vehicleId); @@ -346,10 +350,13 @@ const FirstMilePage = () => { const vehicleOptions = useMemo( () => - (Array.isArray(vehiclesData) ? vehiclesData : []).map((v) => ({ - value: v.id, - label: `${v.manufacturer} ${v.model} (${v.plateNumber})`, - })), + (Array.isArray(vehiclesData) ? vehiclesData : []).map((v) => { + const parts = [`${v.manufacturer} ${v.model}`, v.plateNumber]; + if (v.code) parts.unshift(v.code); + const plates = [v.powerPlateNo, v.trailerPlateNo].filter(Boolean).join(" / "); + if (plates) parts.push(plates); + return { value: v.id, label: parts.join(" · ") }; + }), [vehiclesData], ); diff --git a/apps/edr-freight-web/backoffice/src/pages/operations/LastMilePage.tsx b/apps/edr-freight-web/backoffice/src/pages/operations/LastMilePage.tsx index a5ad12c5b..7a68e447b 100644 --- a/apps/edr-freight-web/backoffice/src/pages/operations/LastMilePage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/operations/LastMilePage.tsx @@ -71,7 +71,11 @@ const FILTER_OPTIONS: { value: StatusFilter; label: string }[] = [ const vehicleLabel = (record: LastMileRecord) => { if (!record.vehicle) return null; const v = record.vehicle; - return `${v.manufacturer} ${v.model} (${v.plateNumber})`; + const parts = [`${v.manufacturer} ${v.model}`, v.plateNumber]; + if (v.code) parts.unshift(v.code); + const plates = [v.powerPlateNo, v.trailerPlateNo].filter(Boolean).join(" / "); + if (plates) parts.push(plates); + return parts.join(" · "); }; const isAssigned = (record: LastMileRecord) => Boolean(record.vehicleId); @@ -313,10 +317,13 @@ const LastMilePage = () => { const vehicleOptions = useMemo( () => - (Array.isArray(vehiclesData) ? vehiclesData : []).map((v) => ({ - value: v.id, - label: `${v.manufacturer} ${v.model} (${v.plateNumber})`, - })), + (Array.isArray(vehiclesData) ? vehiclesData : []).map((v) => { + const parts = [`${v.manufacturer} ${v.model}`, v.plateNumber]; + if (v.code) parts.unshift(v.code); + const plates = [v.powerPlateNo, v.trailerPlateNo].filter(Boolean).join(" / "); + if (plates) parts.push(plates); + return { value: v.id, label: parts.join(" · ") }; + }), [vehiclesData], ); diff --git a/apps/edr-freight-web/backoffice/src/services/first-mile.service.ts b/apps/edr-freight-web/backoffice/src/services/first-mile.service.ts index b16287124..23f5261c8 100644 --- a/apps/edr-freight-web/backoffice/src/services/first-mile.service.ts +++ b/apps/edr-freight-web/backoffice/src/services/first-mile.service.ts @@ -29,6 +29,9 @@ export interface FirstMileVehicle { plateNumber: string; manufacturer: string; model: string; + code?: string | null; + powerPlateNo?: string | null; + trailerPlateNo?: string | null; } export interface FirstMileRecord { diff --git a/apps/edr-freight-web/backoffice/src/services/last-mile.service.ts b/apps/edr-freight-web/backoffice/src/services/last-mile.service.ts index 5d8b60df2..6872d300e 100644 --- a/apps/edr-freight-web/backoffice/src/services/last-mile.service.ts +++ b/apps/edr-freight-web/backoffice/src/services/last-mile.service.ts @@ -29,6 +29,9 @@ export interface LastMileVehicle { plateNumber: string; manufacturer: string; model: string; + code?: string | null; + powerPlateNo?: string | null; + trailerPlateNo?: string | null; } export interface LastMileRecord { diff --git a/apps/edr-freight-web/backoffice/src/services/vehicles.service.ts b/apps/edr-freight-web/backoffice/src/services/vehicles.service.ts index d5f0308f9..b9d5129e3 100644 --- a/apps/edr-freight-web/backoffice/src/services/vehicles.service.ts +++ b/apps/edr-freight-web/backoffice/src/services/vehicles.service.ts @@ -26,6 +26,9 @@ export interface Vehicle { capacity: number; status: VehicleStatus; description?: string | null; + code?: string | null; + powerPlateNo?: string | null; + trailerPlateNo?: string | null; createdAt: string; updatedAt: string; }