diff --git a/src/app/forms/models/async-validators.enum.ts b/src/app/forms/models/async-validators.enum.ts index cec42b68f7..4232bbe6ff 100644 --- a/src/app/forms/models/async-validators.enum.ts +++ b/src/app/forms/models/async-validators.enum.ts @@ -10,5 +10,4 @@ export enum AsyncValidatorNames { HideIfEqualsWithCondition = 'hideIfEqualsWithCondition', PassResultDependantOnCustomDefects = 'passResultDependantOnCustomDefects', RequiredWhenCarryingDangerousGoods = 'requiredWhenCarryingDangerousGoods', - Custom = 'custom', } diff --git a/src/app/forms/models/validators.enum.ts b/src/app/forms/models/validators.enum.ts index 550695214e..d79b068524 100644 --- a/src/app/forms/models/validators.enum.ts +++ b/src/app/forms/models/validators.enum.ts @@ -46,5 +46,4 @@ export enum ValidatorNames { Tc3TestValidator = 'tc3TestValidator', DateIsInvalid = 'dateIsInvalid', MinArrayLengthIfNotEmpty = 'minArrayLengthIfNotEmpty', - IssueRequired = 'issueRequired', } diff --git a/src/app/forms/services/dynamic-form.service.ts b/src/app/forms/services/dynamic-form.service.ts index 67d69c5c77..61dff9f13c 100644 --- a/src/app/forms/services/dynamic-form.service.ts +++ b/src/app/forms/services/dynamic-form.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@angular/core'; import { - AsyncValidatorFn, FormArray, FormControl, FormGroup, ValidatorFn, Validators, + AsyncValidatorFn, FormArray, FormControl, FormGroup, + ValidatorFn, Validators, } from '@angular/forms'; import { GlobalError } from '@core/components/global-error/global-error.interface'; import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; @@ -24,7 +25,7 @@ type CustomFormFields = CustomFormControl | CustomFormArray | CustomFormGroup; providedIn: 'root', }) export class DynamicFormService { - constructor(private store: Store) {} + constructor(private store: Store) { } // eslint-disable-next-line @typescript-eslint/no-explicit-any validatorMap: Record ValidatorFn> = { @@ -54,7 +55,7 @@ export class DynamicFormService { [ValidatorNames.PastDate]: () => CustomValidators.pastDate, [ValidatorNames.Pattern]: (args: string) => Validators.pattern(args), [ValidatorNames.Required]: () => Validators.required, - [ValidatorNames.RequiredIfEquals]: (args: { sibling: string; value: unknown[]; customErrorMessage?: string }) => + [ValidatorNames.RequiredIfEquals]: (args: { sibling: string; value: unknown[], customErrorMessage?: string }) => CustomValidators.requiredIfEquals(args.sibling, args.value, args.customErrorMessage), [ValidatorNames.requiredIfAllEquals]: (args: { sibling: string; value: unknown[] }) => CustomValidators.requiredIfAllEquals(args.sibling, args.value), @@ -69,17 +70,17 @@ export class DynamicFormService { [ValidatorNames.IsMemberOfEnum]: (args: { enum: Record; options?: Partial }) => CustomValidators.isMemberOfEnum(args.enum, args.options), [ValidatorNames.UpdateFunctionCode]: () => CustomValidators.updateFunctionCode(), - [ValidatorNames.ShowGroupsWhenEqualTo]: (args: { values: unknown[]; groups: string[] }) => + [ValidatorNames.ShowGroupsWhenEqualTo]: (args: { values: unknown[], groups: string[] }) => CustomValidators.showGroupsWhenEqualTo(args.values, args.groups), - [ValidatorNames.HideGroupsWhenEqualTo]: (args: { values: unknown[]; groups: string[] }) => + [ValidatorNames.HideGroupsWhenEqualTo]: (args: { values: unknown[], groups: string[] }) => CustomValidators.hideGroupsWhenEqualTo(args.values, args.groups), - [ValidatorNames.ShowGroupsWhenIncludes]: (args: { values: unknown[]; groups: string[] }) => + [ValidatorNames.ShowGroupsWhenIncludes]: (args: { values: unknown[], groups: string[] }) => CustomValidators.showGroupsWhenIncludes(args.values, args.groups), - [ValidatorNames.HideGroupsWhenIncludes]: (args: { values: unknown[]; groups: string[] }) => + [ValidatorNames.HideGroupsWhenIncludes]: (args: { values: unknown[], groups: string[] }) => CustomValidators.hideGroupsWhenIncludes(args.values, args.groups), - [ValidatorNames.ShowGroupsWhenExcludes]: (args: { values: unknown[]; groups: string[] }) => + [ValidatorNames.ShowGroupsWhenExcludes]: (args: { values: unknown[], groups: string[] }) => CustomValidators.showGroupsWhenExcludes(args.values, args.groups), - [ValidatorNames.HideGroupsWhenExcludes]: (args: { values: unknown[]; groups: string[] }) => + [ValidatorNames.HideGroupsWhenExcludes]: (args: { values: unknown[], groups: string[] }) => CustomValidators.hideGroupsWhenExcludes(args.values, args.groups), [ValidatorNames.AddWarningForAdrField]: (warning: string) => CustomValidators.addWarningForAdrField(warning), [ValidatorNames.IsArray]: (args: Partial) => CustomValidators.isArray(args), @@ -87,9 +88,8 @@ export class DynamicFormService { [ValidatorNames.Tc3TestValidator]: (args: { inspectionNumber: number }) => CustomValidators.tc3TestValidator(args), [ValidatorNames.RequiredIfNotHidden]: () => CustomValidators.requiredIfNotHidden(), [ValidatorNames.DateIsInvalid]: () => CustomValidators.dateIsInvalid, - [ValidatorNames.MinArrayLengthIfNotEmpty]: (args: { minimumLength: number; message: string }) => + [ValidatorNames.MinArrayLengthIfNotEmpty]: (args: { minimumLength: number, message: string }) => CustomValidators.minArrayLengthIfNotEmpty(args.minimumLength, args.message), - [ValidatorNames.IssueRequired]: () => CustomValidators.issueRequired(), }; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -102,16 +102,13 @@ export class DynamicFormService { [AsyncValidatorNames.RequiredIfNotResult]: (args: { testResult: resultOfTestEnum | resultOfTestEnum[] }) => CustomAsyncValidators.requiredIfNotResult(this.store, args.testResult), [AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals]: (args: { - testResult: resultOfTestEnum | resultOfTestEnum[]; - sibling: string; - value: unknown; + testResult: resultOfTestEnum | resultOfTestEnum[]; sibling: string; value: unknown }) => CustomAsyncValidators.requiredIfNotResultAndSiblingEquals(this.store, args.testResult, args.sibling, args.value), [AsyncValidatorNames.ResultDependantOnCustomDefects]: () => CustomAsyncValidators.resultDependantOnCustomDefects(this.store), [AsyncValidatorNames.ResultDependantOnRequiredStandards]: () => CustomAsyncValidators.resultDependantOnRequiredStandards(this.store), [AsyncValidatorNames.UpdateTesterDetails]: () => CustomAsyncValidators.updateTesterDetails(this.store), [AsyncValidatorNames.UpdateTestStationDetails]: () => CustomAsyncValidators.updateTestStationDetails(this.store), [AsyncValidatorNames.RequiredWhenCarryingDangerousGoods]: () => CustomAsyncValidators.requiredWhenCarryingDangerousGoods(this.store), - [AsyncValidatorNames.Custom]: (...args) => CustomAsyncValidators.custom(this.store, ...args), }; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -224,20 +221,19 @@ export class DynamicFormService { Object.entries(errors).forEach(([error, data]) => { // If an anchor link is provided, use that, otherwise determine target element from customId or name const defaultAnchorLink = meta?.customId ?? meta?.name; - const anchorLink = typeof data === 'object' && data !== null ? data.anchorLink ?? defaultAnchorLink : defaultAnchorLink; + const anchorLink = typeof data === 'object' && data !== null + ? data.anchorLink ?? defaultAnchorLink + : defaultAnchorLink; // If typeof data is an array, assume we're passing the service multiple global errors - const globalErrors = Array.isArray(data) - ? data - : [ - { - error: meta?.customErrorMessage ?? ErrorMessageMap[`${error}`](data, meta?.customValidatorErrorName ?? meta?.label), - anchorLink, - }, - ]; + const globalErrors = Array.isArray(data) ? data : [{ + error: meta?.customErrorMessage ?? ErrorMessageMap[`${error}`](data, meta?.customValidatorErrorName ?? meta?.label), + anchorLink, + }]; validationErrorList.push(...globalErrors); }); } + } } diff --git a/src/app/forms/templates/test-records/create-master.template.ts b/src/app/forms/templates/test-records/create-master.template.ts index 5ae59ff5d3..a42180ab83 100644 --- a/src/app/forms/templates/test-records/create-master.template.ts +++ b/src/app/forms/templates/test-records/create-master.template.ts @@ -7,7 +7,6 @@ import { AdditionalDefectsSection } from './section-templates/additionalDefects/ import { CustomDefectsSection } from './section-templates/customDefects/custom-defects-section.template'; import { DeskBasedEmissionsSection } from './section-templates/emissions/desk-based-emissions-section.template'; import { EmissionsSection } from './section-templates/emissions/emissions-section.template'; -import { AdrNotesSection } from './section-templates/notes/adr-notes-section.template'; import { NotesSection } from './section-templates/notes/notes-section.template'; import { reasonForCreationHiddenSection, reasonForCreationSection } from './section-templates/reasonForCreation/reasonForCreation.template'; import { CreateRequiredSectionHgvTrl } from './section-templates/required/contingency-required-hidden-section-hgv-trl.template'; @@ -35,8 +34,6 @@ import { ContingencyTestSectionSpecialistGroup3And4, } from './section-templates/test/contingency/contingency-test-section-specialist-group3And4.template'; import { ContingencyTestSectionSpecialistGroup5 } from './section-templates/test/contingency/contingency-test-section-specialist-group5.template'; -import { OldIVAContingencyTestSectionSpecialistGroup1 } from './section-templates/test/contingency/old-contingency-specialist-group1.template'; -import { OldIVAContingencyTestSectionSpecialistGroup5 } from './section-templates/test/contingency/old-contingency-specialist-group5.template'; import { DeskBasedTestSectionGroup1Psv } from './section-templates/test/desk-based/desk-based-test-section-group1-PSV.template'; import { DeskBasedTestSectionGroup1And4HgvTrl as DeskBasedTestSectionGroup1And4And5HgvTrl, @@ -61,6 +58,8 @@ import { DeskBasedVehicleSectionGroup5Lgv } from './section-templates/vehicle/de import { VehicleSectionGroup3 } from './section-templates/vehicle/group-3-light-vehicle-section.template'; import { ContingencyVisitSection } from './section-templates/visit/contingency-visit-section.template'; import { VisitSection } from './section-templates/visit/visit-section.template'; +import { OldIVAContingencyTestSectionSpecialistGroup1 } from './section-templates/test/contingency/old-contingency-specialist-group1.template'; +import { OldIVAContingencyTestSectionSpecialistGroup5 } from './section-templates/test/contingency/old-contingency-specialist-group5.template'; const groups1and2Template: Record = { required: CreateRequiredSection, @@ -281,7 +280,7 @@ export const contingencyTestTemplates: Record) => { - return store.pipe( - select(testResultInEdit), - take(1), - map((testResult) => testResult?.testTypes.at(0)?.centralDocs?.issueRequired), - tap((issueRequired) => { - control.meta.hint = issueRequired ? 'Enter a reason for issuing documents centrally' : ''; - }), - map(() => null), - ); - }, - }, - ], - }, - ], - }, - ], - }, - ], -}; diff --git a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group15and16.template.ts b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group15and16.template.ts index e297897480..5cfdd2b459 100644 --- a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group15and16.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group15and16.template.ts @@ -51,38 +51,10 @@ export const ContingencyTestSectionGroup15and16: FormNode = { { value: 'pass', label: 'Pass' }, { value: 'fail', label: 'Fail' }, ], - validators: [ - { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'testExpiryDate', value: 'pass' } }, - { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'centralDocs', value: ['pass', 'prs'] } }, - ], + validators: [{ name: ValidatorNames.HideIfNotEqual, args: { sibling: 'testExpiryDate', value: 'pass' } }], asyncValidators: [{ name: AsyncValidatorNames.PassResultDependantOnCustomDefects }], type: FormNodeTypes.CONTROL, }, - { - name: 'centralDocs', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'issueRequired', - type: FormNodeTypes.CONTROL, - label: 'Issue documents centrally', - editType: FormNodeEditTypes.RADIO, - value: false, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.HideIfParentSiblingEqual, args: { sibling: 'certificateNumber', value: true } }], - }, - { - name: 'reasonsForIssue', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: [], - }, - ], - }, { name: 'reasonForAbandoning', type: FormNodeTypes.CONTROL, @@ -104,12 +76,7 @@ export const ContingencyTestSectionGroup15and16: FormNode = { label: 'Certificate number', type: FormNodeTypes.CONTROL, editType: FormNodeEditTypes.TEXT, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.Alphanumeric }, - // Make required if test result is pass/prs, but issue documents centrally is false - { name: ValidatorNames.IssueRequired }, - ], + validators: [{ name: ValidatorNames.Required }, { name: ValidatorNames.Alphanumeric }], viewType: FormNodeViewTypes.HIDDEN, required: true, value: null, diff --git a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group7.template.ts b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group7.template.ts index a0d95a1d62..93b7789397 100644 --- a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group7.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group7.template.ts @@ -56,36 +56,10 @@ export const ContingencyTestSectionGroup7: FormNode = { { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'certificateNumber', value: 'pass' } }, { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'generateCert', value: 'pass' } }, { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'testExpiryDate', value: 'pass' } }, - { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'centralDocs', value: 'pass' } }, ], asyncValidators: [{ name: AsyncValidatorNames.ResultDependantOnCustomDefects }], type: FormNodeTypes.CONTROL, }, - { - name: 'centralDocs', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'issueRequired', - type: FormNodeTypes.CONTROL, - label: 'Issue documents centrally', - editType: FormNodeEditTypes.RADIO, - value: false, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.HideIfParentSiblingEqual, args: { sibling: 'certificateNumber', value: true } }], - }, - { - name: 'reasonsForIssue', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: [], - }, - ], - }, { name: 'testTypeName', label: 'Description', @@ -129,8 +103,10 @@ export const ContingencyTestSectionGroup7: FormNode = { type: FormNodeTypes.CONTROL, validators: [ { name: ValidatorNames.Alphanumeric }, - // Make required if test result is pass/prs, but issue documents centrally is false - { name: ValidatorNames.IssueRequired }, + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'testResult', value: ['pass'] }, + }, ], required: true, value: null, diff --git a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-specialist-group1.template.ts b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-specialist-group1.template.ts index 9eb0df7116..1695c14877 100644 --- a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-specialist-group1.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-specialist-group1.template.ts @@ -53,7 +53,22 @@ export const ContingencyTestSectionSpecialistGroup1: FormNode = { { value: 'fail', label: 'Fail' }, { value: 'prs', label: 'PRS' }, ], - validators: [{ name: ValidatorNames.HideIfNotEqual, args: { sibling: 'centralDocs', value: ['pass', 'prs'] } }], + validators: [ + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: ['fail'], + groups: ['failOnly'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: ['fail'], + groups: ['failOnly'], + }, + }, + ], asyncValidators: [ { name: AsyncValidatorNames.ResultDependantOnRequiredStandards }, { @@ -67,31 +82,6 @@ export const ContingencyTestSectionSpecialistGroup1: FormNode = { ], type: FormNodeTypes.CONTROL, }, - { - name: 'centralDocs', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'issueRequired', - type: FormNodeTypes.CONTROL, - label: 'Issue documents centrally', - editType: FormNodeEditTypes.RADIO, - value: false, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.HideIfParentSiblingEqual, args: { sibling: 'certificateNumber', value: true } }], - }, - { - name: 'reasonsForIssue', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: [], - }, - ], - }, { name: 'testTypeName', label: 'Description', @@ -124,8 +114,16 @@ export const ContingencyTestSectionSpecialistGroup1: FormNode = { editType: FormNodeEditTypes.TEXT, validators: [ { name: ValidatorNames.Alphanumeric }, - // Make required if test result is pass/prs, but issue documents centrally is false - { name: ValidatorNames.IssueRequired }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'testResult', + value: [ + 'pass', + 'prs', + ], + }, + }, ], required: true, value: null, diff --git a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-specialist-group2.template.ts b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-specialist-group2.template.ts index 189d9e6696..d1b26533fc 100644 --- a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-specialist-group2.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-specialist-group2.template.ts @@ -52,12 +52,7 @@ export const ContingencyTestSectionSpecialistGroup2: FormNode = { { value: 'fail', label: 'Fail' }, { value: 'prs', label: 'PRS' }, ], - validators: [ - { - name: ValidatorNames.HideIfNotEqual, - args: { sibling: 'secondaryCertificateNumber', value: 'pass' }, - }, - ], + validators: [{ name: ValidatorNames.HideIfNotEqual, args: { sibling: 'secondaryCertificateNumber', value: 'pass' } }], asyncValidators: [{ name: AsyncValidatorNames.ResultDependantOnCustomDefects }], type: FormNodeTypes.CONTROL, }, @@ -66,6 +61,7 @@ export const ContingencyTestSectionSpecialistGroup2: FormNode = { label: 'Description', value: '', disabled: true, + type: FormNodeTypes.CONTROL, }, { diff --git a/src/app/forms/templates/test-records/section-templates/test/specialist/specialist-test-section-group1.template.ts b/src/app/forms/templates/test-records/section-templates/test/specialist/specialist-test-section-group1.template.ts index eea12026f3..f4e7e47952 100644 --- a/src/app/forms/templates/test-records/section-templates/test/specialist/specialist-test-section-group1.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/specialist/specialist-test-section-group1.template.ts @@ -60,7 +60,20 @@ export const SpecialistTestSectionGroup1: FormNode = { validators: [ { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'reasonForAbandoning', value: 'abandoned' } }, { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'additionalCommentsForAbandon', value: 'abandoned' } }, - { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'centralDocs', value: ['pass', 'prs'] } }, + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: ['fail'], + groups: ['failOnly'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: ['fail'], + groups: ['failOnly'], + }, + }, ], asyncValidators: [ { name: AsyncValidatorNames.ResultDependantOnRequiredStandards }, @@ -75,31 +88,6 @@ export const SpecialistTestSectionGroup1: FormNode = { ], type: FormNodeTypes.CONTROL, }, - { - name: 'centralDocs', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'issueRequired', - type: FormNodeTypes.CONTROL, - label: 'Issue documents centrally', - editType: FormNodeEditTypes.RADIO, - value: false, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.HideIfParentSiblingEqual, args: { sibling: 'certificateNumber', value: true } }], - }, - { - name: 'reasonsForIssue', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: [], - }, - ], - }, { name: 'reasonForAbandoning', type: FormNodeTypes.CONTROL, @@ -144,8 +132,13 @@ export const SpecialistTestSectionGroup1: FormNode = { editType: FormNodeEditTypes.TEXT, validators: [ { name: ValidatorNames.Alphanumeric }, - // Make required if test result is pass/prs, but issue documents centrally is false - { name: ValidatorNames.IssueRequired }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'testResult', + value: ['pass', 'prs'], + }, + }, ], viewType: FormNodeViewTypes.HIDDEN, width: FormNodeWidth.L, diff --git a/src/app/forms/templates/test-records/section-templates/test/test-section-group15And16.template.ts b/src/app/forms/templates/test-records/section-templates/test/test-section-group15And16.template.ts index 7e279c58cb..537f267498 100644 --- a/src/app/forms/templates/test-records/section-templates/test/test-section-group15And16.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/test-section-group15And16.template.ts @@ -59,36 +59,10 @@ export const TestSectionGroup15And16: FormNode = { { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'reasonForAbandoning', value: 'abandoned' } }, { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'additionalCommentsForAbandon', value: 'abandoned' } }, { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'testExpiryDate', value: ['pass', 'abandoned'] } }, - { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'centralDocs', value: ['pass', 'prs'] } }, ], asyncValidators: [{ name: AsyncValidatorNames.PassResultDependantOnCustomDefects }], type: FormNodeTypes.CONTROL, }, - { - name: 'centralDocs', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'issueRequired', - type: FormNodeTypes.CONTROL, - label: 'Issue documents centrally', - editType: FormNodeEditTypes.RADIO, - value: false, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.HideIfParentSiblingEqual, args: { sibling: 'certificateNumber', value: true } }], - }, - { - name: 'reasonsForIssue', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: [], - }, - ], - }, { name: 'reasonForAbandoning', type: FormNodeTypes.CONTROL, @@ -131,12 +105,7 @@ export const TestSectionGroup15And16: FormNode = { label: 'Certificate number', type: FormNodeTypes.CONTROL, editType: FormNodeEditTypes.TEXT, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.Alphanumeric }, - // Make required if test result is pass/prs, but issue documents centrally is false - { name: ValidatorNames.IssueRequired }, - ], + validators: [{ name: ValidatorNames.Required }, { name: ValidatorNames.Alphanumeric }], viewType: FormNodeViewTypes.HIDDEN, required: true, value: null, diff --git a/src/app/forms/templates/test-records/section-templates/test/test-section-group7.template.ts b/src/app/forms/templates/test-records/section-templates/test/test-section-group7.template.ts index d6634552b6..bc358b76c2 100644 --- a/src/app/forms/templates/test-records/section-templates/test/test-section-group7.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/test-section-group7.template.ts @@ -60,36 +60,10 @@ export const TestSectionGroup7: FormNode = { { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'reasonForAbandoning', value: 'abandoned' } }, { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'additionalCommentsForAbandon', value: 'abandoned' } }, { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'certificateNumber', value: ['pass', 'prs', 'abandoned'] } }, - { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'centralDocs', value: ['pass', 'prs'] } }, ], asyncValidators: [{ name: AsyncValidatorNames.ResultDependantOnCustomDefects }], type: FormNodeTypes.CONTROL, }, - { - name: 'centralDocs', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'issueRequired', - type: FormNodeTypes.CONTROL, - label: 'Issue documents centrally', - editType: FormNodeEditTypes.RADIO, - value: false, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.HideIfParentSiblingEqual, args: { sibling: 'certificateNumber', value: true } }], - }, - { - name: 'reasonsForIssue', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: [], - }, - ], - }, { name: 'testTypeName', label: 'Description', @@ -102,10 +76,6 @@ export const TestSectionGroup7: FormNode = { label: 'Certificate number', type: FormNodeTypes.CONTROL, viewType: FormNodeViewTypes.HIDDEN, - validators: [ - // Make required if test result is pass/prs, but issue documents centrally is false - { name: ValidatorNames.IssueRequired }, - ], required: true, value: null, }, diff --git a/src/app/forms/validators/custom-async-validators.ts b/src/app/forms/validators/custom-async-validators.ts index 6594efecbd..395ed33793 100644 --- a/src/app/forms/validators/custom-async-validators.ts +++ b/src/app/forms/validators/custom-async-validators.ts @@ -263,14 +263,4 @@ export class CustomAsyncValidators { return operator === operatorEnum.Equals ? isTrue : !isTrue; } - - static custom = ( - store: Store, - func: (...args: unknown[]) => Observable, - ...args: unknown[] - ) => { - return (control: AbstractControl): Observable => { - return func(control, store, ...args); - }; - }; } diff --git a/src/app/forms/validators/custom-validators.spec.ts b/src/app/forms/validators/custom-validators.spec.ts index 64e244323f..ca5fa5b20e 100644 --- a/src/app/forms/validators/custom-validators.spec.ts +++ b/src/app/forms/validators/custom-validators.spec.ts @@ -1,11 +1,19 @@ import { - AbstractControl, FormArray, FormControl, FormGroup, + AbstractControl, + FormArray, + FormControl, FormGroup, } from '@angular/forms'; import { ADRDangerousGood } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrDangerousGood.enum.js'; import { ApprovalType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/approvalType.enum.js'; -import { VehicleClassDescription } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleClassDescription.enum.js'; +import { + VehicleClassDescription, +} from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleClassDescription.enum.js'; import { ValidatorNames } from '@forms/models/validators.enum'; -import { CustomFormControl, CustomFormGroup, FormNodeTypes } from '@forms/services/dynamic-form.types'; +import { + CustomFormControl, + CustomFormGroup, + FormNodeTypes, +} from '@forms/services/dynamic-form.types'; import { VehicleSizes, VehicleTypes } from '@models/vehicle-tech-record.model'; import { CustomValidators } from './custom-validators'; @@ -365,9 +373,7 @@ describe('customPattern', () => { const validation = customPattern(new FormControl(input)); expect(validation).toEqual(expected); if (validation) { - const { - customPattern: { message }, - } = validation; + const { customPattern: { message } } = validation; // eslint-disable-next-line jest/no-conditional-expect expect(message).toEqual(msg); } else { @@ -731,31 +737,32 @@ describe('showGroupsWhenEqualTo', () => { { name: 'form-group', type: FormNodeTypes.GROUP, - children: [ - { - name: 'dangerousGoods', - value: false, - type: FormNodeTypes.CONTROL, - }, - { - name: 'techRecord_adrDetails_applicantDetails_name', - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['adr'], - }, - { - name: 'techRecord_adrDetails_applicantDetails_street', - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['adr'], - }, - { - name: 'techRecord_adrDetails_applicantDetails_town', - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['adr'], - }, - ], + children: + [ + { + name: 'dangerousGoods', + value: false, + type: FormNodeTypes.CONTROL, + }, + { + name: 'techRecord_adrDetails_applicantDetails_name', + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['adr'], + }, + { + name: 'techRecord_adrDetails_applicantDetails_street', + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['adr'], + }, + { + name: 'techRecord_adrDetails_applicantDetails_town', + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['adr'], + }, + ], }, { dangerousGoods: new CustomFormControl( @@ -860,31 +867,32 @@ describe('hideGroupsWhenEqualTo', () => { { name: 'form-group', type: FormNodeTypes.GROUP, - children: [ - { - name: 'dangerousGoods', - value: false, - type: FormNodeTypes.CONTROL, - }, - { - name: 'techRecord_adrDetails_applicantDetails_name', - type: FormNodeTypes.CONTROL, - hide: false, - groups: ['adr'], - }, - { - name: 'techRecord_adrDetails_applicantDetails_street', - type: FormNodeTypes.CONTROL, - hide: false, - groups: ['adr'], - }, - { - name: 'techRecord_adrDetails_applicantDetails_town', - type: FormNodeTypes.CONTROL, - hide: false, - groups: ['adr'], - }, - ], + children: + [ + { + name: 'dangerousGoods', + value: false, + type: FormNodeTypes.CONTROL, + }, + { + name: 'techRecord_adrDetails_applicantDetails_name', + type: FormNodeTypes.CONTROL, + hide: false, + groups: ['adr'], + }, + { + name: 'techRecord_adrDetails_applicantDetails_street', + type: FormNodeTypes.CONTROL, + hide: false, + groups: ['adr'], + }, + { + name: 'techRecord_adrDetails_applicantDetails_town', + type: FormNodeTypes.CONTROL, + hide: false, + groups: ['adr'], + }, + ], }, { dangerousGoods: new CustomFormControl( @@ -989,18 +997,19 @@ describe('addWarningIfFalse', () => { { name: 'form-group', type: FormNodeTypes.GROUP, - children: [ - { - name: 'dangerousGoods', - value: true, - type: FormNodeTypes.CONTROL, - }, - { - name: 'techRecord_adrDetails_applicantDetails_name', - type: FormNodeTypes.CONTROL, - hide: false, - }, - ], + children: + [ + { + name: 'dangerousGoods', + value: true, + type: FormNodeTypes.CONTROL, + }, + { + name: 'techRecord_adrDetails_applicantDetails_name', + type: FormNodeTypes.CONTROL, + hide: false, + }, + ], }, { dangerousGoods: new CustomFormControl( @@ -1136,19 +1145,20 @@ describe('showGroupsWhenIncludes', () => { { name: 'form-group', type: FormNodeTypes.GROUP, - children: [ - { - name: 'dangerousGoods', - value: false, - type: FormNodeTypes.CONTROL, - }, - { - name: 'techRecord_adrDetails_compatibilityGroupJ', - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['compat', 'details'], - }, - ], + children: + [ + { + name: 'dangerousGoods', + value: false, + type: FormNodeTypes.CONTROL, + }, + { + name: 'techRecord_adrDetails_compatibilityGroupJ', + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['compat', 'details'], + }, + ], }, { dangerousGoods: new CustomFormControl( @@ -1253,19 +1263,20 @@ describe('hideGroupsWhenIncludes', () => { { name: 'form-group', type: FormNodeTypes.GROUP, - children: [ - { - name: 'dangerousGoods', - value: false, - type: FormNodeTypes.CONTROL, - }, - { - name: 'techRecord_adrDetails_compatibilityGroupJ', - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['compat', 'details'], - }, - ], + children: + [ + { + name: 'dangerousGoods', + value: false, + type: FormNodeTypes.CONTROL, + }, + { + name: 'techRecord_adrDetails_compatibilityGroupJ', + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['compat', 'details'], + }, + ], }, { dangerousGoods: new CustomFormControl( @@ -1371,19 +1382,20 @@ describe('showGroupsWhenExcludes', () => { { name: 'form-group', type: FormNodeTypes.GROUP, - children: [ - { - name: 'dangerousGoods', - value: false, - type: FormNodeTypes.CONTROL, - }, - { - name: 'techRecord_adrDetails_compatibilityGroupJ', - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['compat', 'details'], - }, - ], + children: + [ + { + name: 'dangerousGoods', + value: false, + type: FormNodeTypes.CONTROL, + }, + { + name: 'techRecord_adrDetails_compatibilityGroupJ', + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['compat', 'details'], + }, + ], }, { dangerousGoods: new CustomFormControl( @@ -1487,19 +1499,20 @@ describe('hideGroupsWhenExcludes', () => { { name: 'form-group', type: FormNodeTypes.GROUP, - children: [ - { - name: 'dangerousGoods', - value: false, - type: FormNodeTypes.CONTROL, - }, - { - name: 'techRecord_adrDetails_compatibilityGroupJ', - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['compat', 'details'], - }, - ], + children: + [ + { + name: 'dangerousGoods', + value: false, + type: FormNodeTypes.CONTROL, + }, + { + name: 'techRecord_adrDetails_compatibilityGroupJ', + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['compat', 'details'], + }, + ], }, { dangerousGoods: new CustomFormControl( @@ -1606,13 +1619,14 @@ describe('isArray', () => { { name: 'form-group', type: FormNodeTypes.GROUP, - children: [ - { - name: 'techRecord_adrDetails_additionalNotes_number', - type: FormNodeTypes.CONTROL, - value: [], - }, - ], + children: + [ + { + name: 'techRecord_adrDetails_additionalNotes_number', + type: FormNodeTypes.CONTROL, + value: [], + }, + ], }, { techRecord_adrDetails_additionalNotes_number: new CustomFormControl( @@ -1690,61 +1704,63 @@ describe('tc3FieldTestValidator', () => { let form: FormGroup; beforeEach(() => { - form = new CustomFormGroup( - { - name: 'group', - label: 'Subsequent', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'tc3Type', - type: FormNodeTypes.CONTROL, - value: null, - label: 'TC3: Inspection Type', - }, - { - name: 'tc3PeriodicNumber', - label: 'TC3: Certificate Number', - value: null, - type: FormNodeTypes.CONTROL, - }, - { - name: 'tc3PeriodicExpiryDate', - label: 'TC3: Expiry Date', - type: FormNodeTypes.CONTROL, - value: null, - isoDate: false, - }, - ], - }, - { - tc3Type: new CustomFormControl({ + form = new CustomFormGroup({ + name: 'group', + label: 'Subsequent', + type: FormNodeTypes.GROUP, + children: [ + { name: 'tc3Type', type: FormNodeTypes.CONTROL, - }), - tc3PeriodicNumber: new CustomFormControl({ + value: null, + label: 'TC3: Inspection Type', + }, + { name: 'tc3PeriodicNumber', + label: 'TC3: Certificate Number', + value: null, type: FormNodeTypes.CONTROL, - }), - tc3PeriodicExpiryDate: new CustomFormControl({ + }, + { name: 'tc3PeriodicExpiryDate', + label: 'TC3: Expiry Date', type: FormNodeTypes.CONTROL, - }), - }, - ); + value: null, + isoDate: false, + }, + ], + }, { + tc3Type: new CustomFormControl({ + name: 'tc3Type', + type: FormNodeTypes.CONTROL, + }), + tc3PeriodicNumber: new CustomFormControl({ + name: 'tc3PeriodicNumber', + type: FormNodeTypes.CONTROL, + }), + tc3PeriodicExpiryDate: new CustomFormControl({ + name: 'tc3PeriodicExpiryDate', + type: FormNodeTypes.CONTROL, + }), + }); }); it('should give an error if all fields passed to the validator are null', () => { const type = form.get('tc3Type') as CustomFormControl; - const validator = CustomValidators.tc3TestValidator({ - inspectionNumber: 1, - })(type as AbstractControl); + const validator = CustomValidators.tc3TestValidator( + { + inspectionNumber: 1, + }, + )(type as AbstractControl); - expect(validator).toEqual({ - tc3TestValidator: { - message: 'TC3 Subsequent inspection 1 must have at least one populated field', + expect(validator).toEqual( + { + tc3TestValidator: + { + message: 'TC3 Subsequent inspection 1 must have at least one populated field', + }, }, - }); + ); }); it('should give an error if fields passed to the validator are undefined', () => { const type = form.get('tc3Type') as CustomFormControl; @@ -1755,15 +1771,20 @@ describe('tc3FieldTestValidator', () => { date.patchValue(undefined); number.patchValue(undefined); - const validator = CustomValidators.tc3TestValidator({ - inspectionNumber: 1, - })(type as AbstractControl); + const validator = CustomValidators.tc3TestValidator( + { + inspectionNumber: 1, + }, + )(type as AbstractControl); - expect(validator).toEqual({ - tc3TestValidator: { - message: 'TC3 Subsequent inspection 1 must have at least one populated field', + expect(validator).toEqual( + { + tc3TestValidator: + { + message: 'TC3 Subsequent inspection 1 must have at least one populated field', + }, }, - }); + ); }); it('should give an error if fields passed to the validator are empty strings', () => { const type = form.get('tc3Type') as CustomFormControl; @@ -1774,15 +1795,20 @@ describe('tc3FieldTestValidator', () => { date.patchValue(''); number.patchValue(''); - const validator = CustomValidators.tc3TestValidator({ - inspectionNumber: 1, - })(type as AbstractControl); + const validator = CustomValidators.tc3TestValidator( + { + inspectionNumber: 1, + }, + )(type as AbstractControl); - expect(validator).toEqual({ - tc3TestValidator: { - message: 'TC3 Subsequent inspection 1 must have at least one populated field', + expect(validator).toEqual( + { + tc3TestValidator: + { + message: 'TC3 Subsequent inspection 1 must have at least one populated field', + }, }, - }); + ); }); it('should give an error if fields to the validator have a variety of empty values', () => { const type = form.get('tc3Type') as CustomFormControl; @@ -1793,15 +1819,20 @@ describe('tc3FieldTestValidator', () => { date.patchValue(null); number.patchValue(undefined); - const validator = CustomValidators.tc3TestValidator({ - inspectionNumber: 1, - })(type as AbstractControl); + const validator = CustomValidators.tc3TestValidator( + { + inspectionNumber: 1, + }, + )(type as AbstractControl); - expect(validator).toEqual({ - tc3TestValidator: { - message: 'TC3 Subsequent inspection 1 must have at least one populated field', + expect(validator).toEqual( + { + tc3TestValidator: + { + message: 'TC3 Subsequent inspection 1 must have at least one populated field', + }, }, - }); + ); }); it('should return null if one field passed to the validator has a value', () => { const type = form.get('tc3Type') as CustomFormControl; @@ -1809,9 +1840,11 @@ describe('tc3FieldTestValidator', () => { number.patchValue('test'); - const validator = CustomValidators.tc3TestValidator({ - inspectionNumber: 1, - })(type as AbstractControl); + const validator = CustomValidators.tc3TestValidator( + { + inspectionNumber: 1, + }, + )(type as AbstractControl); expect(validator).toBeNull(); }); @@ -1821,26 +1854,23 @@ describe('tc3ParentValidator', () => { let form: FormGroup; beforeEach(() => { - form = new CustomFormGroup( - { - name: 'group', - label: 'Subsequent', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'techRecord_adrDetails_tank_tankDetails_tc3Details', - type: FormNodeTypes.CONTROL, - value: null, - }, - ], - }, - { - techRecord_adrDetails_tank_tankDetails_tc3Details: new CustomFormControl({ + form = new CustomFormGroup({ + name: 'group', + label: 'Subsequent', + type: FormNodeTypes.GROUP, + children: [ + { name: 'techRecord_adrDetails_tank_tankDetails_tc3Details', type: FormNodeTypes.CONTROL, - }), - }, - ); + value: null, + }, + ], + }, { + techRecord_adrDetails_tank_tankDetails_tc3Details: new CustomFormControl({ + name: 'techRecord_adrDetails_tank_tankDetails_tc3Details', + type: FormNodeTypes.CONTROL, + }), + }); }); it('should give an error if value contains a test with all null values', () => { const details = form.get('techRecord_adrDetails_tank_tankDetails_tc3Details') as CustomFormControl; @@ -1849,11 +1879,14 @@ describe('tc3ParentValidator', () => { const validator = CustomValidators.tc3TestValidator({ inspectionNumber: 0 })(details as AbstractControl); - expect(validator).toEqual({ - tc3TestValidator: { - message: 'TC3 Subsequent inspection 1 must have at least one populated field', + expect(validator).toEqual( + { + tc3TestValidator: + { + message: 'TC3 Subsequent inspection 1 must have at least one populated field', + }, }, - }); + ); }); it('should give an error if fields passed to the validator are undefined', () => { const details = form.get('techRecord_adrDetails_tank_tankDetails_tc3Details') as CustomFormControl; @@ -1862,11 +1895,14 @@ describe('tc3ParentValidator', () => { const validator = CustomValidators.tc3TestValidator({ inspectionNumber: 0 })(details as AbstractControl); - expect(validator).toEqual({ - tc3TestValidator: { - message: 'TC3 Subsequent inspection 1 must have at least one populated field', + expect(validator).toEqual( + { + tc3TestValidator: + { + message: 'TC3 Subsequent inspection 1 must have at least one populated field', + }, }, - }); + ); }); it('should give an error if fields passed to the validator are empty strings', () => { const details = form.get('techRecord_adrDetails_tank_tankDetails_tc3Details') as CustomFormControl; @@ -1875,11 +1911,14 @@ describe('tc3ParentValidator', () => { const validator = CustomValidators.tc3TestValidator({ inspectionNumber: 0 })(details as AbstractControl); - expect(validator).toEqual({ - tc3TestValidator: { - message: 'TC3 Subsequent inspection 1 must have at least one populated field', + expect(validator).toEqual( + { + tc3TestValidator: + { + message: 'TC3 Subsequent inspection 1 must have at least one populated field', + }, }, - }); + ); }); it('should give an error if fields to the validator have a variety of empty values', () => { const details = form.get('techRecord_adrDetails_tank_tankDetails_tc3Details') as CustomFormControl; @@ -1888,11 +1927,14 @@ describe('tc3ParentValidator', () => { const validator = CustomValidators.tc3TestValidator({ inspectionNumber: 0 })(details as AbstractControl); - expect(validator).toEqual({ - tc3TestValidator: { - message: 'TC3 Subsequent inspection 1 must have at least one populated field', + expect(validator).toEqual( + { + tc3TestValidator: + { + message: 'TC3 Subsequent inspection 1 must have at least one populated field', + }, }, - }); + ); }); it('should tell you which test needs to be filled out', () => { const details = form.get('techRecord_adrDetails_tank_tankDetails_tc3Details') as CustomFormControl; @@ -1905,11 +1947,14 @@ describe('tc3ParentValidator', () => { const validator = CustomValidators.tc3TestValidator({ inspectionNumber: 0 })(details as AbstractControl); - expect(validator).toEqual({ - tc3TestValidator: { - message: 'TC3 Subsequent inspection 2 must have at least one populated field', + expect(validator).toEqual( + { + tc3TestValidator: + { + message: 'TC3 Subsequent inspection 2 must have at least one populated field', + }, }, - }); + ); }); it('should tell you which test needs to be filled out if there are multiple', () => { const details = form.get('techRecord_adrDetails_tank_tankDetails_tc3Details') as CustomFormControl; @@ -1924,11 +1969,14 @@ describe('tc3ParentValidator', () => { const validator = CustomValidators.tc3TestValidator({ inspectionNumber: 0 })(details as AbstractControl); - expect(validator).toEqual({ - tc3TestValidator: { - message: 'TC3 Subsequent inspection 2, 4, 5 must have at least one populated field', + expect(validator).toEqual( + { + tc3TestValidator: + { + message: 'TC3 Subsequent inspection 2, 4, 5 must have at least one populated field', + }, }, - }); + ); }); it('should return null if one field passed to the validator has a value', () => { const details = form.get('techRecord_adrDetails_tank_tankDetails_tc3Details') as CustomFormControl; @@ -1988,11 +2036,9 @@ describe('minArrayLengthIfNotEmpty', () => { }), ]); - expect(CustomValidators.minArrayLengthIfNotEmpty(2, 'Error message')(formArray)).toStrictEqual( - expect.objectContaining({ - minArrayLengthIfNotEmpty: { message: 'Error message' }, - }), - ); + expect(CustomValidators.minArrayLengthIfNotEmpty(2, 'Error message')(formArray)).toStrictEqual(expect.objectContaining({ + minArrayLengthIfNotEmpty: { message: 'Error message' }, + })); }); it('should return null if the minimum length is reached', () => { @@ -2026,63 +2072,3 @@ describe('minArrayLengthIfNotEmpty', () => { expect(CustomValidators.minArrayLengthIfNotEmpty(2, 'Error message')(formArray)).toBeNull(); }); }); - -describe('IssueRequired', () => { - let form: FormGroup; - - beforeEach(() => { - form = new FormGroup({ - testResult: new CustomFormControl({ type: FormNodeTypes.CONTROL, name: 'testResult' }, 'pass'), - certificateNumber: new CustomFormControl({ type: FormNodeTypes.CONTROL, name: 'certificateNumber' }, null), - centralDocs: new CustomFormGroup( - { - name: 'centralDocs', - type: FormNodeTypes.GROUP, - children: [{ type: FormNodeTypes.CONTROL, name: 'issueRequired' }], - }, - { - issueRequired: new CustomFormControl({ type: FormNodeTypes.CONTROL, name: 'issueRequired' }, true), - }, - ), - }); - }); - - describe('when issueRequired is true', () => { - beforeEach(() => { - form.get(['centralDocs', 'issueRequired'])?.patchValue(true); - }); - - it('should return null when testResult is prs', () => { - form.get('testResult')?.patchValue('prs'); - const control = form.get('certificateNumber') as FormControl; - expect(CustomValidators.issueRequired()(control)).toBeNull(); - }); - - it('should return null when testResult is pass', () => { - form.get('testResult')?.patchValue('pass'); - const control = form.get('certificateNumber') as FormControl; - expect(CustomValidators.issueRequired()(control)).toBeNull(); - }); - }); - - describe('when issueRequired is false', () => { - beforeEach(() => { - form.get(['centralDocs', 'issueRequired'])?.patchValue(false); - }); - it('should return null when testResult is pass, but the control is populated', () => { - form.get('testResult')?.patchValue('pass'); - const control = form.get('certificateNumber') as FormControl; - control.patchValue('value'); - expect(CustomValidators.issueRequired()(control)).toBeNull(); - }); - - it('should return error when testResult is pass, but the control is not populated', () => { - form.get('testResult')?.patchValue('pass'); - const control = form.get('certificateNumber') as FormControl; - control.patchValue(null); - expect(CustomValidators.issueRequired()(control)).toEqual({ - requiredIfEquals: { customErrorMessage: undefined, sibling: undefined }, - }); - }); - }); -}); diff --git a/src/app/forms/validators/custom-validators.ts b/src/app/forms/validators/custom-validators.ts index e93ffdc8bc..41994a60c9 100644 --- a/src/app/forms/validators/custom-validators.ts +++ b/src/app/forms/validators/custom-validators.ts @@ -1,4 +1,6 @@ -import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; +import { + AbstractControl, ValidationErrors, ValidatorFn, +} from '@angular/forms'; import { VehicleClassDescription } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleClassDescription.enum.js'; // eslint-disable-next-line import/no-cycle import { CustomFormControl, CustomFormGroup } from '@forms/services/dynamic-form.types'; @@ -137,14 +139,18 @@ export class CustomValidators { const isSiblingVisible = !siblingControl.meta.hide; - const isSiblingValueIncluded = Array.isArray(siblingValue) ? siblingValue.every((val) => values.includes(val)) : values.includes(siblingValue); + const isSiblingValueIncluded = Array.isArray(siblingValue) + ? siblingValue.every((val) => values.includes(val)) + : values.includes(siblingValue); const isControlValueEmpty = control.value === null || control.value === undefined || control.value === '' || (Array.isArray(control.value) && (control.value.length === 0 || control.value.every((val) => !val))); - return isSiblingValueIncluded && isControlValueEmpty && isSiblingVisible ? { requiredIfEquals: { sibling: siblingControl.meta.label } } : null; + return isSiblingValueIncluded && isControlValueEmpty && isSiblingVisible + ? { requiredIfEquals: { sibling: siblingControl.meta.label } } + : null; }; static requiredIfNotEquals = (sibling: string, value: unknown): ValidatorFn => { @@ -499,7 +505,9 @@ export class CustomValidators { const { sibling, value } = options.whenEquals; const siblingControl = control.parent?.get(sibling); const siblingValue = siblingControl?.value; - const isSiblingValueIncluded = Array.isArray(siblingValue) ? value.some((v) => siblingValue.includes(v)) : value.includes(siblingValue); + const isSiblingValueIncluded = Array.isArray(siblingValue) + ? value.some((v) => siblingValue.includes(v)) + : value.includes(siblingValue); if (!isSiblingValueIncluded) return null; } @@ -508,12 +516,16 @@ export class CustomValidators { if (options.ofType) { const index = control.value.findIndex((val) => typeof val !== options.ofType); - return index === -1 ? null : { isArray: { message: `${index + 1} must be of type ${options.ofType}` } }; + return index === -1 + ? null + : { isArray: { message: `${index + 1} must be of type ${options.ofType}` } }; } if (options.requiredIndices) { const index = control.value.findIndex((val, i) => options.requiredIndices?.includes(i) && !val); - return index === -1 ? null : { isArray: { message: `${index + 1} is required` } }; + return index === -1 + ? null + : { isArray: { message: `${index + 1} is required` } }; } return null; @@ -568,19 +580,6 @@ export class CustomValidators { return null; }; }; - - static issueRequired = (): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - const isPRS = control.parent?.value.testResult === 'prs'; - const isPass = control.parent?.value.testResult === 'pass'; - const issueRequired = control.parent?.value.centralDocs?.issueRequired; - if ((isPRS || isPass) && issueRequired) { - return null; - } - - return CustomValidators.requiredIfEquals('testResult', ['pass'])(control); - }; - }; } export type EnumValidatorOptions = { @@ -590,10 +589,10 @@ export type EnumValidatorOptions = { export type IsArrayValidatorOptions = { ofType: string; requiredIndices: number[]; - whenEquals: { sibling: string; value: unknown[] }; + whenEquals: { sibling: string, value: unknown[] } }; -const areTc3FieldsEmpty = (values: { tc3Type: string; tc3PeriodicNumber: string; tc3PeriodicExpiryDate: string }[]) => { +const areTc3FieldsEmpty = (values: { tc3Type: string, tc3PeriodicNumber: string, tc3PeriodicExpiryDate: string }[]) => { const isValueEmpty: boolean[] = []; values.forEach((value) => { diff --git a/src/app/models/test-types/test-type.model.ts b/src/app/models/test-types/test-type.model.ts index e058699035..e3939849ef 100644 --- a/src/app/models/test-types/test-type.model.ts +++ b/src/app/models/test-types/test-type.model.ts @@ -39,15 +39,6 @@ export interface TestType { certificateLink?: string | null; deletionFlag?: boolean; secondaryCertificateNumber?: string | null; - reapplicationDate?: string; - - centralDocs?: CentralDocs; -} - -export interface CentralDocs { - issueRequired: boolean; - notes?: string; - reasonsForIssue?: string[]; } export interface CustomDefects { diff --git a/src/app/store/test-records/reducers/test-records.reducer.ts b/src/app/store/test-records/reducers/test-records.reducer.ts index f54cd8081b..aed052d4f7 100644 --- a/src/app/store/test-records/reducers/test-records.reducer.ts +++ b/src/app/store/test-records/reducers/test-records.reducer.ts @@ -50,7 +50,7 @@ interface Extras { sectionTemplates?: FormNode[]; } -export interface TestResultsState extends EntityState, Extras {} +export interface TestResultsState extends EntityState, Extras { } const selectTestResultId = (a: TestResultModel): string => { return a.testResultId; @@ -100,23 +100,15 @@ export const testResultsReducer = createReducer( on(updateDefect, (state, action) => ({ ...state, editingTestResult: updateDefectAtIndex(state.editingTestResult, action.defect, action.index) })), on(removeDefect, (state, action) => ({ ...state, editingTestResult: removeDefectAtIndex(state.editingTestResult, action.index) })), - on(createRequiredStandard, (state, action) => ({ - ...state, - editingTestResult: createNewRequiredStandard(state.editingTestResult, action.requiredStandard), - })), - on(updateRequiredStandard, (state, action) => ({ - ...state, - editingTestResult: updateRequiredStandardAtIndex(state.editingTestResult, action.requiredStandard, action.index), - })), - on(removeRequiredStandard, (state, action) => ({ - ...state, - editingTestResult: removeRequiredStandardAtIndex(state.editingTestResult, action.index), - })), + on(createRequiredStandard, (state, action) => + ({ ...state, editingTestResult: createNewRequiredStandard(state.editingTestResult, action.requiredStandard) })), + on(updateRequiredStandard, (state, action) => + ({ ...state, editingTestResult: updateRequiredStandardAtIndex(state.editingTestResult, action.requiredStandard, action.index) })), + on(removeRequiredStandard, (state, action) => + ({ ...state, editingTestResult: removeRequiredStandardAtIndex(state.editingTestResult, action.index) })), - on(updateResultOfTestRequiredStandards, (state) => ({ - ...state, - editingTestResult: calculateTestResultRequiredStandards(state.editingTestResult), - })), + on(updateResultOfTestRequiredStandards, (state) => + ({ ...state, editingTestResult: calculateTestResultRequiredStandards(state.editingTestResult) })), on(cleanTestResult, (state) => ({ ...state, editingTestResult: cleanTestResultPayload(state.editingTestResult) })), ); @@ -138,38 +130,13 @@ function createNewRequiredStandard(testResultState: TestResultModel | undefined, } function cleanTestResultPayload(testResult: TestResultModel | undefined) { - if (!testResult || !testResult.testTypes) { - return testResult; - } - - const testTypes = testResult.testTypes.map((testType, index) => { - // Remove empty requiredStandards from pass/prs non-voluntary IVA/MVSA tests - if (index === 0) { - const { testTypeId, requiredStandards } = testType; - const isGroup1SpecTest = TEST_TYPES_GROUP1_SPEC_TEST.includes(testTypeId); - const isGroup5SpecTest = TEST_TYPES_GROUP5_SPEC_TEST.includes(testTypeId); - if ((isGroup1SpecTest || isGroup5SpecTest) && !(requiredStandards ?? []).length) { - delete testType.requiredStandards; - } - } - - // If the test type is a fail/cancel/abandon, and issueRequired is true, set it to false - const isFail = testType.testResult === resultOfTestEnum.fail; - const isAbandon = testType.testResult === resultOfTestEnum.abandoned; - if ((isFail || isAbandon) && testType.centralDocs?.issueRequired) { - testType.centralDocs.issueRequired = false; + if (testResult?.testTypes?.at(0)) { + const { testTypeId, requiredStandards } = testResult.testTypes[0]; + if ((TEST_TYPES_GROUP1_SPEC_TEST.includes(testTypeId) || TEST_TYPES_GROUP5_SPEC_TEST.includes(testTypeId)) && !(requiredStandards ?? []).length) { + delete testResult.testTypes[0].requiredStandards; } - - // If test type has issueRequired set to true, set the certificateNumber/secondaryCertificateNumber to 000000 - if (testType.centralDocs?.issueRequired) { - testType.certificateNumber = '000000'; - testType.secondaryCertificateNumber = '000000'; - } - - return testType; - }); - - return { ...testResult, testTypes }; + } + return testResult; } function updateRequiredStandardAtIndex(testResultState: TestResultModel | undefined, requiredStandard: TestResultRequiredStandard, index: number) { @@ -256,7 +223,9 @@ function calculateTestResult(testResultState: TestResultModel | undefined): Test } const failOrPrs = testType.defects.some( - (defect) => defect.deficiencyCategory === DeficiencyCategoryEnum.Major || defect.deficiencyCategory === DeficiencyCategoryEnum.Dangerous, + (defect) => + defect.deficiencyCategory === DeficiencyCategoryEnum.Major + || defect.deficiencyCategory === DeficiencyCategoryEnum.Dangerous, ); if (!failOrPrs) { testType.testResult = resultOfTestEnum.pass; @@ -295,7 +264,11 @@ function calculateTestResultRequiredStandards(testResultState: TestResultModel | return testType; } - testType.testResult = testType.requiredStandards.every((rs) => rs.prs) ? resultOfTestEnum.prs : resultOfTestEnum.fail; + testType.testResult = testType.requiredStandards.every( + (rs) => rs.prs, + ) + ? resultOfTestEnum.prs + : resultOfTestEnum.fail; return testType; });