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/first-mile/first-mile.module.ts b/apps/edr-freight-api/src/modules/first-mile/first-mile.module.ts index 713efa52d..bf6815af7 100644 --- a/apps/edr-freight-api/src/modules/first-mile/first-mile.module.ts +++ b/apps/edr-freight-api/src/modules/first-mile/first-mile.module.ts @@ -1,14 +1,23 @@ -import { Module } from '@nestjs/common'; +import { Module, forwardRef } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { BookingsModule } from '../bookings/bookings.module'; +import { DriversModule } from '../drivers/drivers.module'; +import { NotificationsModule } from '../notifications/notifications.module'; +import { VehiclesModule } from '../vehicles/vehicles.module'; import { FirstMile } from './entities/first-mile.entity'; import { FirstMileController } from './first-mile.controller'; import { FirstMileRepository } from './first-mile.repository'; import { FirstMileService } from './first-mile.service'; @Module({ - imports: [TypeOrmModule.forFeature([FirstMile]), BookingsModule], + imports: [ + TypeOrmModule.forFeature([FirstMile]), + forwardRef(() => BookingsModule), + VehiclesModule, + DriversModule, + NotificationsModule, + ], controllers: [FirstMileController], providers: [FirstMileRepository, FirstMileService], exports: [FirstMileRepository, FirstMileService], diff --git a/apps/edr-freight-api/src/modules/first-mile/first-mile.service.ts b/apps/edr-freight-api/src/modules/first-mile/first-mile.service.ts index a4ead8c2a..2d4079a8b 100644 --- a/apps/edr-freight-api/src/modules/first-mile/first-mile.service.ts +++ b/apps/edr-freight-api/src/modules/first-mile/first-mile.service.ts @@ -1,7 +1,10 @@ -import { Injectable, NotFoundException } from '@nestjs/common'; +import { Injectable, Logger, NotFoundException } from '@nestjs/common'; import { FindOptionsWhere } from 'typeorm'; import { BookingsRepository } from '../bookings/bookings.repository'; +import { DriversService } from '../drivers/drivers.service'; +import { NotificationsService } from '../notifications/notifications.service'; +import { VehiclesService } from '../vehicles/vehicles.service'; import { CreateFirstMileDto } from './dto/create-first-mile.dto'; import { UpdateFirstMileDto } from './dto/update-first-mile.dto'; import { FirstMile, FirstMileStatus } from './entities/first-mile.entity'; @@ -26,9 +29,14 @@ const SORTABLE_FIELDS: (keyof FirstMile)[] = [ @Injectable() export class FirstMileService { + private readonly logger = new Logger(FirstMileService.name); + constructor( private readonly firstMileRepository: FirstMileRepository, private readonly bookingsRepository: BookingsRepository, + private readonly vehiclesService: VehiclesService, + private readonly driversService: DriversService, + private readonly notificationsService: NotificationsService, ) {} /** @@ -37,7 +45,7 @@ export class FirstMileService { * unknown or the booking has not reached PAID status. */ async acceptBooking(bookingReference: string): Promise { - const booking = await this.bookingsRepository.findByReference(bookingReference); + const booking = await this.bookingsRepository.findById(bookingReference); if (!booking) { return null; @@ -119,7 +127,7 @@ export class FirstMileService { } async update(id: string, dto: UpdateFirstMileDto): Promise { - await this.findById(id); + const existing = await this.findById(id); const updated = await this.firstMileRepository.update(id, { ...(dto.bookingId !== undefined ? { bookingId: dto.bookingId } : {}), @@ -135,9 +143,45 @@ export class FirstMileService { throw new NotFoundException(`First-mile record ${id} not found`); } + // Notify assigned driver on every explicit vehicle assignment or reassignment + if (dto.vehicleId) { + void this.notifyDriverAssignment(dto.vehicleId, existing); + } + return updated; } + private async notifyDriverAssignment(vehicleId: string, record: FirstMile): Promise { + try { + const vehicle = await this.vehiclesService.findById(vehicleId); + if (!vehicle.assignedDriverId) { + this.logger.warn(`Vehicle ${vehicleId} has no assigned driver — skipping SMS`); + return; + } + + const driver = await this.driversService.findById(vehicle.assignedDriverId); + if (!driver.phoneNumber) { + this.logger.warn(`Driver ${vehicle.assignedDriverId} has no phone number — skipping SMS`); + return; + } + + const booking = (record as FirstMile & { booking?: { reference?: string; firstMilePickupAddress?: string | null; originYard?: { label?: string } | null } }).booking; + + await this.notificationsService.notifyDriverVehicleAssignment({ + driverPhone: driver.phoneNumber, + driverName: `${driver.firstName ?? ''} ${driver.lastName ?? ''}`.trim(), + vehiclePlateNumber: vehicle.plateNumber ?? vehicleId, + bookingReference: booking?.reference ?? record.bookingId, + pickupAddress: booking?.firstMilePickupAddress, + destinationYard: booking?.originYard?.label, + }); + + this.logger.log(`SMS sent to driver ${driver.phoneNumber} for vehicle ${vehicleId} assignment`); + } catch (err) { + this.logger.error(`Failed to notify driver for vehicle ${vehicleId}: ${String(err)}`); + } + } + async remove(id: string): Promise { await this.findById(id); await this.firstMileRepository.softDelete(id); 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 2ff2f9727..70e00c9ac 100644 --- a/apps/edr-freight-api/src/modules/notifications/notifications.module.ts +++ b/apps/edr-freight-api/src/modules/notifications/notifications.module.ts @@ -1,14 +1,14 @@ import { Module } from "@nestjs/common"; +import { ConfigModule } from "@nestjs/config"; import { NotificationsService } from "./notifications.service"; import { EmailNotificationStrategy } from "./strategies/notification.email.strategy"; import { SmsNotificationStrategy } from "./strategies/notification.sms.strategy"; -import { HttpModule } from "@nestjs/axios"; @Module({ - imports: [HttpModule], + imports: [ConfigModule], controllers: [], providers: [EmailNotificationStrategy, SmsNotificationStrategy, NotificationsService], exports: [NotificationsService], }) -export class NotificationsModule { } +export class NotificationsModule {} diff --git a/apps/edr-freight-api/src/modules/notifications/notifications.service.ts b/apps/edr-freight-api/src/modules/notifications/notifications.service.ts index 35e8ff07d..088f2bbe0 100644 --- a/apps/edr-freight-api/src/modules/notifications/notifications.service.ts +++ b/apps/edr-freight-api/src/modules/notifications/notifications.service.ts @@ -27,9 +27,29 @@ export class NotificationsService { if (!strategy) { throw new NotFoundException(); } - const sent = await strategy.send(recipient, message) - this.logger.log(`is sent - ${sent}`) + const sent = await strategy.send(recipient, message); + this.logger.log(`is sent - ${sent}`); } + async notifyDriverVehicleAssignment(params: { + driverPhone: string; + driverName: string; + vehiclePlateNumber: string; + bookingReference: string; + pickupAddress?: string | null; + destinationYard?: string | null; + }): Promise { + const { driverPhone, driverName, vehiclePlateNumber, bookingReference, pickupAddress, destinationYard } = params; + const message = + `Dear ${driverName}, you have been assigned to a first-mile pickup. ` + + `Booking: ${bookingReference}. Vehicle: ${vehiclePlateNumber}. ` + + (pickupAddress ? `Pickup: ${pickupAddress}. ` : '') + + (destinationYard ? `Destination: ${destinationYard}.` : ''); + try { + await this.directSend('sms', driverPhone, message); + } catch (err) { + this.logger.error(`Failed to notify driver ${driverName} (${driverPhone}): ${String(err)}`); + } + } } diff --git a/apps/edr-freight-api/src/modules/notifications/strategies/notification.sms.strategy.ts b/apps/edr-freight-api/src/modules/notifications/strategies/notification.sms.strategy.ts index 2f8916845..127eae5cd 100644 --- a/apps/edr-freight-api/src/modules/notifications/strategies/notification.sms.strategy.ts +++ b/apps/edr-freight-api/src/modules/notifications/strategies/notification.sms.strategy.ts @@ -1,25 +1,36 @@ -import { Injectable} from "@nestjs/common"; -import { NotificationStrategy } from "./notification.strategy"; -import { HttpService } from '@nestjs/axios'; +import { Injectable } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; -import { firstValueFrom } from 'rxjs'; +import axios from "axios"; + +import { NotificationStrategy } from "./notification.strategy"; @Injectable() export class SmsNotificationStrategy implements NotificationStrategy { - constructor(private readonly httpService: HttpService, private readonly configService: ConfigService) { } - async send(recipient: string, message: string) { - const url = this.configService.get("OZIKING_SMS_URL") - const body = { - to: recipient, - text: message - } - const response = await firstValueFrom( - this.httpService.post( - url, - body, - ), - ); + constructor(private readonly configService: ConfigService) {} - return response.status === 201; - } + async send(recipient: string, message: string): Promise { + const url = + this.configService.get("OZIKING_SMS_URL") ?? + "https://notification-dev.license.aafda.gov.et/api/sms-services/ozeking/sms"; + + await axios.post( + url, + { + to: recipient, + sourceId: this.configService.get("OZIKING_SOURCE_ID") ?? "EDR", + sourceName: this.configService.get("OZIKING_SOURCE_NAME") ?? "EDR Freight", + appKey: this.configService.get("OZIKING_APP_KEY") ?? "", + text: message, + callbackUrl: "", + }, + { + headers: { + accept: "*/*", + "Content-Type": "application/json", + }, + }, + ); + + return true; + } } diff --git a/apps/edr-freight-api/src/modules/payment/payment.module.ts b/apps/edr-freight-api/src/modules/payment/payment.module.ts index e496bb867..d0eb2eecb 100644 --- a/apps/edr-freight-api/src/modules/payment/payment.module.ts +++ b/apps/edr-freight-api/src/modules/payment/payment.module.ts @@ -19,6 +19,7 @@ import { InternalPaymentController } from "./internal-payment.controller"; import { ServiceAuthGuard } from "../../common/guards/service-auth.guard"; import { TrainSchedulingModule } from "../train-scheduling/train-scheduling.module"; import { DropdownSettingsModule } from "../dropdown-settings/dropdown-settings.module"; +import { FirstMileModule } from "../first-mile/first-mile.module"; import { PaymentWebhookEventEntity } from "./entities/payment-webhook-event.entity"; import { PaymentRefundEntity } from "./entities/payment-refund.entity"; @@ -29,6 +30,7 @@ const FREIGHT_QUEUE = PAYMENT_QUEUES[PaymentServiceEnum.FREIGHT]; HttpModule.register({ timeout: 10_000 }), ConfigModule, DropdownSettingsModule, + forwardRef(() => FirstMileModule), forwardRef(() => TrainSchedulingModule), TypeOrmModule.forFeature([PaymentWebhookEventEntity, PaymentRefundEntity]), RabbitMQModule.forRootAsync({ diff --git a/apps/edr-freight-api/src/modules/payment/payment.service.ts b/apps/edr-freight-api/src/modules/payment/payment.service.ts index 1f95c6253..582e7467e 100644 --- a/apps/edr-freight-api/src/modules/payment/payment.service.ts +++ b/apps/edr-freight-api/src/modules/payment/payment.service.ts @@ -35,6 +35,7 @@ import { } from "./payments.dto"; import { BookingBatchService } from "../train-scheduling/booking-batch.service"; import { DropdownSettingsService } from "../dropdown-settings/dropdown-settings.service"; +import { FirstMileService } from "../first-mile/first-mile.service"; /** Setting code holding the global ordering window (months) for general contracts. */ const CONTRACT_PERIOD_SETTING_CODE = "general_contract_period"; @@ -60,6 +61,7 @@ export class PaymentService { @Inject(forwardRef(() => BookingBatchService)) private readonly bookingBatchService: BookingBatchService, private readonly dropdownSettings: DropdownSettingsService, + private readonly firstMileService: FirstMileService, ) { } /** Configured general-contract ordering window in months (defaults to 3). */ @@ -342,6 +344,8 @@ export class PaymentService { ? { paymentStatus: "PAID", status: "CONTRACT_ACTIVE", expiresAt: contractExpiresAt } : { paymentStatus: "PAID", status: "PAID" }, ); + await this.firstMileService.acceptBooking(input.bookingId); + }); if (isGeneralContract) { 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/constants/apiConfig.ts b/apps/edr-freight-web/backoffice/src/constants/apiConfig.ts index 030b051a1..a7c8670cf 100644 --- a/apps/edr-freight-web/backoffice/src/constants/apiConfig.ts +++ b/apps/edr-freight-web/backoffice/src/constants/apiConfig.ts @@ -1,3 +1,3 @@ -export const API_BASE_URL = 'https://edrfreightapi.triaplc.com'; +// export const API_BASE_URL = 'https://edrfreightapi.triaplc.com'; -// export const API_BASE_URL = 'http://localhost:3001'; +export const API_BASE_URL = 'http://localhost:3001'; 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 33f7300f4..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); @@ -91,8 +95,9 @@ const cargoDesc = (r: FirstMileRecord) => { }; const priceAmount = (r: FirstMileRecord) => r.booking?.totalAmount ?? r.advancedPayment; +// First-mile destination is the origin yard (pickup → origin yard) const destinationYardName = (r: FirstMileRecord) => - r.booking?.destinationYard?.name ?? "—"; + r.booking?.originYard?.label ?? "—"; const contactPersonName = (r: FirstMileRecord) => r.booking?.company?.contactPersonName ?? "—"; const contactPhone = (r: FirstMileRecord) => @@ -102,7 +107,7 @@ const requestedDate = (r: FirstMileRecord) => { return d ? new Date(d).toISOString().slice(0, 10) : "—"; }; const serviceTypeName = (r: FirstMileRecord) => - r.booking?.serviceType?.name ?? "—"; + r.booking?.serviceType?.label ?? "—"; const InfoRow = ({ label, value }: { label: string; value: string }) => ( @@ -135,7 +140,7 @@ const BookingInfo = ({ record }: { record: FirstMileRecord }) => ( - + @@ -345,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], ); @@ -587,6 +595,12 @@ const FirstMilePage = () => { meta: { headerClassName, cellClassName }, cell: ({ row }) => pickupLocation(row.original), }, + { + id: "destination", + header: "Destination", + meta: { headerClassName, cellClassName }, + cell: ({ row }) => destinationYardName(row.original), + }, { id: "cargo", header: "Cargo", @@ -903,7 +917,7 @@ const FirstMilePage = () => { - {b.originYard?.name ?? "—"} → {b.destinationYard?.name ?? "—"} + {b.originYard?.label ?? "—"} → {b.destinationYard?.label ?? "—"} {formatPrice(b.totalAmount)} @@ -935,8 +949,8 @@ const FirstMilePage = () => { - - + + 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 f761719ae..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 @@ -18,10 +18,10 @@ export interface FirstMileBooking { totalAmount: number; scheduledDate?: string | null; company?: { id: string; name?: string; phone?: string | null; contactPersonName?: string | null; contactPersonPhone?: string | null } | null; - serviceType?: { id: string; name?: string } | null; - originYard?: { id: string; name?: string } | null; - destinationYard?: { id: string; name?: string } | null; - cargoType?: { id: string; name?: string } | null; + serviceType?: { id: string; label?: string } | null; + originYard?: { id: string; label?: string } | null; + destinationYard?: { id: string; label?: string } | null; + cargoType?: { id: string; label?: string } | null; } export interface FirstMileVehicle { @@ -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; } diff --git a/apps/edr-freight-web/portal/src/constants/apiConfig.ts b/apps/edr-freight-web/portal/src/constants/apiConfig.ts index dce8aad63..fc9f57a58 100644 --- a/apps/edr-freight-web/portal/src/constants/apiConfig.ts +++ b/apps/edr-freight-web/portal/src/constants/apiConfig.ts @@ -1,3 +1,3 @@ -export const API_BASE_URL = 'https://edrfreightapi.triaplc.com'; -// export const API_BASE_URL = 'http://localhost:3001'; +// export const API_BASE_URL = 'https://edrfreightapi.triaplc.com'; +export const API_BASE_URL = 'http://localhost:3001';