import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"; import { IsArray, IsEnum, IsNotEmpty, ArrayMinSize, ArrayUnique, IsOptional, IsInt, } from "class-validator"; import { ClaimVehicleTypeV2, OuterPartSideV2, } from "src/static/outer-car-parts-catalog"; import { DamageSelectedPartV2BodyDto } from "./damage-selected-part-v2.dto"; /** * Enum for valid outer car parts that can be damaged * Follows the naming convention from workflow step definition */ export enum OuterCarPart { // Hood HOOD = "hood", // Doors FRONT_RIGHT_DOOR = "front_right_door", FRONT_LEFT_DOOR = "front_left_door", REAR_RIGHT_DOOR = "rear_right_door", REAR_LEFT_DOOR = "rear_left_door", // Bumpers FRONT_BUMPER = "front_bumper", REAR_BUMPER = "rear_bumper", // Fenders FRONT_RIGHT_FENDER = "front_right_fender", FRONT_LEFT_FENDER = "front_left_fender", REAR_RIGHT_FENDER = "rear_right_fender", REAR_LEFT_FENDER = "rear_left_fender", // Trunk & Roof TRUNK = "trunk", ROOF = "roof", } /** * V2 DTO for selecting damaged outer car parts * Much cleaner than the nested boolean structure */ export class SelectOuterPartsV2Dto { @ApiProperty({ description: "Array of selected damaged outer car parts", example: ["hood", "front_right_door", "rear_bumper", "roof"], enum: OuterCarPart, isArray: true, minItems: 1, maxItems: 13, }) @IsOptional() @IsArray({ message: "selectedParts must be an array" }) @ArrayMinSize(1, { message: "At least one damaged part must be selected" }) @ArrayUnique({ message: "Duplicate parts are not allowed" }) @IsEnum(OuterCarPart, { each: true, message: "Invalid part name. Must be one of the valid outer car parts", }) selectedParts?: OuterCarPart[]; @ApiProperty({ description: "Selected outer part IDs from catalog", example: [9, 10, 4], type: [Number], required: false, }) @IsOptional() @IsArray({ message: "selectedPartIds must be an array" }) @ArrayMinSize(1, { message: "At least one part ID must be selected" }) @ArrayUnique({ message: "Duplicate part IDs are not allowed" }) @IsInt({ each: true, message: "Each selected part ID must be an integer" }) selectedPartIds?: number[]; @ApiProperty({ description: "Vehicle type for validating available outer parts", enum: ClaimVehicleTypeV2, required: true, }) @IsNotEmpty() @IsEnum(ClaimVehicleTypeV2) carType?: ClaimVehicleTypeV2; } /** * Response DTO for select outer parts V2 */ export class SelectOuterPartsV2ResponseDto { @ApiProperty({ description: "Claim request ID", example: "507f1f77bcf86cd799439011", }) claimRequestId: string; @ApiProperty({ description: "Public ID shared across blame and claim", example: "A14235", }) publicId: string; @ApiProperty({ description: "Ordered selected parts: id, side-agnostic name, side, label_fa (and optional catalogKey)", type: [DamageSelectedPartV2BodyDto], }) selectedParts: DamageSelectedPartV2BodyDto[]; @ApiProperty({ description: "Selected part IDs", example: [9, 7, 11], type: [Number], }) selectedPartIds: number[]; @ApiProperty({ description: "Current workflow step", example: "SELECT_OUTER_PARTS", }) currentStep: string; @ApiProperty({ description: "Next possible workflow step", example: "SELECT_OTHER_PARTS", }) nextStep: string; @ApiProperty({ description: "Success message", example: "Outer parts selected successfully. Please proceed to select other parts.", }) message: string; @ApiPropertyOptional({ description: "Best-effort Fanavaran damage-case submit result. Selecting parts still succeeds when this contains a warning.", }) fanavaranDamageCase?: unknown; } export class SetClaimVehicleTypeV2Dto { @ApiProperty({ description: "Vehicle type selected by user", enum: ClaimVehicleTypeV2, }) @IsNotEmpty() @IsEnum(ClaimVehicleTypeV2) carType: ClaimVehicleTypeV2; } /** * Shape returned by `GET .../outer-parts-catalog` (both user and expert * controllers). It mirrors how items are persisted under * `damage.selectedParts` (see `DamageSelectedPartV2BodyDto`) so the front-end * can match catalog rows to stored selections without any field renaming: * `name` is side-agnostic, `label_fa` is disambiguated with the side in * parentheses, and the original full catalog key (`left_backfender`) is * exposed as `catalogKey`. */ export class OuterPartCatalogItemDto { @ApiProperty({ description: "Static catalog id (unique across all car types)", example: 102, }) id: number; @ApiProperty({ description: "Side-agnostic part name (matches stored part `name`)", example: "backWheel", }) name: string; @ApiProperty({ description: "Vehicle side / region", enum: OuterPartSideV2, example: "left", }) side: string; @ApiProperty({ description: "Display label in Farsi, with side disambiguator in parentheses when needed", example: "چرخ عقب (چپ)", }) label_fa: string; @ApiProperty({ description: "Original full catalog key (matches stored `catalogKey`)", example: "left_backWheel", required: false, }) catalogKey?: string; @ApiProperty({ description: "Vehicle type this catalog row belongs to", enum: ClaimVehicleTypeV2, required: false, example: "suv", }) carType?: ClaimVehicleTypeV2; }