From 788de5381e6d7617d657b990787876b72e5f1d0a Mon Sep 17 00:00:00 2001 From: hagiye Date: Sat, 6 Jun 2026 05:52:47 +0300 Subject: [PATCH] feat: complete train scheduling integration --- WagonForm.tsx | 0 .../1750200000000-SeedDefaultWagonTypes.ts | 46 ++++ .../src/modules/cargoes/cargoes.module.ts | 5 +- .../src/modules/cargoes/cargoes.service.ts | 40 +++ .../container-management/containers.module.ts | 5 +- .../containers.service.ts | 42 ++++ .../src/modules/payment/payment.controller.ts | 7 +- .../train-scheduling.service.ts | 8 +- .../wagon-types/wagon-types.controller.ts | 16 ++ .../modules/wagon-types/wagon-types.module.ts | 2 + .../wagon-types/wagon-types.service.ts | 7 + .../AssignContainerDialog.tsx | 10 +- .../container_management/CargoFormDialog.tsx | 125 ++++++++++ .../ContainerFormDialog.tsx | 137 +++++------ .../container_management/ContainersTable.tsx | 4 +- .../cargo-types.service.ts | 15 ++ .../container_management/cargo.service.ts | 19 ++ .../container-types.service.ts | 15 ++ .../container_management/container.service.ts | 31 +++ .../containerTypesService.ts | 0 .../container_management/use-cargo-types.ts | 12 + .../container_management/use-cargoes.ts | 42 ++++ .../use-container-types.ts | 12 + .../container_management/use-containers.ts | 73 ++++++ .../container_management/use-wagon-types.ts | 12 + .../container_management/use-wagons.ts | 48 ++++ .../container_management/useCargoTypes.ts | 0 .../container_management/useCargoes.ts | 0 .../container_management/useContainerTypes.ts | 0 .../wagon-types.service.ts | 13 + .../container_management/wagon.service.ts | 23 ++ .../src/components/wagons/WagonFormDialog.tsx | 44 +++- .../wagons/WagonFormDialogEnhanced.tsx | 35 ++- .../backoffice/src/hooks/use-cargo-types.ts | 12 + .../backoffice/src/hooks/use-cargoes.ts | 1 + .../src/hooks/use-container-types.ts | 12 + .../backoffice/src/hooks/use-containers.ts | 1 + .../backoffice/src/hooks/use-wagon-types.ts | 12 + .../src/pages/fleet/FleetCrudPages.tsx | 231 +++++++++++++++--- .../src/pages/trains/TrainsPage.tsx | 7 +- .../backoffice/src/pages/wagons/WagonForm.tsx | 109 +++++++++ .../src/services/cargo-types.service.ts | 15 ++ .../src/services/container-types.service.ts | 15 ++ .../src/services/wagon-types.service.ts | 13 + cargo-types.service.ts | 10 + container-types.service.ts | 10 + use-cargo-types.ts | 12 + use-cargoes.ts | 0 use-container-types.ts | 12 + use-wagon-types.ts | 12 + wagon-type.entity.ts | 0 wagon-types.controller.ts | 0 wagon-types.repository.ts | 0 wagon-types.service.ts | 0 wagon.service.ts | 0 wagons.controller.ts | 0 56 files changed, 1191 insertions(+), 141 deletions(-) create mode 100644 WagonForm.tsx create mode 100644 apps/edr-freight-api/src/migrations/1750200000000-SeedDefaultWagonTypes.ts create mode 100644 apps/edr-freight-api/src/modules/wagon-types/wagon-types.controller.ts create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/CargoFormDialog.tsx create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/cargo-types.service.ts create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/cargo.service.ts create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/container-types.service.ts create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/container.service.ts create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/containerTypesService.ts create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/use-cargo-types.ts create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/use-cargoes.ts create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/use-container-types.ts create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/use-containers.ts create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/use-wagon-types.ts create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/use-wagons.ts create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/useCargoTypes.ts create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/useCargoes.ts create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/useContainerTypes.ts create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/wagon-types.service.ts create mode 100644 apps/edr-freight-web/backoffice/src/components/container_management/wagon.service.ts create mode 100644 apps/edr-freight-web/backoffice/src/hooks/use-cargo-types.ts create mode 100644 apps/edr-freight-web/backoffice/src/hooks/use-cargoes.ts create mode 100644 apps/edr-freight-web/backoffice/src/hooks/use-container-types.ts create mode 100644 apps/edr-freight-web/backoffice/src/hooks/use-containers.ts create mode 100644 apps/edr-freight-web/backoffice/src/hooks/use-wagon-types.ts create mode 100644 apps/edr-freight-web/backoffice/src/pages/wagons/WagonForm.tsx create mode 100644 apps/edr-freight-web/backoffice/src/services/cargo-types.service.ts create mode 100644 apps/edr-freight-web/backoffice/src/services/container-types.service.ts create mode 100644 apps/edr-freight-web/backoffice/src/services/wagon-types.service.ts create mode 100644 cargo-types.service.ts create mode 100644 container-types.service.ts create mode 100644 use-cargo-types.ts create mode 100644 use-cargoes.ts create mode 100644 use-container-types.ts create mode 100644 use-wagon-types.ts create mode 100644 wagon-type.entity.ts create mode 100644 wagon-types.controller.ts create mode 100644 wagon-types.repository.ts create mode 100644 wagon-types.service.ts create mode 100644 wagon.service.ts create mode 100644 wagons.controller.ts diff --git a/WagonForm.tsx b/WagonForm.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/apps/edr-freight-api/src/migrations/1750200000000-SeedDefaultWagonTypes.ts b/apps/edr-freight-api/src/migrations/1750200000000-SeedDefaultWagonTypes.ts new file mode 100644 index 000000000..06dc0b917 --- /dev/null +++ b/apps/edr-freight-api/src/migrations/1750200000000-SeedDefaultWagonTypes.ts @@ -0,0 +1,46 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class SeedDefaultWagonTypes1750200000000 implements MigrationInterface { + name = 'SeedDefaultWagonTypes1750200000000'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + INSERT INTO freight.wagon_types ( + code, + name, + capacity_tons, + length_meters, + max_wagons_per_train, + supported_load_types, + is_active + ) + VALUES + ('NW7', 'Double deck sedan wagon', 22, 26.066, NULL, ARRAY['vehicles', 'sedan'], true), + ('NW5', 'Flat wagon (container)', 70, 14.000, 53, ARRAY['container', 'steel', 'machinery'], true), + ('PW2', 'Box wagon', 70, 17.066, 18, ARRAY['general cargo', 'break bulk'], true), + ('GW2', 'Tank wagon', 70, 12.228, 37, ARRAY['liquid', 'fuel'], true), + ('CW4', 'Gondola covered wagon', 70, 13.976, 37, ARRAY['covered bulk cargo'], true), + ('CW3', 'Gondola open wagon', 70, 13.976, NULL, ARRAY['open bulk cargo'], true), + ('KW2', 'Hopper covered wagon', 69, 16.466, NULL, ARRAY['bulk grains'], true), + ('KW3', 'Hopper open wagon', 70, 14.400, NULL, ARRAY['coal', 'bulk cargo'], true), + ('NW6', 'Flat wagon (long cargo)', 70, 18.560, NULL, ARRAY['long cargo'], true), + ('BW1', 'Refrigerated wagon', 38, 21.996, NULL, ARRAY['refrigerated cargo'], true) + ON CONFLICT (code) DO UPDATE SET + name = EXCLUDED.name, + capacity_tons = EXCLUDED.capacity_tons, + length_meters = EXCLUDED.length_meters, + max_wagons_per_train = EXCLUDED.max_wagons_per_train, + supported_load_types = EXCLUDED.supported_load_types, + is_active = true, + deleted_at = NULL, + updated_at = now(); + `); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(` + DELETE FROM freight.wagon_types + WHERE code IN ('NW7', 'NW5', 'PW2', 'GW2', 'CW4', 'CW3', 'KW2', 'KW3', 'NW6', 'BW1'); + `); + } +} diff --git a/apps/edr-freight-api/src/modules/cargoes/cargoes.module.ts b/apps/edr-freight-api/src/modules/cargoes/cargoes.module.ts index 8a60d2600..d1c03c9d8 100644 --- a/apps/edr-freight-api/src/modules/cargoes/cargoes.module.ts +++ b/apps/edr-freight-api/src/modules/cargoes/cargoes.module.ts @@ -2,13 +2,14 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { Cargo } from './entities/cargoes.entity'; import { Container } from '../container-management/entities/container.entity'; +import { CargoType } from '../rule-engine/entities/cargo-type.entity'; import { CargoesController } from './cargoes.controller'; import { CargoesService } from './cargoes.service'; @Module({ - imports: [TypeOrmModule.forFeature([Cargo, Container])], + imports: [TypeOrmModule.forFeature([Cargo, Container, CargoType])], controllers: [CargoesController], providers: [CargoesService], exports: [CargoesService], }) -export class CargoesModule {} \ No newline at end of file +export class CargoesModule {} diff --git a/apps/edr-freight-api/src/modules/cargoes/cargoes.service.ts b/apps/edr-freight-api/src/modules/cargoes/cargoes.service.ts index 0ddd507cb..f5940d6a6 100644 --- a/apps/edr-freight-api/src/modules/cargoes/cargoes.service.ts +++ b/apps/edr-freight-api/src/modules/cargoes/cargoes.service.ts @@ -7,6 +7,7 @@ import { LoadCargoDto } from './dto/load-cargo.dto'; import { DeliverCargoDto } from './dto/deliver-cargo.dto'; import { Cargo } from './entities/cargoes.entity'; import { Container } from '../container-management/entities/container.entity'; +import { CargoType } from '../rule-engine/entities/cargo-type.entity'; @Injectable() export class CargoesService { @@ -15,9 +16,30 @@ export class CargoesService { private readonly cargoRepo: Repository, @InjectRepository(Container) private readonly containerRepo: Repository, + @InjectRepository(CargoType) + private readonly cargoTypeRepo: Repository, ) {} async create(dto: CreateCargoDto): Promise { + const existing = await this.cargoRepo.findOne({ + where: { cargoReference: dto.cargoReference }, + }); + if (existing) { + throw new ConflictException(`Cargo reference "${dto.cargoReference}" already exists`); + } + + const container = await this.containerRepo.findOne({ where: { id: dto.containerId } }); + if (!container) { + throw new NotFoundException(`Container ${dto.containerId} not found`); + } + + if (dto.cargoTypeId) { + const cargoType = await this.cargoTypeRepo.findOne({ + where: { id: dto.cargoTypeId, isActive: true }, + }); + if (!cargoType) throw new NotFoundException(`Cargo type ${dto.cargoTypeId} not found`); + } + const cargo = this.cargoRepo.create(dto); return this.cargoRepo.save(cargo); } @@ -62,6 +84,24 @@ export class CargoesService { async update(id: string, dto: UpdateCargoDto): Promise { const cargo = await this.findById(id); + if (dto.cargoReference && dto.cargoReference !== cargo.cargoReference) { + const existing = await this.cargoRepo.findOne({ + where: { cargoReference: dto.cargoReference }, + }); + if (existing) { + throw new ConflictException(`Cargo reference "${dto.cargoReference}" already exists`); + } + } + if (dto.containerId) { + const container = await this.containerRepo.findOne({ where: { id: dto.containerId } }); + if (!container) throw new NotFoundException(`Container ${dto.containerId} not found`); + } + if (dto.cargoTypeId) { + const cargoType = await this.cargoTypeRepo.findOne({ + where: { id: dto.cargoTypeId, isActive: true }, + }); + if (!cargoType) throw new NotFoundException(`Cargo type ${dto.cargoTypeId} not found`); + } Object.assign(cargo, dto); return this.cargoRepo.save(cargo); } diff --git a/apps/edr-freight-api/src/modules/container-management/containers.module.ts b/apps/edr-freight-api/src/modules/container-management/containers.module.ts index eea118187..b048b5af8 100644 --- a/apps/edr-freight-api/src/modules/container-management/containers.module.ts +++ b/apps/edr-freight-api/src/modules/container-management/containers.module.ts @@ -3,12 +3,13 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { Container } from './entities/container.entity'; import { Wagon } from '../wagons/entities/wagon.entity'; +import { ContainerType } from '../rule-engine/entities/container-type.entity'; import { ContainersController } from './containers.controller'; import { ContainersService } from './containers.service'; @Module({ - imports: [TypeOrmModule.forFeature([Container, Wagon])], // ✅ add Wagon + imports: [TypeOrmModule.forFeature([Container, Wagon, ContainerType])], controllers: [ContainersController], providers: [ContainersService], }) -export class ContainersModule {} \ No newline at end of file +export class ContainersModule {} diff --git a/apps/edr-freight-api/src/modules/container-management/containers.service.ts b/apps/edr-freight-api/src/modules/container-management/containers.service.ts index 1624e2d17..bf7c966aa 100644 --- a/apps/edr-freight-api/src/modules/container-management/containers.service.ts +++ b/apps/edr-freight-api/src/modules/container-management/containers.service.ts @@ -7,6 +7,7 @@ import { UpdateContainerDto } from './dto/update-container.dto'; import { AssignContainerToWagonDto } from './dto/assign-container-to-wagon.dto'; import { Container } from './entities/container.entity'; import { Wagon } from '../wagons/entities/wagon.entity'; +import { ContainerType } from '../rule-engine/entities/container-type.entity'; @Injectable() export class ContainersService { @@ -15,9 +16,30 @@ export class ContainersService { private readonly containerRepo: Repository, @InjectRepository(Wagon) private readonly wagonRepo: Repository, // ✅ use raw repository + @InjectRepository(ContainerType) + private readonly containerTypeRepo: Repository, ) {} async create(dto: CreateContainerDto): Promise { + const existing = await this.containerRepo.findOne({ + where: { containerNumber: dto.containerNumber }, + }); + if (existing) { + throw new ConflictException(`Container number "${dto.containerNumber}" already exists`); + } + + const containerType = await this.containerTypeRepo.findOne({ + where: { id: dto.containerTypeId, isActive: true }, + }); + if (!containerType) { + throw new NotFoundException(`Container type ${dto.containerTypeId} not found`); + } + + if (dto.wagonId) { + const wagon = await this.wagonRepo.findOne({ where: { id: dto.wagonId } }); + if (!wagon) throw new NotFoundException(`Wagon ${dto.wagonId} not found`); + } + const container = this.containerRepo.create(dto); if (dto.wagonId === undefined) container.wagonId = null; if (dto.position === undefined) container.position = null; @@ -59,6 +81,26 @@ export class ContainersService { async update(id: string, dto: UpdateContainerDto): Promise { const container = await this.findById(id); + if (dto.containerNumber && dto.containerNumber !== container.containerNumber) { + const existing = await this.containerRepo.findOne({ + where: { containerNumber: dto.containerNumber }, + }); + if (existing) { + throw new ConflictException(`Container number "${dto.containerNumber}" already exists`); + } + } + if (dto.containerTypeId) { + const containerType = await this.containerTypeRepo.findOne({ + where: { id: dto.containerTypeId, isActive: true }, + }); + if (!containerType) { + throw new NotFoundException(`Container type ${dto.containerTypeId} not found`); + } + } + if (dto.wagonId) { + const wagon = await this.wagonRepo.findOne({ where: { id: dto.wagonId } }); + if (!wagon) throw new NotFoundException(`Wagon ${dto.wagonId} not found`); + } Object.assign(container, dto); return this.containerRepo.save(container); } diff --git a/apps/edr-freight-api/src/modules/payment/payment.controller.ts b/apps/edr-freight-api/src/modules/payment/payment.controller.ts index 05b127968..46a7e1e1c 100644 --- a/apps/edr-freight-api/src/modules/payment/payment.controller.ts +++ b/apps/edr-freight-api/src/modules/payment/payment.controller.ts @@ -4,11 +4,6 @@ import { Public } from "@edr/api-common"; import { randomUUID } from "crypto"; import { Response } from "express" -import * as fs from 'fs'; -import * as path from 'path'; -import Handlebars from 'handlebars'; - - @Public() @Controller("payments") export class PaymentController { @@ -86,4 +81,4 @@ export class PaymentController { -} \ No newline at end of file +} diff --git a/apps/edr-freight-api/src/modules/train-scheduling/train-scheduling.service.ts b/apps/edr-freight-api/src/modules/train-scheduling/train-scheduling.service.ts index 1d86bd1a5..34c4a7843 100644 --- a/apps/edr-freight-api/src/modules/train-scheduling/train-scheduling.service.ts +++ b/apps/edr-freight-api/src/modules/train-scheduling/train-scheduling.service.ts @@ -118,9 +118,11 @@ export class TrainSchedulingService { ); } - queryBuilder.andWhere("booking.status = :status", { - status: query.status ?? "PAID", - }); + if (query.status) { + queryBuilder.andWhere("booking.status = :status", { + status: query.status, + }); + } const bookings = await queryBuilder .orderBy("booking.scheduled_date", "ASC") diff --git a/apps/edr-freight-api/src/modules/wagon-types/wagon-types.controller.ts b/apps/edr-freight-api/src/modules/wagon-types/wagon-types.controller.ts new file mode 100644 index 000000000..0c0d65bd7 --- /dev/null +++ b/apps/edr-freight-api/src/modules/wagon-types/wagon-types.controller.ts @@ -0,0 +1,16 @@ +import { Controller, Get } from '@nestjs/common'; +import { ApiTags, ApiOperation } from '@nestjs/swagger'; +import { WagonTypesService } from './wagon-types.service'; +import { WagonType } from './entities/wagon-type.entity'; + +@ApiTags('Wagon Types') +@Controller('wagon-types') +export class WagonTypesController { + constructor(private readonly wagonTypesService: WagonTypesService) {} + + @Get() + @ApiOperation({ summary: 'Get all active wagon types' }) + async findAll(): Promise { + return this.wagonTypesService.findAll(); + } +} \ No newline at end of file diff --git a/apps/edr-freight-api/src/modules/wagon-types/wagon-types.module.ts b/apps/edr-freight-api/src/modules/wagon-types/wagon-types.module.ts index 3cb23cc3c..d2d770585 100644 --- a/apps/edr-freight-api/src/modules/wagon-types/wagon-types.module.ts +++ b/apps/edr-freight-api/src/modules/wagon-types/wagon-types.module.ts @@ -2,11 +2,13 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { WagonType } from './entities/wagon-type.entity'; +import { WagonTypesController } from './wagon-types.controller'; import { WagonTypesRepository } from './wagon-types.repository'; import { WagonTypesService } from './wagon-types.service'; @Module({ imports: [TypeOrmModule.forFeature([WagonType])], + controllers: [WagonTypesController], providers: [WagonTypesRepository, WagonTypesService], exports: [WagonTypesRepository, WagonTypesService], }) diff --git a/apps/edr-freight-api/src/modules/wagon-types/wagon-types.service.ts b/apps/edr-freight-api/src/modules/wagon-types/wagon-types.service.ts index 4e15937e0..879245783 100644 --- a/apps/edr-freight-api/src/modules/wagon-types/wagon-types.service.ts +++ b/apps/edr-freight-api/src/modules/wagon-types/wagon-types.service.ts @@ -7,6 +7,13 @@ import { WagonTypesRepository } from './wagon-types.repository'; export class WagonTypesService { constructor(private readonly wagonTypesRepository: WagonTypesRepository) {} + async findAll(): Promise { + return this.wagonTypesRepository.findAll({ + where: { isActive: true }, + order: { code: 'ASC' }, + }); + } + async findByCode(code: string): Promise { const [wagonType] = await this.wagonTypesRepository.findAll({ where: { code } }); diff --git a/apps/edr-freight-web/backoffice/src/components/container_management/AssignContainerDialog.tsx b/apps/edr-freight-web/backoffice/src/components/container_management/AssignContainerDialog.tsx index d10955933..55f44936c 100644 --- a/apps/edr-freight-web/backoffice/src/components/container_management/AssignContainerDialog.tsx +++ b/apps/edr-freight-web/backoffice/src/components/container_management/AssignContainerDialog.tsx @@ -1,10 +1,16 @@ import { useState } from 'react'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from '@edr/ui-common'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; -import { useContainers, useAssignContainerToWagon } from '@/hooks/useContainers'; +import { useContainers, useAssignContainerToWagon } from './use-containers'; import { useToast } from '@/hooks/use-toast'; import { Plus } from 'lucide-react'; diff --git a/apps/edr-freight-web/backoffice/src/components/container_management/CargoFormDialog.tsx b/apps/edr-freight-web/backoffice/src/components/container_management/CargoFormDialog.tsx new file mode 100644 index 000000000..b36aafe39 --- /dev/null +++ b/apps/edr-freight-web/backoffice/src/components/container_management/CargoFormDialog.tsx @@ -0,0 +1,125 @@ +import { useState, useEffect } from 'react'; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogFooter, +} from '@/components/ui/dialog'; +import { Button } from '@/components/ui/button'; +import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from '@edr/ui-common'; +import { Textarea } from '@/components/ui/textarea'; +import { useCargoTypes } from './use-cargo-types'; +import { useCargoMutations } from './use-cargoes'; +import { Loader2 } from 'lucide-react'; + +interface Cargo { + id: string; + cargoNumber: string; + cargoTypeId: string; + weight: number; + remarks?: string; +} + +interface CargoFormDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; + cargo?: Cargo | null; + onSuccess?: () => void; +} + +export default function CargoFormDialog({ + open, + onOpenChange, + cargo, + onSuccess, +}: CargoFormDialogProps) { + const { data: cargoTypes } = useCargoTypes(); + const { createCargo, updateCargo } = useCargoMutations(); + const [formData, setFormData] = useState>({ + cargoNumber: '', + cargoTypeId: '', + weight: 0, + remarks: '', + }); + + useEffect(() => { + if (cargo) { + setFormData(cargo); + } else { + setFormData({ + cargoNumber: '', + cargoTypeId: '', + weight: 0, + remarks: '', + }); + } + }, [cargo, open]); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + if (cargo?.id) { + updateCargo.mutate( + { id: cargo.id, data: formData }, + { onSuccess: () => { onOpenChange(false); onSuccess?.(); } } + ); + } else { + createCargo.mutate(formData, { + onSuccess: () => { onOpenChange(false); onSuccess?.(); } + }); + } + }; + + const isLoading = createCargo.isPending || updateCargo.isPending; + + return ( + + + {cargo ? 'Edit Cargo' : 'Create New Cargo'} +
+
+
+ + setFormData({...formData, cargoNumber: e.target.value})} required /> +
+
+ + +
+
+
+ + setFormData({...formData, weight: parseFloat(e.target.value)})} required /> +
+
+ +