diff --git a/apps/edr-freight-api/src/modules/last-mile/dto/set-vehicles.dto.ts b/apps/edr-freight-api/src/modules/last-mile/dto/set-vehicles.dto.ts new file mode 100644 index 000000000..40426b663 --- /dev/null +++ b/apps/edr-freight-api/src/modules/last-mile/dto/set-vehicles.dto.ts @@ -0,0 +1,8 @@ +import { IsArray, IsUUID } from 'class-validator'; + +/** Replace the full set of vehicles assigned to a last-mile delivery. */ +export class SetVehiclesDto { + @IsArray() + @IsUUID('4', { each: true }) + vehicleIds!: string[]; +} diff --git a/apps/edr-freight-api/src/modules/last-mile/last-mile.controller.ts b/apps/edr-freight-api/src/modules/last-mile/last-mile.controller.ts index 9ad5a00bf..047d6b3e9 100644 --- a/apps/edr-freight-api/src/modules/last-mile/last-mile.controller.ts +++ b/apps/edr-freight-api/src/modules/last-mile/last-mile.controller.ts @@ -18,6 +18,7 @@ import { TrainSchedulingManage, TrainSchedulingView } from '../../common/booking import { CreateLastMileDto } from './dto/create-last-mile.dto'; import { UpdateLastMileDto } from './dto/update-last-mile.dto'; import { AllocateLastMileContainersDto } from './dto/allocate-containers.dto'; +import { SetVehiclesDto } from './dto/set-vehicles.dto'; import { LastMileStatus } from './entities/last-mile.entity'; import { LastMileService } from './last-mile.service'; import { LastMileInvoiceService } from './last-mile-invoice.service'; @@ -136,4 +137,14 @@ export class LastMileController { ) { return this.lastMileService.allocateContainers(id, dto.allocations); } + + @Post(':id/vehicles') + @TrainSchedulingManage() + @ApiOperation({ summary: 'Set the vehicles assigned to a last-mile delivery (multi-truck)' }) + async setVehicles( + @Param('id', ParseUUIDPipe) id: string, + @Body() dto: SetVehiclesDto, + ) { + return this.lastMileService.setVehicles(id, dto.vehicleIds); + } } diff --git a/apps/edr-freight-api/src/modules/last-mile/last-mile.module.ts b/apps/edr-freight-api/src/modules/last-mile/last-mile.module.ts index 32b688069..e639e4dfd 100644 --- a/apps/edr-freight-api/src/modules/last-mile/last-mile.module.ts +++ b/apps/edr-freight-api/src/modules/last-mile/last-mile.module.ts @@ -8,6 +8,7 @@ import { NotificationsModule } from '../notifications/notifications.module'; import { VehiclesModule } from '../vehicles/vehicles.module'; import { LastMile } from './entities/last-mile.entity'; import { LastMileContainerAllocation } from './entities/last-mile-container-allocation.entity'; +import { LastMileVehicleAssignment } from './entities/last-mile-vehicle-assignment.entity'; import { LastMileController } from './last-mile.controller'; import { LastMileInvoiceService } from './last-mile-invoice.service'; import { LastMileRepository } from './last-mile.repository'; @@ -15,7 +16,7 @@ import { LastMileService } from './last-mile.service'; @Module({ imports: [ - TypeOrmModule.forFeature([LastMile, LastMileContainerAllocation]), + TypeOrmModule.forFeature([LastMile, LastMileContainerAllocation, LastMileVehicleAssignment]), BillingModule, forwardRef(() => BookingsModule), VehiclesModule, diff --git a/apps/edr-freight-api/src/modules/last-mile/last-mile.service.ts b/apps/edr-freight-api/src/modules/last-mile/last-mile.service.ts index 884a02aae..744aa7df1 100644 --- a/apps/edr-freight-api/src/modules/last-mile/last-mile.service.ts +++ b/apps/edr-freight-api/src/modules/last-mile/last-mile.service.ts @@ -10,6 +10,7 @@ import { CreateLastMileDto } from './dto/create-last-mile.dto'; import { UpdateLastMileDto } from './dto/update-last-mile.dto'; import { LastMile, LastMileStatus } from './entities/last-mile.entity'; import { LastMileContainerAllocation } from './entities/last-mile-container-allocation.entity'; +import { LastMileVehicleAssignment } from './entities/last-mile-vehicle-assignment.entity'; import { LastMileRepository } from './last-mile.repository'; import { InvoiceEventPayload } from '../billing/billing.service'; import { OnEvent } from '@nestjs/event-emitter'; @@ -149,8 +150,9 @@ export class LastMileService { const [data, total] = await this.lastMileRepository.findAndCount({ where, relations: { - booking: { company: true, serviceType: true, originYard: true, destinationYard: true, cargoType: true }, + booking: { company: true, serviceType: true, originYard: true, destinationYard: true, cargoType: true, bookingContainers: true }, vehicle: true, + vehicleAssignments: { vehicle: true }, }, order: { [sortBy]: sortOrder }, skip: (page - 1) * pageSize, @@ -171,8 +173,9 @@ export class LastMileService { async findById(id: string): Promise { const record = await this.lastMileRepository.findById(id, { relations: { - booking: { company: true, serviceType: true, originYard: true, destinationYard: true, cargoType: true }, + booking: { company: true, serviceType: true, originYard: true, destinationYard: true, cargoType: true, bookingContainers: true }, vehicle: true, + vehicleAssignments: { vehicle: true }, }, }); @@ -353,6 +356,70 @@ export class LastMileService { await this.vehiclesService.releaseIfUnused(vehicleIds); } + /** + * Replace the full set of vehicles serving a last-mile delivery (multi-truck). + * Diffs against the current junction rows, syncing availability + audit history + * for each added/removed vehicle. The first vehicle is mirrored onto the legacy + * `vehicleId` column for back-compat with single-vehicle readers. + */ + async setVehicles(id: string, vehicleIds: string[]): Promise { + const existing = await this.findById(id); + const desired = [...new Set(vehicleIds.filter(Boolean))]; + + const manager = this.dataSource.manager; + const current = await manager.find(LastMileVehicleAssignment, { + where: { lastMileId: id }, + }); + const currentIds = current.map((a) => a.vehicleId); + const currentSet = new Set(currentIds); + const desiredSet = new Set(desired); + const added = desired.filter((v) => !currentSet.has(v)); + const removed = currentIds.filter((v) => !desiredSet.has(v)); + + await this.dataSource.transaction(async (tx) => { + if (removed.length) { + await tx.delete(LastMileVehicleAssignment, { + lastMileId: id, + vehicleId: In(removed), + }); + } + for (const vehicleId of added) { + await tx.insert(LastMileVehicleAssignment, { lastMileId: id, vehicleId }); + } + }); + + // Legacy primary vehicle = first of the set (null when cleared). + await this.lastMileRepository.update(id, { vehicleId: desired[0] ?? null } as any); + + const bookingRef = await this.resolveBookingRef(existing); + for (const vehicleId of added) { + await this.vehiclesService.setAvailability(vehicleId, VehicleAvailability.BUSY); + void this.notifyDriverAssignment(vehicleId, existing); + const info = await this.vehicleInfo(vehicleId); + await this.history.record({ + eventType: FleetEventType.MILE_VEHICLE_ASSIGNED, + vehicleId, + lastMileId: id, + driverId: info.driverId, + label: existing.status, + metadata: { mile: 'LAST', bookingRef, vehiclePlate: info.plate, driverName: info.driverName }, + }); + } + for (const vehicleId of removed) { + await this.vehiclesService.releaseIfUnused([vehicleId]); + const info = await this.vehicleInfo(vehicleId); + await this.history.record({ + eventType: FleetEventType.MILE_VEHICLE_RELEASED, + vehicleId, + lastMileId: id, + driverId: info.driverId, + metadata: { mile: 'LAST', bookingRef, vehiclePlate: info.plate, driverName: info.driverName }, + }); + } + + return this.findById(id); + } + private async notifyDriverAssignment(vehicleId: string, record: LastMile): Promise { try { const vehicle = await this.vehiclesService.findById(vehicleId); diff --git a/apps/edr-freight-api/src/modules/notifications/notifications.module.ts b/apps/edr-freight-api/src/modules/notifications/notifications.module.ts index 4e56c8b70..16d598eb0 100644 --- a/apps/edr-freight-api/src/modules/notifications/notifications.module.ts +++ b/apps/edr-freight-api/src/modules/notifications/notifications.module.ts @@ -8,6 +8,11 @@ import { EmailClientService } from "./email-client.service"; import { EmailNotificationStrategy } from "./strategies/notification.email.strategy"; import { SmsNotificationStrategy } from "./strategies/notification.sms.strategy"; +// Fall back to a sane broker URL so an unset RABBITMQ_URL can't produce +// `urls: [undefined]` (which crashes amqp-connection-manager on 'heartbeat'). +const RABBITMQ_URL = + process.env.RABBITMQ_URL ?? process.env.PAYMENT_RABBITMQ_URL ?? "amqp://localhost:5672"; + @Module({ imports: [ ConfigModule, @@ -16,7 +21,7 @@ import { SmsNotificationStrategy } from "./strategies/notification.sms.strategy" name: "SMS_SERVICE", transport: Transport.RMQ, options: { - urls: [process.env.RABBITMQ_URL as string], + urls: [RABBITMQ_URL], queue: process.env.SMS_QUEUE ?? "sms_queue", queueOptions: { durable: true }, }, @@ -25,7 +30,7 @@ import { SmsNotificationStrategy } from "./strategies/notification.sms.strategy" name: "EMAIL_SERVICE", transport: Transport.RMQ, options: { - urls: [process.env.RABBITMQ_URL as string], + urls: [RABBITMQ_URL], queue: process.env.EMAIL_QUEUE ?? "email_queue", queueOptions: { durable: true }, }, diff --git a/apps/edr-freight-api/src/seed/marshalling-demo-trains.seeder.ts b/apps/edr-freight-api/src/seed/marshalling-demo-trains.seeder.ts index 2d3c47c26..53d6c9eec 100644 --- a/apps/edr-freight-api/src/seed/marshalling-demo-trains.seeder.ts +++ b/apps/edr-freight-api/src/seed/marshalling-demo-trains.seeder.ts @@ -3,6 +3,7 @@ import { WagonStatus } from '@edr/types'; import { DataSource } from 'typeorm'; import { Booking } from '../modules/bookings/entities/booking.entity'; +import { Company } from '../modules/companies/entities/company.entity'; import { Locomotive } from '../modules/locomotives/entities/locomotive.entity'; import { CargoType } from '../modules/rule-engine/entities/cargo-type.entity'; import { ServiceType } from '../modules/rule-engine/entities/service-type.entity'; @@ -116,6 +117,11 @@ export class MarshallingDemoTrainsSeeder { ? await warehouseZoneRepo.findOne({ where: { yardId: warehouseYard.id } }) : null; + // bookings.company_id is NOT NULL — reuse any seeded company for the demo. + const company = await this.dataSource + .getRepository(Company) + .findOne({ where: {}, order: { createdAt: 'ASC' } }); + const missing = [ !djiboutiYard ? 'Djibouti yard' : '', !ethiopiaYard ? 'Ethiopia yard' : '', @@ -124,6 +130,7 @@ export class MarshallingDemoTrainsSeeder { !warehouse ? 'INDODE_OPEN warehouse' : '', !warehouseYard ? 'warehouse yard' : '', !warehouseZone ? 'warehouse zone' : '', + !company ? 'company' : '', ].filter(Boolean); if (missing.length) { this.logger.warn(`Cannot seed marshalling demo trains, missing: ${missing.join(', ')}`); @@ -141,6 +148,7 @@ export class MarshallingDemoTrainsSeeder { warehouse: warehouse!, warehouseYard: warehouseYard!, warehouseZone: warehouseZone!, + company: company!, }); if (created) seeded += 1; } @@ -164,6 +172,7 @@ export class MarshallingDemoTrainsSeeder { warehouse: Warehouse; warehouseYard: WarehouseYard; warehouseZone: WarehouseZone; + company: Company; }, ): Promise { const bookingRepo = this.dataSource.getRepository(Booking); @@ -231,6 +240,7 @@ export class MarshallingDemoTrainsSeeder { const booking = await bookingRepo.save( bookingRepo.create({ reference: bookingReference, + companyId: refs.company.id, originYardId: originYard.id, destinationYardId: destinationYard.id, serviceTypeId: refs.serviceType.id, 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 2ec99f496..5f1790f42 100644 --- a/apps/edr-freight-web/backoffice/src/pages/operations/FirstMilePage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/operations/FirstMilePage.tsx @@ -755,30 +755,6 @@ const FirstMilePage = () => { meta: { headerClassName, cellClassName }, cell: ({ row }) => customerName(row.original), }, - { - id: "pickup", - header: "Pickup", - meta: { headerClassName, cellClassName }, - cell: ({ row }) => pickupLocation(row.original), - }, - { - id: "destination", - header: "Destination", - meta: { headerClassName, cellClassName }, - cell: ({ row }) => destinationYardName(row.original), - }, - { - id: "cargo", - header: "Cargo", - meta: { headerClassName, cellClassName }, - cell: ({ row }) => cargoDesc(row.original), - }, - { - id: "advancedPayment", - header: "Advanced Payment", - meta: { headerClassName, cellClassName }, - cell: ({ row }) => formatPrice(row.original.advancedPayment), - }, { id: "postPayment", header: "Post Payment", @@ -789,13 +765,8 @@ const FirstMilePage = () => { id: "vehicle", header: "Vehicle", meta: { headerClassName, cellClassName }, - cell: ({ row }) => vehicleLabel(row.original) ?? , - }, - { - id: "estimatedKm", - header: "Est. Distance (KM)", - meta: { headerClassName, cellClassName }, - cell: ({ row }) => row.original.estimatedKm != null ? row.original.estimatedKm : , + cell: ({ row }) => + vehicleLabel(row.original) ?? Unassigned, }, { id: "exactKm", @@ -849,16 +820,6 @@ const FirstMilePage = () => { return {meta.label}; }, }, - { - id: "assignment", - header: "Assignment", - meta: { headerClassName, cellClassName }, - cell: ({ row }) => ( - - {isAssigned(row.original) ? "Assigned" : "Unassigned"} - - ), - }, { id: "actions", header: "Actions", 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 2fb05b0de..4fce74364 100644 --- a/apps/edr-freight-web/backoffice/src/pages/operations/LastMilePage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/operations/LastMilePage.tsx @@ -3,18 +3,21 @@ import { ArrowRight, Eye, MoreHorizontal, + Plus, Printer, Receipt, RefreshCw, Ruler, Trash, Truck, + X, } from "lucide-react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import type { ColumnDef } from "@edr/ui-common"; import { DataTable, DataTableFooter, usePagination } from "@edr/ui-common"; import { ActionIcon, + Alert, Badge, Box, Button, @@ -24,6 +27,7 @@ import { Group, Menu, Modal, + MultiSelect, NumberInput, ScrollArea, Select, @@ -92,6 +96,32 @@ const vehicleLabel = (record: LastMileRecord) => { return parts.join(" · "); }; +/** One vehicle (with trailer) carries two containers. */ +const CONTAINERS_PER_VEHICLE = 2; +const containerCount = (record: LastMileRecord) => + (record.booking?.bookingContainers ?? []).reduce( + (sum, c) => sum + (Number(c.quantity) || 0), + 0, + ); +/** Trucks needed for a booking = ceil(containers / 2). 0 when no container data. */ +const requiredVehicles = (record: LastMileRecord) => { + const n = containerCount(record); + return n > 0 ? Math.ceil(n / CONTAINERS_PER_VEHICLE) : 0; +}; + +/** Column summary: the primary vehicle, plus a "+N more" when multi-truck. */ +const vehiclesSummary = (record: LastMileRecord) => { + const assigns = record.vehicleAssignments ?? []; + if (assigns.length > 1) { + const first = assigns[0]?.vehicle; + const firstLabel = first + ? [first.code, first.plateNumber].filter(Boolean).join(" · ") + : "Vehicle"; + return `${firstLabel} +${assigns.length - 1} more`; + } + return vehicleLabel(record); +}; + const isAssigned = (record: LastMileRecord) => Boolean(record.vehicleId); const fmtStamp = (iso?: string | null) => { @@ -422,13 +452,14 @@ const LastMilePage = () => { const [tripSlipOpen, setTripSlipOpen] = useState(false); const [tripSlipRecord, setTripSlipRecord] = useState(null); const [activeId, setActiveId] = useState(null); - const [vehicleValue, setVehicleValue] = useState(null); + // Multi-vehicle assign: one entry per selected vehicle (null = empty picker). + const [vehicleValues, setVehicleValues] = useState<(string | null)[]>([null]); // 2-step "Assign Mile" accept modal (arrival queue → vehicle) const [acceptOpen, setAcceptOpen] = useState(false); const [acceptStep, setAcceptStep] = useState<1 | 2>(1); const [selectedArrivalItems, setSelectedArrivalItems] = useState([]); - const [acceptVehicleValue, setAcceptVehicleValue] = useState(null); + const [acceptVehicleValues, setAcceptVehicleValues] = useState([]); const [arrivalSearch, setArrivalSearch] = useState(""); const [distanceOpen, setDistanceOpen] = useState(false); @@ -516,6 +547,18 @@ const LastMilePage = () => { }, }); + const setVehiclesMutation = useMutation({ + mutationFn: ({ id, vehicleIds }: { id: string; vehicleIds: string[] }) => + lastMileService.setVehicles(id, vehicleIds), + onSuccess: () => { + void qc.invalidateQueries({ queryKey: QUERY_KEYS.LAST_MILE.ROOT }); + void qc.invalidateQueries({ queryKey: ["vehicles"] }); + }, + onError: () => { + toast({ title: "Assign failed", variant: "destructive" }); + }, + }); + const updateDistanceMutation = useMutation({ mutationFn: ({ id, exactKm, remainingPayment }: { id: string; exactKm: number; remainingPayment?: number }) => lastMileService.update(id, { exactKm, ...(remainingPayment != null && { remainingPayment }) }), @@ -576,12 +619,12 @@ const LastMilePage = () => { }, [arrivalQueue, arrivalSearch, existingLastMileBookingIds]); const acceptMutation = useMutation({ - mutationFn: async ({ items, vehicleId }: { items: ArrivalQueueItem[]; vehicleId: string | null }) => { + mutationFn: async ({ items, vehicleIds }: { items: ArrivalQueueItem[]; vehicleIds: string[] }) => { const created = await Promise.all( items.map((item) => lastMileService.accept(item.bookingReference).then((r) => r.data)), ); - if (vehicleId) { - await Promise.all(created.map((record) => lastMileService.update(record.id, { vehicleId }))); + if (vehicleIds.length) { + await Promise.all(created.map((record) => lastMileService.setVehicles(record.id, vehicleIds))); } return created; }, @@ -603,7 +646,7 @@ const LastMilePage = () => { setAcceptOpen(true); setAcceptStep(1); setSelectedArrivalItems([]); - setAcceptVehicleValue(null); + setAcceptVehicleValues([]); setArrivalSearch(""); }; @@ -611,7 +654,7 @@ const LastMilePage = () => { setAcceptOpen(false); setAcceptStep(1); setSelectedArrivalItems([]); - setAcceptVehicleValue(null); + setAcceptVehicleValues([]); setArrivalSearch(""); }; @@ -625,7 +668,7 @@ const LastMilePage = () => { const handleAcceptConfirm = () => { if (!selectedArrivalItems.length) return; - acceptMutation.mutate({ items: selectedArrivalItems, vehicleId: acceptVehicleValue }); + acceptMutation.mutate({ items: selectedArrivalItems, vehicleIds: acceptVehicleValues }); }; const openDistance = (id: string) => { @@ -688,6 +731,27 @@ const LastMilePage = () => { [records, activeId], ); + // Vehicle picker options for the assign modal = free vehicles PLUS the ones + // already on this record (which are BUSY, so absent from the free list) so a + // reassign shows its current trucks selected instead of blank. + const assignVehicleOptions = useMemo(() => { + const opts = [...vehicleOptions]; + const seen = new Set(opts.map((o) => o.value)); + const current = [ + ...(activeRecord?.vehicleAssignments?.map((a) => a.vehicle) ?? []), + activeRecord?.vehicle, + ]; + for (const v of current) { + if (v && !seen.has(v.id)) { + seen.add(v.id); + const parts = [`${v.manufacturer} ${v.model}`, v.plateNumber]; + if (v.code) parts.unshift(v.code); + opts.push({ value: v.id, label: parts.join(" · ") }); + } + } + return opts; + }, [vehicleOptions, activeRecord]); + const pickupReadyByBooking = useMemo(() => { const map = new Map(); for (const row of pickupReadyRows) { @@ -751,16 +815,22 @@ const LastMilePage = () => { const openAssign = (id: string | null) => { const resolved = id ?? filteredRecords.find((r) => !isAssigned(r))?.id ?? null; + const rec = records.find((r) => r.id === resolved); + const existing = rec?.vehicleAssignments?.length + ? rec.vehicleAssignments.map((a) => a.vehicleId) + : rec?.vehicleId + ? [rec.vehicleId] + : []; setBulkMode(false); setActiveId(resolved); - setVehicleValue(null); + setVehicleValues(existing.length ? existing : [null]); setAssignOpen(true); }; const openBulkAssign = () => { setBulkMode(true); setActiveId(null); - setVehicleValue(null); + setVehicleValues([null]); setAssignOpen(true); }; @@ -768,28 +838,26 @@ const LastMilePage = () => { setAssignOpen(false); setBulkMode(false); setActiveId(null); - setVehicleValue(null); + setVehicleValues([null]); }; const handleAssign = () => { - if (!vehicleValue) { - toast({ title: "Select a vehicle", description: "Choose a vehicle to assign.", variant: "destructive" }); - return; - } - + const ids = [...new Set(vehicleValues.filter((v): v is string => Boolean(v)))]; const targetIds = bulkMode ? selectedIds : [activeId ?? filteredRecords.find((r) => !isAssigned(r))?.id].filter((id): id is string => Boolean(id)); if (!targetIds.length) return; + if (!ids.length) { + toast({ title: "Select a vehicle", description: "Choose at least one vehicle to assign.", variant: "destructive" }); + return; + } - const selectedLabel = vehicleOptions.find((o) => o.value === vehicleValue)?.label ?? vehicleValue; - - Promise.all(targetIds.map((id) => updateMutation.mutateAsync({ id, data: { vehicleId: vehicleValue } }))) + Promise.all(targetIds.map((id) => setVehiclesMutation.mutateAsync({ id, vehicleIds: ids }))) .then(() => { toast({ - title: "Vehicle assigned", - description: bulkMode ? `${targetIds.length} deliveries → ${selectedLabel}` : selectedLabel, + title: ids.length > 1 ? "Vehicles assigned" : "Vehicle assigned", + description: `${bulkMode ? `${targetIds.length} deliveries · ` : ""}${ids.length} vehicle${ids.length > 1 ? "s" : ""}`, }); if (bulkMode) setRowSelection({}); closeAssign(); @@ -893,30 +961,6 @@ const LastMilePage = () => { meta: { headerClassName, cellClassName }, cell: ({ row }) => customerName(row.original), }, - { - id: "pickup", - header: "Pickup", - meta: { headerClassName, cellClassName }, - cell: ({ row }) => originYardName(row.original), - }, - { - id: "destination", - header: "Destination", - meta: { headerClassName, cellClassName }, - cell: ({ row }) => deliveryLocation(row.original), - }, - { - id: "cargo", - header: "Cargo", - meta: { headerClassName, cellClassName }, - cell: ({ row }) => cargoDesc(row.original), - }, - { - id: "advancedPayment", - header: "Advanced Payment", - meta: { headerClassName, cellClassName }, - cell: ({ row }) => formatPrice(row.original.advancedPayment), - }, { id: "postPayment", header: "Post Payment", @@ -927,13 +971,8 @@ const LastMilePage = () => { id: "vehicle", header: "Vehicle", meta: { headerClassName, cellClassName }, - cell: ({ row }) => vehicleLabel(row.original) ?? , - }, - { - id: "estimatedKm", - header: "Est. Distance (KM)", - meta: { headerClassName, cellClassName }, - cell: ({ row }) => row.original.estimatedKm != null ? row.original.estimatedKm : , + cell: ({ row }) => + vehiclesSummary(row.original) ?? Unassigned, }, { id: "exactKm", @@ -987,16 +1026,6 @@ const LastMilePage = () => { return {meta.label}; }, }, - { - id: "assignment", - header: "Assignment", - meta: { headerClassName, cellClassName }, - cell: ({ row }) => ( - - {isAssigned(row.original) ? "Assigned" : "Unassigned"} - - ), - }, { id: "actions", header: "Actions", @@ -1315,19 +1344,26 @@ const LastMilePage = () => { - + + {vehicleValues.map((val, i) => ( + +