diff --git a/src/app/features/tech-record/components/tech-record-summary/tech-record-summary.component.ts b/src/app/features/tech-record/components/tech-record-summary/tech-record-summary.component.ts index ce4a5a9a79..bc658d661c 100644 --- a/src/app/features/tech-record/components/tech-record-summary/tech-record-summary.component.ts +++ b/src/app/features/tech-record/components/tech-record-summary/tech-record-summary.component.ts @@ -156,7 +156,10 @@ export class TechRecordSummaryComponent implements OnInit, OnDestroy, AfterViewI }); this.form.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((changes) => { - this.handleFormState(changes); + // prevent merging of array of objects - always override + const isArray = (a: unknown, b: unknown) => (Array.isArray(a) ? b : undefined); + this.techRecordCalculated = mergeWith(cloneDeep(this.techRecordCalculated), changes, isArray); + this.technicalRecordService.updateEditingTechRecord(this.techRecordCalculated as TechRecordType<'put'>); }); } diff --git a/src/app/forms/components/autocomplete/__tests__/autocomplete.component.spec.ts b/src/app/forms/components/autocomplete/__tests__/autocomplete.component.spec.ts index c1b6e98d38..4a365c58d8 100644 --- a/src/app/forms/components/autocomplete/__tests__/autocomplete.component.spec.ts +++ b/src/app/forms/components/autocomplete/__tests__/autocomplete.component.spec.ts @@ -80,15 +80,15 @@ describe('AutocompleteComponent', () => { expect(control?.touched).toBeTruthy(); }); - it('should propagate "" to form control when input is left empty', () => { + it('should propagate null and reset to form control when input is cleared', () => { const findOptionValueSpy = jest.spyOn(autocompleteComponent, 'findOptionValue'); const control = component.form.get('foo'); autocompleteComponent.handleChange({ target: { value: '' } } as unknown as Event); expect(findOptionValueSpy).toHaveBeenCalled(); - expect(control?.value).toBe(''); - expect(control?.touched).toBeTruthy(); + expect(control?.value).toBeNull(); // use null to indicate the field is empty + expect(control?.touched).toBe(false); }); it('should propagate "[INVALID_OPTION]" to form control when value is not an option', () => { diff --git a/src/app/forms/components/autocomplete/autocomplete.component.ts b/src/app/forms/components/autocomplete/autocomplete.component.ts index 1effb9968d..5004987d5a 100644 --- a/src/app/forms/components/autocomplete/autocomplete.component.ts +++ b/src/app/forms/components/autocomplete/autocomplete.component.ts @@ -88,6 +88,13 @@ export class AutocompleteComponent extends BaseControlComponent implements After handleChangeForOption(value: string) { const optionValue = this.findOptionValue(value); + // Handle case where input is cleared fully, so it returns to default state without triggering validation + if (optionValue === '') { + this.control?.patchValue(null); + this.control?.markAsPristine(); + return; + } + this.control?.patchValue(optionValue ?? '[INVALID_OPTION]'); this.control?.markAsTouched(); this.control?.updateValueAndValidity(); diff --git a/src/app/forms/custom-sections/adr-section/adr-section-edit/adr-section-edit.component.ts b/src/app/forms/custom-sections/adr-section/adr-section-edit/adr-section-edit.component.ts index 3e42d175a0..ce24d7b648 100644 --- a/src/app/forms/custom-sections/adr-section/adr-section-edit/adr-section-edit.component.ts +++ b/src/app/forms/custom-sections/adr-section/adr-section-edit/adr-section-edit.component.ts @@ -1,6 +1,6 @@ import { ViewportScroller } from '@angular/common'; import { Component, OnDestroy, OnInit, inject, input } from '@angular/core'; -import { ControlContainer, FormBuilder, FormGroup } from '@angular/forms'; +import { ControlContainer, FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { ADRAdditionalNotesNumber } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrAdditionalNotesNumber.enum.js'; import { ADRBodyDeclarationTypes } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrBodyDeclarationType.enum.js'; @@ -131,12 +131,8 @@ export class AdrSectionEditComponent implements OnInit, OnDestroy { 'Reference number or UN number 1 is required when selecting Product List' ), ]), - techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: this.fb.array( - [ - this.fb.control(null, [ - this.commonValidators.maxLength(1500, 'UN number 1 must be less than or equal to 1500 characters'), - ]), - ], + techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: this.fb.array>( + [], [ this.adrValidators.requiresAllUnNumbersToBePopulated(), this.adrValidators.requiresAUnNumberOrReferenceNumber( @@ -312,9 +308,30 @@ export class AdrSectionEditComponent implements OnInit, OnDestroy { } handleInitialiseUNNumbers() { - this.techRecord()?.techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo?.forEach(() => - this.addUNNumber() - ); + const unNumbers = this.techRecord()?.techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo; + + // If there are un numbers, then prepopulate them + if (Array.isArray(unNumbers) && unNumbers.length > 0) { + unNumbers?.forEach((number, index) => { + this.form.controls.techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo.push( + this.fb.control(number, [ + this.commonValidators.maxLength( + 1500, + `UN number ${index + 1} must be less than or equal to 1500 characters` + ), + ]) + ); + }); + } + + // Otherwise, add a single empty UN number + else { + this.form.controls.techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo.push( + this.fb.control(null, [ + this.commonValidators.maxLength(1500, 'UN number 1 must be less than or equal to 1500 characters'), + ]) + ); + } } handleInitialiseSubsequentTankInspections() { diff --git a/src/app/forms/custom-sections/vehicle-section/vehicle-section-edit/vehicle-section-edit.component.html b/src/app/forms/custom-sections/vehicle-section/vehicle-section-edit/vehicle-section-edit.component.html index a17f097b77..eebabdbae4 100644 --- a/src/app/forms/custom-sections/vehicle-section/vehicle-section-edit/vehicle-section-edit.component.html +++ b/src/app/forms/custom-sections/vehicle-section/vehicle-section-edit/vehicle-section-edit.component.html @@ -132,7 +132,7 @@ label="Vehicle subclass" formControlName="techRecord_vehicleSubclass" [options]="VEHICLE_SUBCLASS_OPTIONS" - [tags]="[{ label: TagTypeLabels.REQUIRED, colour: TagType.RED }]" + [tags]="getVehicleType() !== VehicleTypes.SMALL_TRL ? [{ label: TagTypeLabels.REQUIRED, colour: TagType.RED }] : []" > @@ -301,6 +301,7 @@

formControlName="techRecord_euVehicleCategory" [width]="FormNodeWidth.S" [options]="EUCategoryOptions" + [tags]="getVehicleType() === VehicleTypes.SMALL_TRL ? [{ label: TagTypeLabels.REQUIRED, colour: TagType.RED }] : []" > diff --git a/src/app/forms/custom-sections/vehicle-section/vehicle-section-edit/vehicle-section-edit.component.ts b/src/app/forms/custom-sections/vehicle-section/vehicle-section-edit/vehicle-section-edit.component.ts index e4fd8c68cb..017ae8edec 100644 --- a/src/app/forms/custom-sections/vehicle-section/vehicle-section-edit/vehicle-section-edit.component.ts +++ b/src/app/forms/custom-sections/vehicle-section/vehicle-section-edit/vehicle-section-edit.component.ts @@ -29,6 +29,7 @@ import { MONTHS, PSV_EU_VEHICLE_CATEGORY_OPTIONS, PSV_VEHICLE_CLASS_DESCRIPTION_OPTIONS, + SMALL_TRL_EU_VEHICLE_CATEGORY_OPTIONS, SUSPENSION_TYRE_OPTIONS, TRL_VEHICLE_CLASS_DESCRIPTION_OPTIONS, TRL_VEHICLE_CONFIGURATION_OPTIONS, @@ -318,6 +319,8 @@ export class VehicleSectionEditComponent implements OnInit, OnDestroy { return HGV_EU_VEHICLE_CATEGORY_OPTIONS; case VehicleTypes.PSV: return PSV_EU_VEHICLE_CATEGORY_OPTIONS; + case VehicleTypes.SMALL_TRL: + return SMALL_TRL_EU_VEHICLE_CATEGORY_OPTIONS; default: return ALL_EU_VEHICLE_CATEGORY_OPTIONS; } diff --git a/src/app/forms/custom-sections/vehicle-section/vehicle-section-view/vehicle-section-view.component.html b/src/app/forms/custom-sections/vehicle-section/vehicle-section-view/vehicle-section-view.component.html index 203ea9fa80..df5c0e161e 100644 --- a/src/app/forms/custom-sections/vehicle-section/vehicle-section-view/vehicle-section-view.component.html +++ b/src/app/forms/custom-sections/vehicle-section/vehicle-section-view/vehicle-section-view.component.html @@ -30,10 +30,9 @@ {{ vm.techRecord_manufactureYear | defaultNullOrEmpty }} - -
+ + +
Date of first use
{{ vm.techRecord_firstUseDate | date: 'dd/MM/yyyy' | defaultNullOrEmpty }} @@ -229,6 +228,7 @@
+ +

Seats: @@ -308,5 +307,6 @@

{{ vm.techRecord_alterationMarker | defaultNullOrEmpty }}

- +
+
diff --git a/src/app/models/options.model.ts b/src/app/models/options.model.ts index aeff2a8d56..0da4e42d58 100644 --- a/src/app/models/options.model.ts +++ b/src/app/models/options.model.ts @@ -35,6 +35,11 @@ export const HGV_EU_VEHICLE_CATEGORY_OPTIONS: MultiOptions = getOptionsFromEnum( export const PSV_EU_VEHICLE_CATEGORY_OPTIONS: MultiOptions = getOptionsFromEnum(PSVCategories); +export const SMALL_TRL_EU_VEHICLE_CATEGORY_OPTIONS: MultiOptions = [ + { label: 'O1', value: EUVehicleCategory.O1 }, + { label: 'O2', value: EUVehicleCategory.O2 }, +]; + export const ALL_EU_VEHICLE_CATEGORY_OPTIONS: MultiOptions = getOptionsFromEnum(EUVehicleCategory); export const HGV_VEHICLE_CLASS_DESCRIPTION_OPTIONS: MultiOptions = [