import { IsString, IsDateString, IsEnum, IsOptional, IsInt, Min, IsBoolean, Matches, } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; export class RateSearchRequestDto { @ApiProperty({ description: 'Origin port code (UN/LOCODE)', example: 'NLRTM', pattern: '^[A-Z]{5}$', }) @IsString() @Matches(/^[A-Z]{5}$/, { message: 'Origin must be a valid 5-character UN/LOCODE (e.g., NLRTM)' }) origin: string; @ApiProperty({ description: 'Destination port code (UN/LOCODE)', example: 'CNSHA', pattern: '^[A-Z]{5}$', }) @IsString() @Matches(/^[A-Z]{5}$/, { message: 'Destination must be a valid 5-character UN/LOCODE (e.g., CNSHA)', }) destination: string; @ApiProperty({ description: 'Container type', example: '40HC', enum: ['20DRY', '20HC', '40DRY', '40HC', '40REEFER', '45HC'], }) @IsString() @IsEnum(['20DRY', '20HC', '40DRY', '40HC', '40REEFER', '45HC'], { message: 'Container type must be one of: 20DRY, 20HC, 40DRY, 40HC, 40REEFER, 45HC', }) containerType: string; @ApiProperty({ description: 'Shipping mode', example: 'FCL', enum: ['FCL', 'LCL'], }) @IsEnum(['FCL', 'LCL'], { message: 'Mode must be either FCL or LCL' }) mode: 'FCL' | 'LCL'; @ApiProperty({ description: 'Desired departure date (ISO 8601 format)', example: '2025-02-15', }) @IsDateString({}, { message: 'Departure date must be a valid ISO 8601 date string' }) departureDate: string; @ApiPropertyOptional({ description: 'Number of containers', example: 2, minimum: 1, default: 1, }) @IsOptional() @IsInt() @Min(1, { message: 'Quantity must be at least 1' }) quantity?: number; @ApiPropertyOptional({ description: 'Total cargo weight in kg', example: 20000, minimum: 0, }) @IsOptional() @IsInt() @Min(0, { message: 'Weight must be non-negative' }) weight?: number; @ApiPropertyOptional({ description: 'Total cargo volume in cubic meters', example: 50.5, minimum: 0, }) @IsOptional() @Min(0, { message: 'Volume must be non-negative' }) volume?: number; @ApiPropertyOptional({ description: 'Whether cargo is hazardous material', example: false, default: false, }) @IsOptional() @IsBoolean() isHazmat?: boolean; @ApiPropertyOptional({ description: 'IMO hazmat class (required if isHazmat is true)', example: '3', pattern: '^[1-9](\\.[1-9])?$', }) @IsOptional() @IsString() @Matches(/^[1-9](\.[1-9])?$/, { message: 'IMO class must be in format X or X.Y (e.g., 3 or 3.1)', }) imoClass?: string; }