From c45abcd9e8a9db4fb6dccfc0f44516357609fc39 Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Tue, 13 Aug 2024 11:55:56 +0100 Subject: [PATCH 01/21] feat(linting-1): biome intro --- .gitignore | 1 - biome.json | 3 + package-lock.json | 10328 +++++----------- package.json | 22 +- src/app/accessible-autocomplete.d.ts | 42 +- .../api/document-retrieval.service.ts | 374 +- .../api/document-retrieval/configuration.ts | 139 +- .../document-retrieval-api.module.ts | 43 +- src/app/api/document-retrieval/encoder.ts | 16 +- src/app/api/reference-data/api.module.ts | 47 +- .../api/referenceData.service.ts | 1070 +- src/app/api/reference-data/configuration.ts | 139 +- src/app/api/reference-data/encoder.ts | 27 +- src/app/api/reference-data/index.ts | 2 +- .../api/reference-data/model/deleteItem.ts | 6 +- .../api/reference-data/model/emptyObject.ts | 3 +- .../model/referenceDataApiResponse.ts | 4 +- .../referenceDataApiResponseWithPagination.ts | 7 +- ...ferenceDataApiResponseWithoutPagination.ts | 6 +- .../reference-data/model/referenceDataItem.ts | 10 +- .../model/referenceDataItemApiResponse.ts | 2 +- .../api/reference-data/model/resourceKey.ts | 2 +- src/app/api/reference-data/variables.ts | 10 +- src/app/api/test-results/api.module.ts | 50 +- .../api/archiveTestResults.service.ts | 216 +- .../api/test-results/api/default.service.ts | 187 +- .../api/getTestResults.service.ts | 261 +- .../api/updateTestResults.service.ts | 214 +- src/app/api/test-results/configuration.ts | 139 +- src/app/api/test-results/encoder.ts | 16 +- src/app/api/test-results/index.ts | 2 +- .../test-results/model/completeTestResults.ts | 411 +- .../model/completeTestResultsVehicleClass.ts | 75 +- .../api/test-results/model/customDefect.ts | 10 +- .../api/test-results/model/customDefects.ts | 3 +- src/app/api/test-results/model/defect.ts | 50 +- .../model/defectAdditionalInformation.ts | 8 +- .../defectAdditionalInformationLocation.ts | 60 +- src/app/api/test-results/model/defects.ts | 3 +- src/app/api/test-results/model/testResults.ts | 3 +- .../api/test-results/model/testTypeRecords.ts | 3 +- .../api/test-results/model/testTypeResults.ts | 257 +- .../model/testTypeResultsModType.ts | 32 +- src/app/api/test-results/model/testTypes.ts | 3 +- src/app/api/test-results/variables.ts | 10 +- src/app/api/test-types/api.module.ts | 47 +- .../api/test-types/api/testTypes.service.ts | 433 +- src/app/api/test-types/configuration.ts | 139 +- src/app/api/test-types/encoder.ts | 27 +- src/app/api/test-types/index.ts | 2 +- src/app/api/test-types/model/testType.ts | 176 +- .../api/test-types/model/testTypeCategory.ts | 158 +- src/app/api/test-types/model/testTypeInfo.ts | 30 +- .../api/test-types/model/testTypesTaxonomy.ts | 3 +- src/app/api/test-types/variables.ts | 10 +- src/app/api/vehicle/api.module.ts | 57 +- .../api/addProvisionalTechRecord.service.ts | 214 +- src/app/api/vehicle/api/api.ts | 8 +- .../api/archiveTechRecordStatus.service.ts | 214 +- .../api/vehicle/api/getTechRecords.service.ts | 235 +- .../vehicle/api/postTechRecords.service.ts | 188 +- .../vehicle/api/updateTechRecords.service.ts | 234 +- src/app/api/vehicle/configuration.ts | 139 +- src/app/api/vehicle/encoder.ts | 16 +- src/app/api/vehicle/index.ts | 2 +- src/app/api/vehicle/model/adrDetails.ts | 106 +- .../model/adrDetailsAdditionalNotes.ts | 20 +- .../model/adrDetailsApplicantDetails.ts | 14 +- src/app/api/vehicle/model/adrDetailsTank.ts | 8 +- .../model/adrDetailsTankTankDetails.ts | 56 +- .../adrDetailsTankTankDetailsTc2Details.ts | 36 +- .../adrDetailsTankTankDetailsTc3Details.ts | 36 +- .../model/adrDetailsTankTankStatement.ts | 44 +- .../vehicle/model/adrDetailsVehicleDetails.ts | 20 +- .../model/applicantDetailsProperties.ts | 20 +- src/app/api/vehicle/model/authIntoService.ts | 44 +- .../api/vehicle/model/axleBrakeProperties.ts | 10 +- .../api/vehicle/model/axleTyreProperties.ts | 113 +- .../api/vehicle/model/axleWeightProperties.ts | 44 +- src/app/api/vehicle/model/axles.ts | 3 +- .../model/brakeForceWheelsNotLocked.ts | 28 +- .../model/brakeForceWheelsUpToHalfLocked.ts | 28 +- src/app/api/vehicle/model/brakes.ts | 124 +- .../api/vehicle/model/completeTechRecord.ts | 34 +- .../api/vehicle/model/completeTechRecordDB.ts | 36 +- .../vehicle/model/completeTechRecordPUT.ts | 32 +- .../api/vehicle/model/completeTechRecords.ts | 3 +- src/app/api/vehicle/model/dda.ts | 100 +- src/app/api/vehicle/model/lettersOfAuth.ts | 38 +- .../api/vehicle/model/manufacturerDetails.ts | 24 +- src/app/api/vehicle/model/metadata.ts | 16 +- .../api/vehicle/model/metadataAdrDetails.ts | 52 +- .../metadataAdrDetailsAdditionalNotes.ts | 34 +- .../vehicle/model/metadataAdrDetailsTank.ts | 6 +- .../metadataAdrDetailsTankTankStatement.ts | 20 +- .../model/metadataAdrDetailsVehicleDetails.ts | 75 +- src/app/api/vehicle/model/microfilm.ts | 199 +- src/app/api/vehicle/model/plates.ts | 3 +- src/app/api/vehicle/model/platesInner.ts | 68 +- src/app/api/vehicle/model/purchaserDetails.ts | 24 +- src/app/api/vehicle/model/techRecord.ts | 933 +- .../techRecordArchiveAndProvisionalPayload.ts | 8 +- ...chiveAndProvisionalPayloadMsUserDetails.ts | 8 +- .../api/vehicle/model/techRecordBodyType.ts | 141 +- .../api/vehicle/model/techRecordDimensions.ts | 36 +- .../model/techRecordDimensionsAxleSpacing.ts | 14 +- src/app/api/vehicle/model/techRecordPOST.ts | 40 +- src/app/api/vehicle/model/techRecordPUT.ts | 32 +- .../vehicle/model/techRecordVehicleClass.ts | 75 +- src/app/api/vehicle/model/techRecords.ts | 3 +- src/app/api/vehicle/model/vrm.ts | 8 +- src/app/api/vehicle/model/vrms.ts | 3 +- src/app/api/vehicle/model/weights.ts | 26 +- src/app/api/vehicle/variables.ts | 10 +- src/app/app-routing.module.ts | 143 +- src/app/app.component.spec.ts | 232 +- src/app/app.component.ts | 121 +- src/app/app.module.ts | 254 +- src/app/app.stories.ts | 6 +- .../breadcrumbs/breadcrumbs.component.spec.ts | 165 +- .../breadcrumbs/breadcrumbs.component.ts | 56 +- .../footer/footer.component.spec.ts | 30 +- .../components/footer/footer.component.ts | 4 +- .../core/components/footer/footer.stories.ts | 6 +- .../global-error.component.spec.ts | 54 +- .../global-error/global-error.component.ts | 31 +- .../global-error/global-error.interface.ts | 4 +- .../global-error/global-error.service.spec.ts | 88 +- .../global-error/global-error.service.ts | 65 +- .../global-error/global-error.stories.ts | 8 +- .../global-warning.component.spec.ts | 76 +- .../global-warning.component.ts | 18 +- .../global-warning.interface.ts | 4 +- .../global-warning.service.spec.ts | 50 +- .../global-warning/global-warning.service.ts | 32 +- .../header/header.component.spec.ts | 76 +- .../components/header/header.component.ts | 20 +- .../core/components/header/header.stories.ts | 14 +- .../page-not-found.component.spec.ts | 30 +- .../page-not-found.component.ts | 6 +- .../phase-banner.component.spec.ts | 30 +- .../phase-banner/phase-banner.component.ts | 14 +- .../server-error.component.spec.ts | 30 +- .../server-error/server-error.component.ts | 4 +- .../spinner/spinner.component.spec.ts | 56 +- .../components/spinner/spinner.component.ts | 10 +- src/app/core/core.module.ts | 52 +- .../app-role-required.directive.spec.ts | 98 +- .../directives/app-role-required.directive.ts | 45 +- .../feature-toggle.directive.spec.ts | 70 +- .../directives/feature-toggle.directive.ts | 28 +- .../feature-toggle-routing.module.ts | 16 +- .../feature-toggle/feature-toggle.module.ts | 8 +- .../feature-toggle.component.ts | 7 +- .../home-button/home-button.component.spec.ts | 32 +- .../home-button/home-button.component.ts | 14 +- .../home-button/home-button.stories.ts | 6 +- src/app/features/home/home-routing.module.ts | 14 +- src/app/features/home/home.component.spec.ts | 54 +- src/app/features/home/home.component.ts | 10 +- src/app/features/home/home.module.ts | 4 +- src/app/features/home/home.stories.ts | 6 +- .../reference-data-add.component.spec.ts | 204 +- .../reference-data-add.component.ts | 246 +- ...rence-data-amend-history.component.spec.ts | 52 +- .../reference-data-amend-history.component.ts | 91 +- .../reference-data-amend.component.spec.ts | 182 +- .../reference-data-amend.component.ts | 214 +- .../reference-data-delete.component.spec.ts | 156 +- .../reference-data-delete.component.ts | 253 +- ...erence-data-deleted-list.component.spec.ts | 48 +- .../reference-data-deleted-list.component.ts | 100 +- .../reference-data-list.component.spec.ts | 288 +- .../reference-data-list.component.ts | 350 +- .../reference-data-routing.module.ts | 110 +- ...ference-data-select-type.component.spec.ts | 97 +- .../reference-data-select-type.component.ts | 101 +- .../reference-data/reference-data.module.ts | 27 +- .../multiple-search-results.component.spec.ts | 238 +- .../multiple-search-results.component.ts | 74 +- .../features/search/search-routing.module.ts | 26 +- .../features/search/search.component.spec.ts | 228 +- src/app/features/search/search.component.ts | 59 +- src/app/features/search/search.module.ts | 6 +- src/app/features/search/search.stories.ts | 26 +- .../single-search-result.component.spec.ts | 70 +- .../single-search-result.component.ts | 66 +- ...adr-generate-certificate.component.spec.ts | 279 +- .../adr-generate-certificate.component.ts | 134 +- .../edit-tech-record-button.component.spec.ts | 544 +- .../edit-tech-record-button.component.ts | 138 +- ...tech-record-amend-reason.component.spec.ts | 136 +- .../tech-record-amend-reason.component.ts | 102 +- .../tech-record-amend-vin.component.spec.ts | 208 +- .../tech-record-amend-vin.component.ts | 266 +- ...-record-amend-vrm-reason.component.spec.ts | 114 +- .../tech-record-amend-vrm-reason.component.ts | 156 +- .../tech-record-amend-vrm.component.spec.ts | 374 +- .../tech-record-amend-vrm.component.ts | 332 +- ...ech-record-change-status.component.spec.ts | 65 +- .../tech-record-change-status.component.ts | 200 +- .../tech-record-change-type.component.spec.ts | 271 +- .../tech-record-change-type.component.ts | 171 +- ...record-change-visibility.component.spec.ts | 64 +- ...tech-record-change-visibility.component.ts | 169 +- ...additional-examiner-note.component.spec.ts | 150 +- ...edit-additional-examiner-note.component.ts | 173 +- ...h-record-generate-letter.component.spec.ts | 258 +- .../tech-record-generate-letter.component.ts | 145 +- ...ch-record-generate-plate.component.spec.ts | 229 +- .../tech-record-generate-plate.component.ts | 144 +- .../tech-record-history.component.spec.ts | 36 +- .../tech-record-history.component.ts | 87 +- ...tech-record-search-tyres.component.spec.ts | 434 +- .../tech-record-search-tyres.component.ts | 315 +- ...h-record-summary-changes.component.spec.ts | 400 +- .../tech-record-summary-changes.component.ts | 438 +- .../tech-record-summary.component.spec.ts | 411 +- .../tech-record-summary.component.ts | 463 +- .../tech-record-title.component.spec.ts | 201 +- .../tech-record-title.component.ts | 105 +- .../tech-record-unarchive-component.ts | 194 +- .../tech-record-unarchive.component.spec.ts | 65 +- .../tech-router-outlet.component.ts | 4 +- .../test-record-summary.component.spec.ts | 181 +- .../test-record-summary.component.ts | 118 +- .../test-record-summary.stories.ts | 19 +- ...vehicle-technical-record.component.spec.ts | 148 +- .../vehicle-technical-record.component.ts | 300 +- .../vehicle-technical-record.stories.ts | 10 +- .../batch-vehicle-details.component.spec.ts | 85 +- .../batch-vehicle-details.component.ts | 361 +- .../batch-vehicle-results.component.spec.ts | 56 +- .../batch-vehicle-results.component.ts | 128 +- .../batch-vehicle-template.component.spec.ts | 389 +- .../batch-vehicle-template.component.ts | 244 +- .../select-vehicle-type.component.spec.ts | 144 +- .../select-vehicle-type.component.ts | 132 +- .../create-batch-routing.module.ts | 103 +- .../create-batch/create-batch.module.ts | 31 +- ...drate-new-vehicle-record.component.spec.ts | 204 +- .../hydrate-new-vehicle-record.component.ts | 235 +- .../create-tech-record.component.spec.ts | 354 +- .../create/create-tech-record.component.ts | 378 +- .../create-tech-records-routing.module.ts | 67 +- .../create/create-tech-records.module.ts | 22 +- .../tech-record/shared-tech-record.module.ts | 6 +- .../tech-record/tech-record-routing.module.ts | 435 +- .../tech-record/tech-record.component.spec.ts | 80 +- .../tech-record/tech-record.component.ts | 54 +- .../tech-record/tech-record.module.ts | 69 +- .../amend-test-records-routing.module.ts | 260 +- .../amend/amend-test-records.module.ts | 32 +- .../test-amendment-history.component.spec.ts | 236 +- .../test-amendment-history.component.ts | 22 +- .../amend-test/amend-test.component.spec.ts | 32 +- .../views/amend-test/amend-test.component.ts | 6 +- .../amended-test-record.component.spec.ts | 79 +- .../amended-test-record.component.ts | 24 +- .../confirm-cancellation.component.spec.ts | 52 +- .../confirm-cancellation.component.ts | 94 +- .../test-amend-reason.component.spec.ts | 58 +- .../test-amend-reason.component.ts | 57 +- .../test-record/test-record.component.spec.ts | 401 +- .../test-record/test-record.component.ts | 317 +- .../test-result-summary.component.spec.ts | 39 +- .../test-result-summary.component.ts | 42 +- .../test-router-outlet.component.spec.ts | 32 +- .../test-router-outlet.component.ts | 6 +- ...test-type-select-wrapper.component.spec.ts | 72 +- .../test-type-select-wrapper.component.ts | 25 +- .../base-test-record.component.spec.ts | 166 +- .../base-test-record.component.ts | 185 +- .../test-type-select.component.spec.ts | 108 +- .../test-type-select.component.ts | 97 +- .../vehicle-header.component.spec.ts | 146 +- .../vehicle-header.component.ts | 156 +- .../create-test-records-routing.module.ts | 166 +- .../create/create-test-records.module.ts | 12 +- .../create-test-record.component.spec.ts | 394 +- .../create-test-record.component.ts | 480 +- .../create-test-type.component.spec.ts | 153 +- .../create-test-type.component.ts | 78 +- .../test-router-outlet.component.spec.ts | 32 +- .../test-router-outlet.component.ts | 6 +- .../test-records/test-records.module.ts | 6 +- ...approval-type-focus-next.directive.spec.ts | 78 +- .../approval-type-focus-next.directive.ts | 32 +- .../approval-type.component.spec.ts | 870 +- .../approval-type/approval-type.component.ts | 890 +- .../autocomplete.component.spec.ts | 169 +- .../autocomplete/autocomplete.component.ts | 195 +- .../autocomplete/autocomplete.stories.ts | 60 +- .../base-control.component.spec.ts | 269 +- .../base-control/base-control.component.ts | 205 +- .../checkbox-group.component.spec.ts | 122 +- .../checkbox-group.component.ts | 77 +- .../checkbox-group/checkbox-group.stories.ts | 88 +- .../checkbox/checkbox.component.spec.ts | 42 +- .../components/checkbox/checkbox.component.ts | 6 +- ...ngency-adr-generate-cert.component.spec.ts | 183 +- ...contingency-adr-generate-cert.component.ts | 125 +- .../components/date/date.component.spec.ts | 340 +- .../forms/components/date/date.component.ts | 400 +- .../date/focus-next.directive.spec.ts | 124 +- .../components/date/focus-next.directive.ts | 72 +- .../defect-select.component.spec.ts | 140 +- .../defect-select/defect-select.component.ts | 169 +- .../dynamic-form-field.component.spec.ts | 130 +- .../dynamic-form-field.component.ts | 95 +- .../dynamic-form-group.component.spec.ts | 955 +- .../dynamic-form-group.component.ts | 111 +- .../field-error-message.component.spec.ts | 30 +- .../field-error-message.component.ts | 8 +- .../field-warning-message.component.spec.ts | 27 +- .../field-warning-message.component.ts | 8 +- .../number-input.component.spec.ts | 50 +- .../number-input/number-input.component.ts | 77 +- .../radio-group/radio-group.component.spec.ts | 106 +- .../radio-group/radio-group.component.ts | 47 +- .../radio-group/radio-group.stories.ts | 72 +- .../read-only/read-only.component.spec.ts | 44 +- .../read-only/read-only.component.ts | 22 +- ...required-standard-select.component.spec.ts | 191 +- .../required-standard-select.component.ts | 160 +- .../select/select.component.spec.ts | 90 +- .../components/select/select.component.ts | 34 +- .../forms/components/select/select.stories.ts | 72 +- .../suggestive-input.component.spec.ts | 104 +- .../suggestive-input.component.ts | 126 +- .../switchable-input.component.spec.ts | 62 +- .../switchable-input.component.ts | 92 +- .../text-area/text-area.component.spec.ts | 42 +- .../text-area/text-area.component.ts | 24 +- .../text-input/text-input.component.spec.ts | 42 +- .../text-input/text-input.component.ts | 37 +- .../view-combination.component.spec.ts | 102 +- .../view-combination.component.ts | 58 +- .../view-list-item.component.spec.ts | 42 +- .../view-list-item.component.ts | 56 +- .../abandon-dialog.component.spec.ts | 74 +- .../abandon-dialog.component.ts | 127 +- .../adr-certificate-history.component.spec.ts | 182 +- .../adr-certificate-history.component.ts | 184 +- ...miner-notes-history.component-edit.spec.ts | 175 +- ...r-examiner-notes-history.component-edit.ts | 121 +- ...miner-notes-history-view.component.spec.ts | 175 +- ...r-examiner-notes-history-view.component.ts | 92 +- ...ertificate-required-view.component.spec.ts | 51 +- ...new-certificate-required-view.component.ts | 20 +- ...-initial-inspection-view.component.spec.ts | 55 +- ...tails-initial-inspection-view.component.ts | 6 +- ...r-tank-details-m145-view.component.spec.ts | 53 +- .../adr-tank-details-m145-view.component.ts | 24 +- ...sequent-inspections-edit.component.spec.ts | 290 +- ...s-subsequent-inspections-edit.component.ts | 222 +- ...sequent-inspections-view.component.spec.ts | 53 +- ...s-subsequent-inspections-view.component.ts | 24 +- ...statement-un-number-edit.component.spec.ts | 174 +- ...tank-statement-un-number-edit.component.ts | 111 +- ...statement-un-number-view.component.spec.ts | 51 +- ...tank-statement-un-number-view.component.ts | 6 +- .../custom-sections/adr/adr.component.spec.ts | 155 +- .../custom-sections/adr/adr.component.ts | 113 +- .../approval-type/approval-type.component.ts | 148 +- .../approval-type/approval-type.directive.ts | 24 +- .../body/body.component.spec.ts | 439 +- .../custom-sections/body/body.component.ts | 308 +- .../custom-defect.component.spec.ts | 30 +- .../custom-defect/custom-defect.component.ts | 20 +- .../custom-defects.component.spec.ts | 186 +- .../custom-defects.component.ts | 92 +- .../custom-form-control.component.spec.ts | 27 +- .../custom-form-control.component.ts | 42 +- .../defect/defect.component.spec.ts | 472 +- .../defect/defect.component.ts | 426 +- .../defects/defects.component.spec.ts | 81 +- .../defects/defects.component.ts | 85 +- .../dimensions/dimensions.component.spec.ts | 34 +- .../dimensions/dimensions.component.ts | 172 +- .../letters/letters.component.spec.ts | 194 +- .../letters/letters.component.ts | 276 +- .../modified-weights.component.spec.ts | 318 +- .../modified-weights.component.ts | 114 +- .../plates/plates.component.spec.ts | 923 +- .../plates/plates.component.ts | 305 +- .../psv-brakes/psv-brakes.component.spec.ts | 197 +- .../psv-brakes/psv-brakes.component.ts | 264 +- .../required-standard.component.spec.ts | 338 +- .../required-standard.component.ts | 229 +- .../required-standards.component.spec.ts | 154 +- .../required-standards.component.ts | 146 +- .../trl-brakes/trl-brakes.component.spec.ts | 185 +- .../trl-brakes/trl-brakes.component.ts | 150 +- .../tyres/tyres.component.spec.ts | 528 +- .../custom-sections/tyres/tyres.component.ts | 569 +- .../weights/weights.component.spec.ts | 284 +- .../weights/weights.component.ts | 396 +- .../directives/app-no-space.directive.spec.ts | 238 +- .../directives/app-no-space.directive.ts | 38 +- .../app-number-only.directive.spec.ts | 46 +- .../directives/app-number-only.directive.ts | 63 +- .../app-to-uppercase.directive.spec.ts | 48 +- .../directives/app-to-uppercase.directive.ts | 12 +- .../app-trim-whitespace.directive.spec.ts | 188 +- .../app-trim-whitespace.directive.ts | 26 +- .../forms/directives/prefix.directive.spec.ts | 30 +- src/app/forms/directives/prefix.directive.ts | 4 +- .../forms/directives/suffix.directive.spec.ts | 30 +- src/app/forms/directives/suffix.directive.ts | 4 +- src/app/forms/dynamic-forms.module.ts | 262 +- src/app/forms/models/async-validators.enum.ts | 24 +- src/app/forms/models/condition.model.ts | 10 +- src/app/forms/models/options.model.ts | 4 +- .../forms/models/plateRequiredFields.model.ts | 71 +- src/app/forms/models/testTypeId.enum.ts | 304 +- src/app/forms/models/validators.enum.ts | 96 +- .../services/dynamic-form.service.spec.ts | 492 +- .../forms/services/dynamic-form.service.ts | 465 +- .../forms/services/dynamic-form.types.spec.ts | 125 +- src/app/forms/services/dynamic-form.types.ts | 444 +- .../forms/services/multi-options.service.ts | 70 +- .../templates/car/car-tech-record.template.ts | 176 +- .../general/adr-certificate.template.ts | 26 +- .../templates/general/adr-summary.template.ts | 1579 +-- .../forms/templates/general/adr.template.ts | 1628 ++- .../general/applicant-details.template.ts | 138 +- .../general/approval-type.template.ts | 140 +- .../forms/templates/general/audit.template.ts | 100 +- .../templates/general/defect.template.ts | 376 +- .../forms/templates/general/document-types.ts | 320 +- .../templates/general/documents.template.ts | 54 +- .../general/hgv-trl-body.template.ts | 166 +- .../forms/templates/general/letter-types.ts | 16 +- .../templates/general/letters.template.ts | 66 +- .../general/manufacturer.template.ts | 154 +- .../forms/templates/general/notes.template.ts | 28 +- .../templates/general/plates.template.ts | 104 +- .../general/reason-for-creation.template.ts | 59 +- .../general/required-standards.template.ts | 178 +- .../templates/hgv/hgv-dimensions.template.ts | 156 +- .../templates/hgv/hgv-tech-record.template.ts | 457 +- .../forms/templates/hgv/hgv-tyres.template.ts | 189 +- .../templates/hgv/hgv-weight.template.ts | 334 +- .../templates/lgv/lgv-tech-record.template.ts | 181 +- .../motorcycle-tech-record.template.ts | 237 +- .../psv/psv-approval-type.template.ts | 188 +- .../forms/templates/psv/psv-body.template.ts | 191 +- .../templates/psv/psv-brakes.template.ts | 156 +- .../forms/templates/psv/psv-dda.template.ts | 202 +- .../templates/psv/psv-dimensions.template.ts | 66 +- .../forms/templates/psv/psv-notes.template.ts | 46 +- .../templates/psv/psv-tech-record.template.ts | 562 +- .../forms/templates/psv/psv-tyres.template.ts | 193 +- .../templates/psv/psv-weight.template.ts | 268 +- .../search/single-search-result.template.ts | 122 +- .../small-trailer-tech-record.template.ts | 217 +- .../tech-records/vehicle-summary.template.ts | 98 +- .../test-records/create-master.template.ts | 1498 ++- .../templates/test-records/master.template.ts | 1403 ++- .../additional-defects-section.template.ts | 84 +- .../custom-defects-section.template.ts | 98 +- .../desk-based-emissions-section.template.ts | 284 +- .../emissions/emissions-section.template.ts | 300 +- .../notes/adr-notes-section.template.ts | 100 +- .../notes/notes-section.template.ts | 52 +- .../reasonForCreation.template.ts | 54 +- ...equired-hidden-section-hgv-trl.template.ts | 420 +- ...equired-hidden-section-lgv-car.template.ts | 442 +- ...ired-hidden-section-motorcycle.template.ts | 418 +- ...ngency-required-hidden-section.template.ts | 444 +- .../custom-defects-hidden-section.template.ts | 50 +- .../defect-hidden-section.template.ts | 50 +- ...sed-required-hidden-group4-lgv.template.ts | 526 +- ...hidden-group4-motorcycle-amend.template.ts | 474 +- ...uired-hidden-group4-motorcycle.template.ts | 502 +- ...sed-required-hidden-group5-lgv.template.ts | 472 +- ...equired-hidden-section-hgv-trl.template.ts | 448 +- ...ed-required-hidden-section-psv.template.ts | 472 +- ...-required-section-group4-amend.template.ts | 498 +- ...equired-hidden-section-hgv-trl.template.ts | 446 +- .../required-hidden-section.template.ts | 484 +- .../seatbelt-hidden-section.template.ts | 80 +- ...equired-hidden-section-hgv-trl.template.ts | 432 +- ...equired-hidden-section-lgv-car.template.ts | 456 +- ...ired-hidden-section-motorcycle.template.ts | 444 +- ...ialist-required-hidden-section.template.ts | 456 +- .../seatbelt/seatbelt-section.template.ts | 120 +- ...ontingency-test-section-group1.template.ts | 240 +- ...ency-test-section-group12and14.template.ts | 228 +- ...ency-test-section-group15and16.template.ts | 292 +- ...cy-test-section-group3And4And8.template.ts | 258 +- ...gency-test-section-group5And13.template.ts | 274 +- ...gency-test-section-group6And11.template.ts | 242 +- ...ontingency-test-section-group7.template.ts | 389 +- ...-test-section-group8Notifiable.template.ts | 308 +- ...gency-test-section-group9And10.template.ts | 244 +- ...section-group9And10CentralDocs.template.ts | 303 +- ...test-section-specialist-group1.template.ts | 391 +- ...test-section-specialist-group2.template.ts | 306 +- ...-section-specialist-group3And4.template.ts | 305 +- ...test-section-specialist-group5.template.ts | 334 +- ...-contingency-specialist-group1.template.ts | 284 +- ...-contingency-specialist-group5.template.ts | 260 +- ...-based-test-section-group1-PSV.template.ts | 426 +- ...est-section-group1And4-HGV-TRL.template.ts | 374 +- ...desk-based-test-section-group2.template.ts | 394 +- ...desk-based-test-section-group3.template.ts | 382 +- ...-based-test-section-group4-PSV.template.ts | 440 +- ...-based-test-section-group4-lgv-template.ts | 368 +- .../desk-based-test-section-group5-LGV.ts | 454 +- ...specialist-test-section-group1.template.ts | 343 +- ...specialist-test-section-group5.template.ts | 301 +- ...specialist-test-section-group1.template.ts | 448 +- ...specialist-test-section-group2.template.ts | 412 +- ...specialist-test-section-group3.template.ts | 178 +- ...ialist-test-section-group3And4.template.ts | 336 +- ...specialist-test-section-group5.template.ts | 359 +- .../test/test-section-group1.template.ts | 317 +- .../test-section-group12And14.template.ts | 239 +- .../test-section-group15And16.template.ts | 399 +- .../test/test-section-group2.template.ts | 299 +- .../test-section-group3And4And8.template.ts | 275 +- .../test/test-section-group5And13.template.ts | 302 +- .../test/test-section-group6And11.template.ts | 257 +- .../test/test-section-group7.template.ts | 393 +- .../test-section-group8Notifiable.template.ts | 325 +- .../test/test-section-group9And10.template.ts | 317 +- ...section-group9And10CentralDocs.template.ts | 374 +- .../test/test-section.template.ts | 306 +- .../amend-iva-msva-psv-hgv-light.template.ts | 243 +- ...-psv-hgv-light-vehicle-section.template.ts | 214 +- ...cy-default-trl-vehicle-section.template.ts | 168 +- ...gency-iva-msva-vehicle-section.template.ts | 221 +- ...-psv-hgv-light-vehicle-section.template.ts | 258 +- .../default-trl-vehicle-section.template.ts | 192 +- ...efault-psv-hgv-vehicle-section.template.ts | 196 +- ...ed-default-trl-vehicle-section.template.ts | 156 +- ...vehicle-section-group1And2And4.template.ts | 184 +- ...sed-vehicle-section-group4-lgv.template.ts | 198 +- ...sed-vehicle-section-group5-lgv.template.ts | 186 +- .../group-3-light-vehicle-section.template.ts | 162 +- .../contingency-visit-section.template.ts | 136 +- .../visit/visit-section.template.ts | 134 +- .../test-records/test-abandonment-reasons.ts | 122 +- .../trl/trl-auth-into-service.template.ts | 110 +- .../templates/trl/trl-brakes.template.ts | 118 +- .../templates/trl/trl-dimensions.template.ts | 190 +- .../templates/trl/trl-purchaser.template.ts | 174 +- .../templates/trl/trl-tech-record.template.ts | 394 +- .../forms/templates/trl/trl-tyres.template.ts | 176 +- .../templates/trl/trl-weight.template.ts | 186 +- src/app/forms/utils/enum-map.ts | 8 +- src/app/forms/utils/error-message-map.spec.ts | 114 +- src/app/forms/utils/error-message-map.ts | 101 +- src/app/forms/utils/tech-record-constants.ts | 184 +- .../validators/adr/adr.validators.spec.ts | 306 +- .../forms/validators/adr/adr.validators.ts | 108 +- .../custom-async-validators.spec.ts | 1371 +- .../validators/custom-async-validators.ts | 552 +- .../validators/custom-validators.spec.ts | 4038 +++--- src/app/forms/validators/custom-validators.ts | 1235 +- .../validators/date/date.validators.spec.ts | 148 +- .../forms/validators/date/date.validators.ts | 82 +- .../defects/defect.validators.spec.ts | 286 +- .../validators/defects/defect.validators.ts | 83 +- src/app/govuk.d.ts | 14 +- .../cancel-edit-tech.guard.spec.ts | 36 +- .../cancel-edit-tech.guard.ts | 20 +- .../cancel-edit-test.guard.spec.ts | 36 +- .../cancel-edit-test.guard.ts | 12 +- .../feature-toggle.guard.spec.ts | 68 +- .../feature-toggle.guard.ts | 18 +- src/app/guards/no-edit/no-edit.guard.spec.ts | 98 +- src/app/guards/no-edit/no-edit.guard.ts | 41 +- .../no-query-params.guard.spec.ts | 140 +- .../no-query-params/no-query-params.guard.ts | 33 +- src/app/guards/role-guard/roles.guard.spec.ts | 70 +- src/app/guards/role-guard/roles.guard.ts | 26 +- .../delayed-retry.interceptor.spec.ts | 194 +- .../delayed-retry.interceptor.ts | 144 +- .../delayed-retry/delayed-retry.module.ts | 46 +- .../error-handling.interceptor.spec.ts | 134 +- .../error-handling.interceptor.ts | 61 +- .../error-handling/error-handling.module.ts | 46 +- src/app/interceptors/interceptor.module.ts | 20 +- src/app/models/adr.enum.ts | 8 +- src/app/models/body-type-enum.ts | 168 +- src/app/models/coupling-type-enum.ts | 24 +- .../defects/additional-information.model.ts | 10 +- src/app/models/defects/defect.model.ts | 10 +- .../defects/deficiency-category.enum.ts | 8 +- src/app/models/defects/deficiency.model.ts | 14 +- src/app/models/defects/item.model.ts | 8 +- src/app/models/defects/location.model.ts | 32 +- src/app/models/reference-data.model.ts | 118 +- src/app/models/roles.enum.ts | 24 +- src/app/models/routes.enum.ts | 124 +- src/app/models/search-types-enum.ts | 12 +- .../tech-record/tech-record-actions.enum.ts | 8 +- .../defectAdditionalInformation.ts | 4 +- .../defectAdditionalInformationLocation.ts | 32 +- .../test-results/test-result-defect.model.ts | 34 +- .../test-result-required-standard.model.ts | 22 +- .../test-results/test-result-status.enum.ts | 4 +- .../test-results/test-result-view.enum.ts | 8 +- .../models/test-results/test-result.model.ts | 104 +- src/app/models/test-results/testCodes.enum.ts | 112 +- .../models/test-results/typeOfTest.enum.ts | 4 +- .../test-stations/test-station-type.enum.ts | 8 +- .../test-stations/test-station.model.ts | 34 +- src/app/models/test-types/emissions.enum.ts | 46 +- .../test-types/eu-vehicle-category.enum.ts | 36 +- .../models/test-types/odometer-unit.enum.ts | 4 +- src/app/models/test-types/test-type.model.ts | 86 +- src/app/models/vehicle-class.model.ts | 70 +- src/app/models/vehicle-configuration.enum.ts | 48 +- src/app/models/vehicle-size.enum.ts | 4 +- src/app/models/vehicle-tech-record.model.ts | 758 +- .../contingency-test.resolver.spec.ts | 385 +- .../contingency-test.resolver.ts | 213 +- .../defects-taxonomy.resolver.spec.ts | 100 +- .../defects-taxonomy.resolver.ts | 23 +- .../required-standards.resolver.spec.ts | 106 +- .../required-standards.resolver.ts | 26 +- .../tech-record-clean.resolver.spec.ts | 180 +- .../tech-record-clean.resolver.ts | 58 +- .../tech-record-data.resolver.spec.ts | 60 +- .../tech-record-data.resolver.ts | 8 +- .../tech-record-validate.resolver.spec.ts | 315 +- .../tech-record-validate.resolver.ts | 210 +- .../tech-record-view.resolver.spec.ts | 137 +- .../tech-record-view.resolver.ts | 42 +- .../test-result/test-result.resolver.spec.ts | 122 +- .../test-result/test-result.resolver.ts | 30 +- .../test-stations.resolver.spec.ts | 96 +- .../test-stations/test-stations.resolver.ts | 16 +- .../test-type-taxonomy.resolver.spec.ts | 106 +- .../test-type-taxonomy.resolver.ts | 22 +- .../resolvers/title/title.resolver.spec.ts | 111 +- src/app/resolvers/title/title.resolver.ts | 22 +- src/app/services/adr/adr.service.spec.ts | 166 +- src/app/services/adr/adr.service.ts | 46 +- src/app/services/axles/axles.service.spec.ts | 204 +- src/app/services/axles/axles.service.ts | 119 +- .../batch-technical-record.service.spec.ts | 414 +- .../batch-technical-record.service.ts | 356 +- .../services/defects/defects.service.spec.ts | 176 +- src/app/services/defects/defects.service.ts | 16 +- .../documents/documents.service.spec.ts | 148 +- .../services/documents/documents.service.ts | 71 +- .../feature-toggle-service.spec.ts | 142 +- .../feature-toggle-service.ts | 55 +- .../services/loading/loading.service.spec.ts | 92 +- src/app/services/loading/loading.service.ts | 58 +- .../reference-data.service.spec.ts | 788 +- .../reference-data/reference-data.service.ts | 381 +- .../required-standards.service.ts | 13 +- .../result-of-test.service.spec.ts | 48 +- .../result-of-test/result-of-test.service.ts | 45 +- .../services/router/router.service.spec.ts | 120 +- src/app/services/router/router.service.ts | 93 +- .../technical-record-http.service.spec.ts | 385 +- .../technical-record-http.service.ts | 289 +- .../technical-record.service.spec.ts | 1558 +-- .../technical-record.service.ts | 667 +- .../test-records/test-records.service.spec.ts | 357 +- .../test-records/test-records.service.ts | 449 +- .../test-stations.service.spec.ts | 178 +- .../test-stations/test-stations.service.ts | 46 +- .../test-types/test-types.service.spec.ts | 22 +- .../services/test-types/test-types.service.ts | 40 +- .../user-service/user-service.spec.ts | 119 +- src/app/services/user-service/user-service.ts | 135 +- .../accordion-control.component.spec.ts | 56 +- .../accordion-control.component.ts | 49 +- .../accordion/accordion.component.spec.ts | 100 +- .../accordion/accordion.component.ts | 53 +- .../banner/banner.component.spec.ts | 30 +- .../components/banner/banner.component.ts | 4 +- .../base-dialog/base-dialog.component.spec.ts | 30 +- .../base-dialog/base-dialog.component.ts | 14 +- .../button-group.component.spec.ts | 30 +- .../button-group/button-group.component.ts | 8 +- .../button/button.component.spec.ts | 32 +- .../components/button/button.component.ts | 22 +- .../collapsible-text.component.spec.ts | 51 +- .../collapsible-text.component.ts | 25 +- .../components/icon/icon.component.spec.ts | 30 +- .../shared/components/icon/icon.component.ts | 8 +- .../input-spinner.component.spec.ts | 30 +- .../input-spinner/input-spinner.component.ts | 8 +- .../number-plate.component.spec.ts | 102 +- .../number-plate/number-plate.component.ts | 40 +- .../pagination/pagination.component.spec.ts | 361 +- .../pagination/pagination.component.ts | 166 +- .../router-outlet.component.spec.ts | 32 +- .../router-outlet/router-outlet.component.ts | 4 +- .../components/tag/tag.component.spec.ts | 30 +- .../shared/components/tag/tag.component.ts | 20 +- .../test-certificate.component.spec.ts | 196 +- .../test-certificate.component.ts | 91 +- .../shared/custom-module/fixNgZoneError.ts | 4 +- .../prevent-double-click.directive.spec.ts | 72 +- .../prevent-double-click.directive.ts | 50 +- .../retrieve-document.directive.spec.ts | 34 +- .../retrieve-document.directive.ts | 62 +- .../default-null-or-empty.pipe.spec.ts | 72 +- .../default-null-or-empty.pipe.ts | 38 +- .../digit-group-separator.pipe.spec.ts | 28 +- .../digit-group-separator.pipe.ts | 14 +- .../format-vehicle-type.pipe.spec.ts | 32 +- .../format-vehicle-type.pipe.ts | 18 +- .../get-control-label.pipe.spec.ts | 38 +- .../get-control-label.pipe.ts | 14 +- .../ref-data-decode.pipe.spec.ts | 252 +- .../ref-data-decode/ref-data-decode.pipe.ts | 132 +- .../test-type-name.pipe.spec.ts | 74 +- .../test-type-name/test-type-name.pipe.ts | 52 +- .../pipes/truncate/truncate.pipe.spec.ts | 22 +- .../shared/pipes/truncate/truncate.pipe.ts | 8 +- .../tyre-axle-load.pipe.spec.ts | 38 +- .../tyre-axle-load/tyre-axle-load.pipe.ts | 26 +- src/app/shared/shared.module.ts | 113 +- src/app/store/app-store.module.ts | 54 +- .../defects/actions/defects.actions.spec.ts | 23 +- .../store/defects/actions/defects.actions.ts | 6 +- src/app/store/defects/defects-state.module.ts | 10 +- .../defects/effects/defects.effects.spec.ts | 214 +- .../store/defects/effects/defects.effects.ts | 61 +- .../defects/reducers/defects.reducer.spec.ts | 158 +- .../store/defects/reducers/defects.reducer.ts | 34 +- .../selectors/defects.selectors.spec.ts | 140 +- .../defects/selectors/defects.selectors.ts | 81 +- .../global-error/global-error-state.module.ts | 11 +- .../global-error-service.reducer.spec.ts | 149 +- .../reducers/global-error-service.reducer.ts | 90 +- .../selectors/global-error.selectors.spec.ts | 14 +- .../selectors/global-error.selectors.ts | 2 +- .../actions/global-warning.actions.ts | 5 +- .../global-warning-state.module.ts | 11 +- .../global-warning-service.reducer.spec.ts | 98 +- .../global-warning-service.reducers.ts | 36 +- src/app/store/index.ts | 133 +- .../actions/reference-data.actions.spec.ts | 80 +- .../actions/reference-data.actions.ts | 184 +- .../reference-data.operators.spec.ts | 92 +- .../operators/reference-data.operators.ts | 98 +- .../effects/reference-data.effects.spec.ts | 1045 +- .../effects/reference-data.effects.ts | 366 +- .../reducers/reference-data.reducer.spec.ts | 986 +- .../reducers/reference-data.reducer.ts | 378 +- .../reference-data/reference-data.module.ts | 12 +- .../reference-data.test-cases.ts | 10 +- .../reference-data.selectors.spec.ts | 333 +- .../selectors/reference-data.selectors.ts | 122 +- .../required-standards.actions.spec.ts | 16 +- .../actions/required-standards.actions.ts | 9 +- .../required-standards.effects.spec.ts | 121 +- .../effects/required-standards.effects.ts | 32 +- .../required-standards.reducer.spec.ts | 118 +- .../reducers/required-standards.reducer.ts | 68 +- .../required-standards.module.ts | 9 +- .../required-standards.selector.spec.ts | 143 +- .../selectors/required-standards.selector.ts | 25 +- .../actions/retry-interceptor.actions.ts | 5 +- .../retry-interceptor.module.ts | 4 +- src/app/store/router/router-state.module.ts | 10 +- .../router/selectors/router.selectors.spec.ts | 14 +- .../router/selectors/router.selectors.ts | 41 +- .../spinner/actions/spinner.actions.spec.ts | 36 +- .../spinner/reducers/spinner.reducer.spec.ts | 18 +- .../store/spinner/reducers/spinner.reducer.ts | 8 +- .../selectors/spinner.selectors.spec.ts | 14 +- .../spinner/selectors/spinner.selectors.ts | 4 +- src/app/store/spinner/spinner-state.module.ts | 8 +- .../actions/tech-record-search.actions.ts | 11 +- .../effects/tech-record-search.effect.spec.ts | 121 +- .../effects/tech-record-search.effect.ts | 74 +- .../tech-record-search.reducer.spec.ts | 76 +- .../reducer/tech-record-search.reducer.ts | 40 +- .../tech-record-search.selector.spec.ts | 305 +- .../selector/tech-record-search.selector.ts | 51 +- .../tech-record-search-state.module.ts | 14 +- .../actions/batch-create.actions.ts | 24 +- .../technical-record-service.actions.spec.ts | 86 +- .../technical-record-service.actions.ts | 142 +- .../technical-record-service.effects.spec.ts | 776 +- .../technical-record-service.effects.ts | 620 +- .../reducers/batch-create.reducer.ts | 108 +- .../technical-record-service.reducer.spec.ts | 1284 +- .../technical-record-service.reducer.ts | 1022 +- .../selectors/batch-create.selectors.ts | 4 +- ...technical-record-service.selectors.spec.ts | 465 +- .../technical-record-service.selectors.ts | 54 +- .../technical-records-state.module.ts | 17 +- .../actions/test-records.actions.spec.ts | 56 +- .../actions/test-records.actions.ts | 91 +- .../effects/test-records.effects.spec.ts | 1640 +-- .../effects/test-records.effects.ts | 557 +- .../reducers/test-records.reducer.spec.ts | 1073 +- .../reducers/test-records.reducer.ts | 566 +- .../selectors/test-records.selectors.spec.ts | 508 +- .../selectors/test-records.selectors.ts | 140 +- .../store/test-records/test-records.module.ts | 8 +- .../actions/test-stations.actions.spec.ts | 28 +- .../actions/test-stations.actions.ts | 11 +- .../effects/test-stations.effects.spec.ts | 218 +- .../effects/test-stations.effects.ts | 61 +- .../reducers/test-stations.reducer.spec.ts | 158 +- .../reducers/test-stations.reducer.ts | 44 +- .../selectors/test-stations.selectors.spec.ts | 107 +- .../selectors/test-stations.selectors.ts | 2 +- .../test-stations-state.module.ts | 12 +- .../actions/test-types.actions.spec.ts | 12 +- .../test-types/actions/test-types.actions.ts | 5 +- .../effects/test-types.effects.spec.ts | 128 +- .../test-types/effects/test-types.effects.ts | 37 +- .../reducers/test-types.reducer.spec.ts | 98 +- .../test-types/reducers/test-types.reducer.ts | 18 +- .../selectors/test-types.selectors.spec.ts | 872 +- .../selectors/test-types.selectors.ts | 273 +- src/app/store/test-types/test-types.module.ts | 8 +- src/app/store/user/user-service.actions.ts | 5 +- src/app/store/user/user-service.reducer.ts | 50 +- src/app/store/user/user-state.module.ts | 6 +- src/environments/environment.prod.ts | 28 +- src/environments/environment.ts | 28 +- src/main.ts | 6 +- src/mocks/custom-defect.mock.ts | 14 +- src/mocks/google-analytics-service.mock.ts | 6 +- src/mocks/hgv-record.mock.ts | 112 +- src/mocks/lgv-record.mock.ts | 30 +- src/mocks/mock-defects.ts | 34 +- src/mocks/mock-test-result.ts | 156 +- .../mock-vehicle-technical-record.mock.ts | 18 +- src/mocks/psv-record.mock.ts | 300 +- ...ountries-of-registration.reference-data.ts | 380 +- src/mocks/test-result.mock.ts | 42 +- src/mocks/test-type-category.mock.ts | 8 +- src/mocks/test-type.mock.ts | 86 +- src/mocks/trl-record.mock.ts | 78 +- 842 files changed, 73000 insertions(+), 72956 deletions(-) create mode 100644 biome.json diff --git a/.gitignore b/.gitignore index 75885522f3..a11a0b13c5 100644 --- a/.gitignore +++ b/.gitignore @@ -45,7 +45,6 @@ yarn-error.log testem.log /typings .reports/ -{} .scannerwork # System files diff --git a/biome.json b/biome.json new file mode 100644 index 0000000000..7b0ae1910b --- /dev/null +++ b/biome.json @@ -0,0 +1,3 @@ +{ + "extends": ["@dvsa/biome-config/biome"] +} diff --git a/package-lock.json b/package-lock.json index 35a3c90c12..6d9b2d318c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,6 @@ "accessible-autocomplete": "^2.0.4", "angular-google-tag-manager": "^1.9.0", "deep-object-diff": "^1.1.9", - "eslint-import-resolver-typescript": "^3.6.1", "govuk-frontend": "^4.7.0", "jwt-decode": "^4.0.0", "lodash": "^4.17.21", @@ -46,18 +45,14 @@ }, "devDependencies": { "@angular-devkit/build-angular": "^17.2.0", - "@angular-eslint/builder": "^17.2.1", - "@angular-eslint/eslint-plugin": "^17.2.1", - "@angular-eslint/eslint-plugin-template": "^17.2.1", - "@angular-eslint/schematics": "^17.2.1", - "@angular-eslint/template-parser": "^17.2.1", "@angular/cli": "^17.2.0", "@angular/compiler-cli": "^17.2.1", "@babel/core": "^7.23.9", + "@biomejs/biome": "1.8.3", "@commitlint/cli": "^18.6.1", "@commitlint/config-conventional": "^18.6.2", "@compodoc/compodoc": "^1.1.23", - "@dvsa/eslint-config-ts": "^3.0.1", + "@dvsa/biome-config": "^0.1.0", "@ngrx/schematics": "^17.1.0", "@types/jest": "^29.5.12", "@types/json-server": "^0.14.7", @@ -65,22 +60,14 @@ "@types/lodash.merge": "^4.6.9", "@types/node": "^18.18.0", "@types/uuid": "^9.0.8", - "@typescript-eslint/eslint-plugin": "^6.0.0", - "@typescript-eslint/parser": "^6.0.0", "babel-loader": "^9.1.3", "commitlint-plugin-function-rules": "^3.1.0", "dotenv": "^16.4.5", - "eslint": "^8.56.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-ngrx": "^2.1.4", - "eslint-plugin-prettier": "^5.1.3", "husky": "^9.0.11", "jest": "^29.7.0", "jest-preset-angular": "^14.0.3", "jest-sonar-reporter": "^2.0.0", "json-server": "^0.17.3", - "prettier": "^3.2.5", "sonarqube-scanner": "^3.3.0", "ts-jest": "^29.1.2", "ts-node": "^10.9.2", @@ -99,14 +86,6 @@ "@nx/nx-win32-x64-msvc": "18.0.4" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@aduh95/viz.js": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/@aduh95/viz.js/-/viz.js-3.4.0.tgz", @@ -503,104 +482,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular-eslint/builder": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-17.2.1.tgz", - "integrity": "sha512-O30eaR0wCPiP+zKWvXj2JM8hVq30Wok2rp7zJMFm3PurjF9nWIIyexXkE5fa538DYZYxu8N3gQRqhpv5jvTXCg==", - "dev": true, - "dependencies": { - "@nx/devkit": "17.2.8", - "nx": "17.2.8" - }, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-17.2.1.tgz", - "integrity": "sha512-puC0itsZv2QlrDOCcWtq1KZH+DvfrpV+mV78HHhi6+h25R5iIhr8ARKcl3EQxFjvrFq34jhG8pSupxKvFbHVfA==", - "dev": true - }, - "node_modules/@angular-eslint/eslint-plugin": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-17.2.1.tgz", - "integrity": "sha512-9yA81BHpsaCUKRBtHGN3ieAy8HpIoffzPQMu34lYqZFT4yGHGhYmhQjNSQGBRbV2LD9dVv2U35rMHNmUcozXpw==", - "dev": true, - "dependencies": { - "@angular-eslint/utils": "17.2.1", - "@typescript-eslint/utils": "6.19.0" - }, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-17.2.1.tgz", - "integrity": "sha512-hl1hcHtcm90wyVL1OQGTz16oA0KHon+FFb3Qg0fLXObaXxA495Ecefd9ub5Xxg4JEOPRDi29bF1Y3YKpwflgeg==", - "dev": true, - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "17.2.1", - "@angular-eslint/utils": "17.2.1", - "@typescript-eslint/type-utils": "6.19.0", - "@typescript-eslint/utils": "6.19.0", - "aria-query": "5.3.0", - "axobject-query": "4.0.0" - }, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/schematics": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-17.2.1.tgz", - "integrity": "sha512-7ldtIePI4ZTp/TBpeOZkzfv30HSAn//4TgtFuqvojudI8n8batV5FqQ0VNm1e0zitl75t8Zwtr0KYT4I6vh59g==", - "dev": true, - "dependencies": { - "@angular-eslint/eslint-plugin": "17.2.1", - "@angular-eslint/eslint-plugin-template": "17.2.1", - "@nx/devkit": "17.2.8", - "ignore": "5.3.0", - "nx": "17.2.8", - "strip-json-comments": "3.1.1", - "tmp": "0.2.1" - }, - "peerDependencies": { - "@angular/cli": ">= 17.0.0 < 18.0.0" - } - }, - "node_modules/@angular-eslint/template-parser": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-17.2.1.tgz", - "integrity": "sha512-WPQYFvRju0tCDXQ/pwrzC911pE07JvpeDgcN2elhzV6lxDHJEZpA5O9pnW9qgNA6J6XM9Q7dBkJ22ztAzC4WFw==", - "dev": true, - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "17.2.1", - "eslint-scope": "^8.0.0" - }, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/utils": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-17.2.1.tgz", - "integrity": "sha512-qQYTBXy90dWM7fhhpa5i9lTtqqhJisvRa+naCrQx9kBgR458JScLdkVIdcZ9D/rPiDCmKiVUfgcDISnjUeqTqg==", - "dev": true, - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "17.2.1", - "@typescript-eslint/utils": "6.19.0" - }, - "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", - "typescript": "*" - } - }, "node_modules/@angular/animations": { "version": "17.2.3", "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-17.2.3.tgz", @@ -2676,6 +2557,161 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@biomejs/biome": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.8.3.tgz", + "integrity": "sha512-/uUV3MV+vyAczO+vKrPdOW0Iaet7UnJMU4bNMinggGJTAnBPjCoLEYcyYtYHNnUNYlv4xZMH6hVIQCAozq8d5w==", + "dev": true, + "hasInstallScript": true, + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "1.8.3", + "@biomejs/cli-darwin-x64": "1.8.3", + "@biomejs/cli-linux-arm64": "1.8.3", + "@biomejs/cli-linux-arm64-musl": "1.8.3", + "@biomejs/cli-linux-x64": "1.8.3", + "@biomejs/cli-linux-x64-musl": "1.8.3", + "@biomejs/cli-win32-arm64": "1.8.3", + "@biomejs/cli-win32-x64": "1.8.3" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.8.3.tgz", + "integrity": "sha512-9DYOjclFpKrH/m1Oz75SSExR8VKvNSSsLnVIqdnKexj6NwmiMlKk94Wa1kZEdv6MCOHGHgyyoV57Cw8WzL5n3A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.8.3.tgz", + "integrity": "sha512-UeW44L/AtbmOF7KXLCoM+9PSgPo0IDcyEUfIoOXYeANaNXXf9mLUwV1GeF2OWjyic5zj6CnAJ9uzk2LT3v/wAw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.8.3.tgz", + "integrity": "sha512-fed2ji8s+I/m8upWpTJGanqiJ0rnlHOK3DdxsyVLZQ8ClY6qLuPc9uehCREBifRJLl/iJyQpHIRufLDeotsPtw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.8.3.tgz", + "integrity": "sha512-9yjUfOFN7wrYsXt/T/gEWfvVxKlnh3yBpnScw98IF+oOeCYb5/b/+K7YNqKROV2i1DlMjg9g/EcN9wvj+NkMuQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.8.3.tgz", + "integrity": "sha512-I8G2QmuE1teISyT8ie1HXsjFRz9L1m5n83U1O6m30Kw+kPMPSKjag6QGUn+sXT8V+XWIZxFFBoTDEDZW2KPDDw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.8.3.tgz", + "integrity": "sha512-UHrGJX7PrKMKzPGoEsooKC9jXJMa28TUSMjcIlbDnIO4EAavCoVmNQaIuUSH0Ls2mpGMwUIf+aZJv657zfWWjA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.8.3.tgz", + "integrity": "sha512-J+Hu9WvrBevfy06eU1Na0lpc7uR9tibm9maHynLIoAjLZpQU3IW+OKHUtyL8p6/3pT2Ju5t5emReeIS2SAxhkQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.8.3.tgz", + "integrity": "sha512-/PJ59vA1pnQeKahemaQf4Nyj7IKUvGQSc3Ze1uIGi+Wvr1xF7rGobSrAAG01T/gUDG21vkDsZYM03NAmPiVkqg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, "node_modules/@commitlint/cli": { "version": "18.6.1", "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-18.6.1.tgz", @@ -3385,6 +3421,12 @@ "node": ">=10.0.0" } }, + "node_modules/@dvsa/biome-config": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@dvsa/biome-config/-/biome-config-0.1.0.tgz", + "integrity": "sha512-eHJ5UN+klqWgwyHrcuIXQpNy0YsP8AELR8UhLaIdMr0/sPZgyZBD5YRhv54GFjh94UYWKhEbc1qyltW7imupwg==", + "dev": true + }, "node_modules/@dvsa/cvs-type-definitions": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/@dvsa/cvs-type-definitions/-/cvs-type-definitions-6.3.0.tgz", @@ -3396,25 +3438,6 @@ "util": "^0.12.5" } }, - "node_modules/@dvsa/eslint-config-ts": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@dvsa/eslint-config-ts/-/eslint-config-ts-3.0.1.tgz", - "integrity": "sha512-kvXp2oD9o8RfvcIrxHH5Dp2cWxZ65D6POslJZ+tnyExPVhWyxFDJjGehkpsJHPawkpp6/SsXtjv9Qe76XbDk9w==", - "dev": true, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": ">=4.33.0", - "@typescript-eslint/typescript-estree": ">=4.33.0", - "eslint": ">=7.32.0", - "eslint-config-airbnb-base": ">=14.2.0", - "eslint-config-airbnb-typescript": ">=12.3.1", - "eslint-plugin-import": ">=2.24.2", - "eslint-plugin-jest": ">=25.2.4", - "eslint-plugin-jsx-a11y": ">=6.4.1", - "eslint-plugin-react": ">=7.26.1", - "eslint-plugin-react-hooks": ">=4.2.0", - "eslint-plugin-security": ">=2.1.0" - } - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.20.0", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.0.tgz", @@ -3783,139 +3806,6 @@ "node": ">=12" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, "node_modules/@fastify/busboy": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", @@ -3987,71 +3877,21 @@ "integrity": "sha512-59SgoZ3EXbkfSX7b63tsou/SDGzwUEK6MuB5sKqgVK1/XE0fxmpsOb9DQI8LXW3KfGnAjImCGhhEb7uPPAUVNA==", "dev": true }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==" - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" + "node": ">=12" } }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { @@ -5059,6 +4899,7 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -5071,6 +4912,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, "engines": { "node": ">= 8" } @@ -5079,6 +4921,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -5308,79 +5151,6 @@ "node": "^16.13.0 || >=18.0.0" } }, - "node_modules/@nrwl/devkit": { - "version": "17.2.8", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-17.2.8.tgz", - "integrity": "sha512-l2dFy5LkWqSA45s6pee6CoqJeluH+sjRdVnAAQfjLHRNSx6mFAKblyzq5h1f4P0EUCVVVqLs+kVqmNx5zxYqvw==", - "dev": true, - "dependencies": { - "@nx/devkit": "17.2.8" - } - }, - "node_modules/@nrwl/tao": { - "version": "17.2.8", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-17.2.8.tgz", - "integrity": "sha512-Qpk5YKeJ+LppPL/wtoDyNGbJs2MsTi6qyX/RdRrEc8lc4bk6Cw3Oul1qTXCI6jT0KzTz+dZtd0zYD/G7okkzvg==", - "dev": true, - "dependencies": { - "nx": "17.2.8", - "tslib": "^2.3.0" - }, - "bin": { - "tao": "index.js" - } - }, - "node_modules/@nx/devkit": { - "version": "17.2.8", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-17.2.8.tgz", - "integrity": "sha512-6LtiQihtZwqz4hSrtT5cCG5XMCWppG6/B8c1kNksg97JuomELlWyUyVF+sxmeERkcLYFaKPTZytP0L3dmCFXaw==", - "dev": true, - "dependencies": { - "@nrwl/devkit": "17.2.8", - "ejs": "^3.1.7", - "enquirer": "~2.3.6", - "ignore": "^5.0.4", - "semver": "7.5.3", - "tmp": "~0.2.1", - "tslib": "^2.3.0" - }, - "peerDependencies": { - "nx": ">= 16 <= 18" - } - }, - "node_modules/@nx/devkit/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@nx/devkit/node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@nx/devkit/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@nx/nx-darwin-arm64": { "version": "18.0.4", "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-18.0.4.tgz", @@ -5411,70 +5181,6 @@ "node": ">= 10" } }, - "node_modules/@nx/nx-freebsd-x64": { - "version": "17.2.8", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-17.2.8.tgz", - "integrity": "sha512-YFMgx5Qpp2btCgvaniDGdu7Ctj56bfFvbbaHQWmOeBPK1krNDp2mqp8HK6ZKOfEuDJGOYAp7HDtCLvdZKvJxzA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "17.2.8", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-17.2.8.tgz", - "integrity": "sha512-iN2my6MrhLRkVDtdivQHugK8YmR7URo1wU9UDuHQ55z3tEcny7LV3W9NSsY9UYPK/FrxdDfevj0r2hgSSdhnzA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "17.2.8", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-17.2.8.tgz", - "integrity": "sha512-Iy8BjoW6mOKrSMiTGujUcNdv+xSM1DALTH6y3iLvNDkGbjGK1Re6QNnJAzqcXyDpv32Q4Fc57PmuexyysZxIGg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-linux-arm64-musl": { - "version": "17.2.8", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-17.2.8.tgz", - "integrity": "sha512-9wkAxWzknjpzdofL1xjtU6qPFF1PHlvKCZI3hgEYJDo4mQiatGI+7Ttko+lx/ZMP6v4+Umjtgq7+qWrApeKamQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@nx/nx-linux-x64-gnu": { "version": "18.0.4", "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-18.0.4.tgz", @@ -5490,38 +5196,6 @@ "node": ">= 10" } }, - "node_modules/@nx/nx-linux-x64-musl": { - "version": "17.2.8", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-17.2.8.tgz", - "integrity": "sha512-QiakXZ1xBCIptmkGEouLHQbcM4klQkcr+kEaz2PlNwy/sW3gH1b/1c0Ed5J1AN9xgQxWspriAONpScYBRgxdhA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nx/nx-win32-arm64-msvc": { - "version": "17.2.8", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-17.2.8.tgz", - "integrity": "sha512-XBWUY/F/GU3vKN9CAxeI15gM4kr3GOBqnzFZzoZC4qJt2hKSSUEWsMgeZtsMgeqEClbi4ZyCCkY7YJgU32WUGA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@nx/nx-win32-x64-msvc": { "version": "18.0.4", "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-18.0.4.tgz", @@ -5547,18 +5221,6 @@ "node": ">=14" } }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.12.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz", @@ -6753,11 +6415,6 @@ "@types/lowdb": "*" } }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" - }, "node_modules/@types/lodash": { "version": "4.14.202", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", @@ -6845,12 +6502,6 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true - }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", @@ -6932,1520 +6583,1349 @@ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "node_modules/@vitejs/plugin-basic-ssl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", + "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=14.6.0" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" } }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.62.0.tgz", - "integrity": "sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==", + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dev": true, "dependencies": { - "@typescript-eslint/utils": "5.62.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@xtuc/ieee754": "^1.2.0" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "@xtuc/long": "4.2.2" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", "dev": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", "dev": true, "engines": { - "node": ">=4.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">= 0.6" } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", - "dev": true, + "node_modules/accessible-autocomplete": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/accessible-autocomplete/-/accessible-autocomplete-2.0.4.tgz", + "integrity": "sha512-2p0txrSpvs5wXFUeQJHMheDPTZVSEmiUHWlEPb7vJnv2Dd1xPfoLnBQQMfNbTSit2pL/9sSQYESuD2Yyohd4Yw==", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "preact": "^8.3.1" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=0.4.0" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.19.0.tgz", - "integrity": "sha512-mcvS6WSWbjiSxKCwBcXtOM5pRkPQ6kcDds/juxcy/727IQr3xMEcwr/YLHW2A2+Fp5ql6khjbKBzOyjuPqGi/w==", + "node_modules/acorn-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.19.0", - "@typescript-eslint/utils": "6.19.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.0.tgz", - "integrity": "sha512-lFviGV/vYhOy3m8BJ/nAKoAyNhInTdXpftonhWle66XHAtT1ouBlkjL496b5H5hb8dWXHwtypTqgtb/DEa+j5A==", + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "acorn": "^8" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.0.tgz", - "integrity": "sha512-o/zefXIbbLBZ8YJ51NlkSAt2BamrK6XOmuxSR3hynMIzzyMY33KuJ9vuMdFSXW+H0tVvdF9qBPTHA91HDb4BIQ==", + "node_modules/acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/visitor-keys": "6.19.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.0.tgz", - "integrity": "sha512-hZaUCORLgubBvtGpp1JEFEazcuEdfxta9j4iUwdSAr7mEsYYAp3EAUyCZk3VEEqGj6W+AV4uWyrDGtrlawAsgQ==", + "node_modules/acorn-node/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.19.0", - "eslint-visitor-keys": "^3.4.1" + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=0.4.0" } }, - "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "node_modules/acorn-node/node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", "dev": true, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=0.4.0" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz", - "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", "dev": true, - "peer": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=8.9" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": ">=8.9.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/types": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", - "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "node_modules/adm-zip": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", + "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==", "dev": true, - "peer": true, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=6.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/visitor-keys": { + "node_modules/agent-base": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", - "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", "dev": true, - "peer": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", - "eslint-visitor-keys": "^3.4.1" + "debug": "^4.3.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">= 14" } }, - "node_modules/@typescript-eslint/utils": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.0.tgz", - "integrity": "sha512-QR41YXySiuN++/dC9UArYOg4X86OAYP83OWTewpVx5ct1IZhjjgTLocj7QNxGhWoTqknsgpl7L+hGygCO+sdYw==", + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.19.0", - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/typescript-estree": "6.19.0", - "semver": "^7.5.4" + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.0.tgz", - "integrity": "sha512-dO1XMhV2ehBI6QN8Ufi7I10wmUovmLU0Oru3n5LVlM2JuzB4M+dVphCPLkVpKvGij2j/pHBWuJ9piuXx+BhzxQ==", + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/visitor-keys": "6.19.0" + "ajv": "^8.0.0" }, - "engines": { - "node": "^16.0.0 || >=18.0.0" + "peerDependencies": { + "ajv": "^8.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.0.tgz", - "integrity": "sha512-lFviGV/vYhOy3m8BJ/nAKoAyNhInTdXpftonhWle66XHAtT1ouBlkjL496b5H5hb8dWXHwtypTqgtb/DEa+j5A==", + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" + "dependencies": { + "fast-deep-equal": "^3.1.3" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "ajv": "^8.8.2" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.0.tgz", - "integrity": "sha512-o/zefXIbbLBZ8YJ51NlkSAt2BamrK6XOmuxSR3hynMIzzyMY33KuJ9vuMdFSXW+H0tVvdF9qBPTHA91HDb4BIQ==", + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", "dev": true, + "optional": true, + "engines": { + "node": ">=0.4.2" + } + }, + "node_modules/angular-google-tag-manager": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/angular-google-tag-manager/-/angular-google-tag-manager-1.9.0.tgz", + "integrity": "sha512-4FIgoeljnbrsWHanKcud6zSGf08sH6Frdk6xcP5pauAk+YVMhxxoCisAsI0HSmzi5jPOguma3F+/+wHdtE3RjA==", "dependencies": { - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/visitor-keys": "6.19.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "tslib": "^2.5.0" }, + "peerDependencies": { + "@angular/common": "^17.0.3", + "@angular/compiler": "^17.0.3" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=6" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.0.tgz", - "integrity": "sha512-hZaUCORLgubBvtGpp1JEFEazcuEdfxta9j4iUwdSAr7mEsYYAp3EAUyCZk3VEEqGj6W+AV4uWyrDGtrlawAsgQ==", + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.0", - "eslint-visitor-keys": "^3.4.1" + "type-fest": "^0.21.3" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" - }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } }, - "node_modules/@vitejs/plugin-basic-ssl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", - "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "engines": { - "node": ">=14.6.0" - }, - "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + "node": ">=8" } }, - "node_modules/@webassemblyjs/ast": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", - "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", - "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "node_modules/ansi-styles/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@xtuc/long": "4.2.2" + "color-name": "1.1.3" } }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "node_modules/ansi-styles/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", - "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "node_modules/apache-crypt": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/apache-crypt/-/apache-crypt-1.2.6.tgz", + "integrity": "sha512-072WetlM4blL8PREJVeY+WHiUh1R5VNt2HfceGS8aKqttPHcmqE5pkKuXPz/ULmJOFkc8Hw3kfKl6vy7Qka6DA==", "dev": true, "dependencies": { - "@xtuc/long": "4.2.2" + "unix-crypt-td-js": "^1.1.4" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", - "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "node_modules/apache-md5": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/apache-md5/-/apache-md5-1.1.8.tgz", + "integrity": "sha512-FCAJojipPn0bXjuEpjOOOMN8FZDkxfWWp4JGN9mifU2IhxvKyXZYqpzPHdnTSUpmPDy+tsslB6Z1g+Vg6nVbYA==", "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-opt": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6", - "@webassemblyjs/wast-printer": "1.11.6" + "engines": { + "node": ">=8" } }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", - "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", - "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6" + "sprintf-js": "~1.0.2" } }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", - "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==", + "dev": true + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", - "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "node_modules/ast-transform": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/ast-transform/-/ast-transform-0.0.0.tgz", + "integrity": "sha512-e/JfLiSoakfmL4wmTGPjv0HpTICVmxwXgYOB8x+mzozHL8v+dSfCbrJ8J8hJ0YBP0XcYu1aLZ6b/3TnxNK3P2A==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@xtuc/long": "4.2.2" + "escodegen": "~1.2.0", + "esprima": "~1.0.4", + "through": "~2.3.4" } }, - "node_modules/@xtuc/ieee754": { + "node_modules/ast-transform/node_modules/escodegen": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "node_modules/@yarnpkg/lockfile": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true - }, - "node_modules/@yarnpkg/parsers": { - "version": "3.0.0-rc.46", - "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz", - "integrity": "sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.2.0.tgz", + "integrity": "sha512-yLy3Cc+zAC0WSmoT2fig3J87TpQ8UaZGx8ahCAs9FL8qNbyV7CVyPKS74DG4bsHiL5ew9sxdYx131OkBQMFnvA==", "dev": true, "dependencies": { - "js-yaml": "^3.10.0", - "tslib": "^2.4.0" + "esprima": "~1.0.4", + "estraverse": "~1.5.0", + "esutils": "~1.0.0" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" }, "engines": { - "node": ">=14.15.0" + "node": ">=0.4.0" + }, + "optionalDependencies": { + "source-map": "~0.1.30" } }, - "node_modules/@zkochan/js-yaml": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz", - "integrity": "sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg==", + "node_modules/ast-transform/node_modules/esprima": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, "bin": { - "js-yaml": "bin/js-yaml.js" + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.4.0" } }, - "node_modules/@zkochan/js-yaml/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "deprecated": "Use your platform's native atob() and btoa() methods instead", - "dev": true - }, - "node_modules/abbrev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", - "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "node_modules/ast-transform/node_modules/estraverse": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz", + "integrity": "sha512-FpCjJDfmo3vsc/1zKSeqR5k42tcIhxFIlvq+h9j0fO2q/h2uLKyweq7rYJ+0CoVvrGQOxIS5wyBrW/+vF58BUQ==", "dev": true, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=0.4.0" } }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/ast-transform/node_modules/esutils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz", + "integrity": "sha512-x/iYH53X3quDwfHRz4y8rn4XcEwwCJeWsul9pF1zldMbGtgOtMNBEOuYWwB1EQlK2LRa1fev3YAgym/RElp5Cg==", "dev": true, - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/accessible-autocomplete": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/accessible-autocomplete/-/accessible-autocomplete-2.0.4.tgz", - "integrity": "sha512-2p0txrSpvs5wXFUeQJHMheDPTZVSEmiUHWlEPb7vJnv2Dd1xPfoLnBQQMfNbTSit2pL/9sSQYESuD2Yyohd4Yw==", + "node_modules/ast-transform/node_modules/source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", + "dev": true, + "optional": true, "dependencies": { - "preact": "^8.3.1" - } - }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "bin": { - "acorn": "bin/acorn" + "amdefine": ">=0.0.4" }, "engines": { - "node": ">=0.4.0" + "node": ">=0.8.0" } }, - "node_modules/acorn-globals": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", - "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", + "node_modules/ast-types": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.7.8.tgz", + "integrity": "sha512-RIOpVnVlltB6PcBJ5BMLx+H+6JJ/zjDGU0t7f0L6c2M1dqcK92VQopLBlPQ9R80AVXelfqYgjcPLtHtDbNFg0Q==", "dev": true, - "dependencies": { - "acorn": "^8.1.0", - "acorn-walk": "^8.0.2" + "engines": { + "node": ">= 0.6" } }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/autoprefixer": { + "version": "10.4.17", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.17.tgz", + "integrity": "sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.22.2", + "caniuse-lite": "^1.0.30001578", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, "peerDependencies": { - "acorn": "^8" + "postcss": "^8.1.0" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "dev": true, "dependencies": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" } }, - "node_modules/acorn-node/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "node_modules/babel-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "color-convert": "^2.0.1" }, "engines": { - "node": ">=0.4.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/acorn-node/node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">=0.4.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "node_modules/babel-jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=0.4.0" + "node": ">=8" } }, - "node_modules/adjust-sourcemap-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", - "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "node_modules/babel-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "loader-utils": "^2.0.0", - "regex-parser": "^2.2.11" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=8.9" + "node": ">=8" } }, - "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "node_modules/babel-loader": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", "dev": true, "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" }, "engines": { - "node": ">=8.9.0" + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" } }, - "node_modules/adm-zip": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", - "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==", + "node_modules/babel-loader/node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", "dev": true, + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, "engines": { - "node": ">=6.0" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "node_modules/babel-loader/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", "dev": true, "dependencies": { - "debug": "^4.3.4" + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" }, "engines": { - "node": ">= 14" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "node_modules/babel-loader/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", "dev": true, "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" + "p-locate": "^6.0.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "node_modules/babel-loader/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, "dependencies": { - "ajv": "^8.0.0" + "yocto-queue": "^1.0.0" }, - "peerDependencies": { - "ajv": "^8.0.0" + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "node_modules/babel-loader/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.3" + "p-limit": "^4.0.0" }, - "peerDependencies": { - "ajv": "^8.8.2" + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.4.2" - } - }, - "node_modules/angular-google-tag-manager": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/angular-google-tag-manager/-/angular-google-tag-manager-1.9.0.tgz", - "integrity": "sha512-4FIgoeljnbrsWHanKcud6zSGf08sH6Frdk6xcP5pauAk+YVMhxxoCisAsI0HSmzi5jPOguma3F+/+wHdtE3RjA==", - "dependencies": { - "tslib": "^2.5.0" - }, - "peerDependencies": { - "@angular/common": "^17.0.3", - "@angular/compiler": "^17.0.3" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "node_modules/babel-loader/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true, "engines": { - "node": ">=6" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "node_modules/babel-loader/node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "dev": true, "dependencies": { - "type-fest": "^0.21.3" + "find-up": "^6.3.0" }, "engines": { - "node": ">=8" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "node_modules/babel-loader/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "bin": { - "ansi-html": "bin/ansi-html" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, "engines": { "node": ">=8" } }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" }, "engines": { - "node": ">=4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/ansi-styles/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.8.tgz", + "integrity": "sha512-OtIuQfafSzpo/LhnJaykc0R/MMnuLSSVjVYy9mHArIZ9qTCSZ6TpWCuEKZYVoN//t8HqBNScHrOtCrIK5IaGLg==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.5.0", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/ansi-styles/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", + "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", "dev": true, "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "@babel/helper-define-polyfill-provider": "^0.5.0", + "core-js-compat": "^3.34.0" }, - "engines": { - "node": ">= 8" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", + "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", "dev": true, - "engines": { - "node": ">=8.6" + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/apache-crypt": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/apache-crypt/-/apache-crypt-1.2.6.tgz", - "integrity": "sha512-072WetlM4blL8PREJVeY+WHiUh1R5VNt2HfceGS8aKqttPHcmqE5pkKuXPz/ULmJOFkc8Hw3kfKl6vy7Qka6DA==", + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, "dependencies": { - "unix-crypt-td-js": "^1.1.4" + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/apache-md5": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/apache-md5/-/apache-md5-1.1.8.tgz", - "integrity": "sha512-FCAJojipPn0bXjuEpjOOOMN8FZDkxfWWp4JGN9mifU2IhxvKyXZYqpzPHdnTSUpmPDy+tsslB6Z1g+Vg6nVbYA==", + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", "dev": true, "dependencies": { - "dequal": "^2.0.3" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", - "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" + "safe-buffer": "5.1.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.8" } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true }, - "node_modules/array-from": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==", - "dev": true - }, - "node_modules/array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "node_modules/bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", "dev": true }, - "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" - }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "*" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/array.prototype.filter": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz", - "integrity": "sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw==", + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-array-method-boxes-properly": "^1.0.0", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" } }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz", - "integrity": "sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ==", + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.8" } }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" }, "engines": { - "node": ">= 0.4" + "node": ">=0.6" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", - "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", "dev": true, - "peer": true, "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.1.0", - "es-shim-unscopables": "^1.0.2" + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" } }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/bootstrap.native": { + "version": "5.0.11", + "resolved": "https://registry.npmjs.org/bootstrap.native/-/bootstrap.native-5.0.11.tgz", + "integrity": "sha512-bk2i4sQcQk2KuCTs1yygTa+JGjZOpKzIZ/It6TZZOO/Q+PmVGuKuIbrznXF64BUFxXaPNy7gO9LnE7vjGdauSQ==", + "dev": true, "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" + "@thednp/event-listener": "^2.0.4", + "@thednp/shorty": "^2.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=16", + "pnpm": ">=8.6.0" } }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "engines": { - "node": ">=0.10.0" + "dependencies": { + "balanced-match": "^1.0.0" } }, - "node_modules/ast-transform": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/ast-transform/-/ast-transform-0.0.0.tgz", - "integrity": "sha512-e/JfLiSoakfmL4wmTGPjv0HpTICVmxwXgYOB8x+mzozHL8v+dSfCbrJ8J8hJ0YBP0XcYu1aLZ6b/3TnxNK3P2A==", + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "dependencies": { - "escodegen": "~1.2.0", - "esprima": "~1.0.4", - "through": "~2.3.4" + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/ast-transform/node_modules/escodegen": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.2.0.tgz", - "integrity": "sha512-yLy3Cc+zAC0WSmoT2fig3J87TpQ8UaZGx8ahCAs9FL8qNbyV7CVyPKS74DG4bsHiL5ew9sxdYx131OkBQMFnvA==", + "node_modules/brfs": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brfs/-/brfs-2.0.2.tgz", + "integrity": "sha512-IrFjVtwu4eTJZyu8w/V2gxU7iLTtcHih67sgEdzrhjLBMHp2uYefUBfdM4k2UvcuWMgV7PQDZHSLeNWnLFKWVQ==", "dev": true, "dependencies": { - "esprima": "~1.0.4", - "estraverse": "~1.5.0", - "esutils": "~1.0.0" + "quote-stream": "^1.0.1", + "resolve": "^1.1.5", + "static-module": "^3.0.2", + "through2": "^2.0.0" }, "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=0.4.0" - }, - "optionalDependencies": { - "source-map": "~0.1.30" + "brfs": "bin/cmd.js" } }, - "node_modules/ast-transform/node_modules/esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", + "node_modules/brfs/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/brfs/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/ast-transform/node_modules/estraverse": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz", - "integrity": "sha512-FpCjJDfmo3vsc/1zKSeqR5k42tcIhxFIlvq+h9j0fO2q/h2uLKyweq7rYJ+0CoVvrGQOxIS5wyBrW/+vF58BUQ==", + "node_modules/brfs/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "engines": { - "node": ">=0.4.0" + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "node_modules/ast-transform/node_modules/esutils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz", - "integrity": "sha512-x/iYH53X3quDwfHRz4y8rn4XcEwwCJeWsul9pF1zldMbGtgOtMNBEOuYWwB1EQlK2LRa1fev3YAgym/RElp5Cg==", + "node_modules/brfs/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "dev": true, - "engines": { - "node": ">=0.10.0" + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" } }, - "node_modules/ast-transform/node_modules/source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", "dev": true, - "optional": true, "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" + "base64-js": "^1.1.2" } }, - "node_modules/ast-types": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.7.8.tgz", - "integrity": "sha512-RIOpVnVlltB6PcBJ5BMLx+H+6JJ/zjDGU0t7f0L6c2M1dqcK92VQopLBlPQ9R80AVXelfqYgjcPLtHtDbNFg0Q==", + "node_modules/browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", "dev": true, - "engines": { - "node": ">= 0.6" + "dependencies": { + "resolve": "1.1.7" } }, - "node_modules/ast-types-flow": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", - "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", - "dev": true, - "peer": true - }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "node_modules/browser-resolve/node_modules/resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", "dev": true }, - "node_modules/asynciterator.prototype": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", - "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", + "node_modules/browserify-optional": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-optional/-/browserify-optional-1.0.1.tgz", + "integrity": "sha512-VrhjbZ+Ba5mDiSYEuPelekQMfTbhcA2DhLk2VQWqdcCROWeFqlTcXZ7yfRkXCIl8E+g4gINJYJiRB7WEtfomAQ==", "dev": true, - "peer": true, "dependencies": { - "has-symbols": "^1.0.3" + "ast-transform": "0.0.0", + "ast-types": "^0.7.0", + "browser-resolve": "^1.8.1" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/autoprefixer": { - "version": "10.4.17", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.17.tgz", - "integrity": "sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==", + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, "funding": [ { "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "url": "https://opencollective.com/browserslist" }, { "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" + "url": "https://tidelift.com/funding/github/npm/browserslist" }, { "type": "github", @@ -8453,601 +7933,694 @@ } ], "dependencies": { - "browserslist": "^4.22.2", - "caniuse-lite": "^1.0.30001578", - "fraction.js": "^4.3.7", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" }, "bin": { - "autoprefixer": "bin/autoprefixer" + "browserslist": "cli.js" }, "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, "dependencies": { - "possible-typed-array-names": "^1.0.0" + "fast-json-stable-stringify": "2.x" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 6" } }, - "node_modules/axe-core": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", - "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, - "peer": true, - "engines": { - "node": ">=4" + "dependencies": { + "node-int64": "^0.4.0" } }, - "node_modules/axios": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", - "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "dependencies": { - "follow-redirects": "^1.15.4", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" } }, - "node_modules/axobject-query": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", - "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", + "node_modules/buffer-equal": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", + "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==", "dev": true, - "dependencies": { - "dequal": "^2.0.3" + "engines": { + "node": ">=0.4.0" } }, - "node_modules/babel-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", - "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", "dev": true, "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" + "semver": "^7.0.0" } }, - "node_modules/babel-jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">= 0.8" } }, - "node_modules/babel-jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/cacache": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz", + "integrity": "sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/babel-jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/cacache/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "dev": true, "engines": { - "node": ">=8" + "node": "14 || >=16.14" } }, - "node_modules/babel-jest/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dependencies": { - "has-flag": "^4.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/babel-loader": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", - "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", + "node_modules/callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==", "dev": true, - "dependencies": { - "find-cache-dir": "^4.0.0", - "schema-utils": "^4.0.0" - }, "engines": { - "node": ">= 14.15.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0", - "webpack": ">=5" + "node": "*" } }, - "node_modules/babel-loader/node_modules/find-cache-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", - "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, - "dependencies": { - "common-path-prefix": "^3.0.0", - "pkg-dir": "^7.0.0" - }, "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, - "node_modules/babel-loader/node_modules/find-up": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", - "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" } }, - "node_modules/babel-loader/node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, - "dependencies": { - "p-locate": "^6.0.0" - }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, - "node_modules/babel-loader/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", "dev": true, "dependencies": { - "yocto-queue": "^1.0.0" + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/babel-loader/node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "node_modules/caniuse-lite": { + "version": "1.0.30001591", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz", + "integrity": "sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "dependencies": { - "p-limit": "^4.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, - "node_modules/babel-loader/node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=10" } }, - "node_modules/babel-loader/node_modules/pkg-dir": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", - "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "engines": { + "node": "*" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", "dev": true, "dependencies": { - "find-up": "^6.3.0" + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" }, "engines": { - "node": ">=14.16" + "node": ">= 6" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" } }, - "node_modules/babel-loader/node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", "dev": true, - "engines": { - "node": ">=12.20" + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">=8" + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", - "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10" } }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.8.tgz", - "integrity": "sha512-OtIuQfafSzpo/LhnJaykc0R/MMnuLSSVjVYy9mHArIZ9qTCSZ6TpWCuEKZYVoN//t8HqBNScHrOtCrIK5IaGLg==", + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", "dev": true, - "dependencies": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.5.0", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "engines": { + "node": ">=6.0" } }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" } }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", - "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.5.0", - "core-js-compat": "^3.34.0" + "source-map": "~0.6.0" }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } + "engines": { + "node": ">= 10.0" + } }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", - "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.5.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "engines": { + "node": ">=6" } }, - "node_modules/babel-preset-jest": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", - "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" + "restore-cursor": "^3.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "node": ">=8" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "node_modules/cli-spinners": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", + "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/basic-auth": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, - "dependencies": { - "safe-buffer": "5.1.2" - }, "engines": { - "node": ">= 0.8" + "node": ">= 12" } }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true - }, - "node_modules/bcryptjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", - "dev": true - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, "engines": { - "node": "*" + "node": ">=12" } }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=6" } }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, "engines": { - "node": ">= 0.8" + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" } }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } + "node_modules/code-block-writer": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-12.0.0.tgz", + "integrity": "sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==", + "dev": true }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", "dev": true }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "side-channel": "^1.0.4" + "color-name": "~1.1.4" }, "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=7.0.0" } }, - "node_modules/bonjour-service": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", - "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "multicast-dns": "^7.2.5" + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" } }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, - "node_modules/bootstrap.native": { - "version": "5.0.11", - "resolved": "https://registry.npmjs.org/bootstrap.native/-/bootstrap.native-5.0.11.tgz", - "integrity": "sha512-bk2i4sQcQk2KuCTs1yygTa+JGjZOpKzIZ/It6TZZOO/Q+PmVGuKuIbrznXF64BUFxXaPNy7gO9LnE7vjGdauSQ==", + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "dependencies": { - "@thednp/event-listener": "^2.0.4", - "@thednp/shorty": "^2.0.0" + "delayed-stream": "~1.0.0" }, "engines": { - "node": ">=16", - "pnpm": ">=8.6.0" + "node": ">= 0.8" } }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/commitlint-plugin-function-rules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/commitlint-plugin-function-rules/-/commitlint-plugin-function-rules-3.1.0.tgz", + "integrity": "sha512-K44912/g7ZZ0bEawrsJTn3giDEwDn6T18g/UcimUblv8hcSIoIxMX5uk6LY+uYO9cb/+3Suilbp7XoxP53Nk9g==", + "dev": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@commitlint/lint": ">=9.1.2 <19" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0" + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" } }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "node_modules/complexion": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/complexion/-/complexion-0.2.2.tgz", + "integrity": "sha512-YAfDsYc27CsPQPzZU4i1OklMCyigN7VHPylWba0AWf5VmVr34NpLhHjJm0gumFh9m2aX8fYGCTTgne7oLfXXug==" + }, + "node_modules/complexion-js": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/complexion-js/-/complexion-js-0.2.2.tgz", + "integrity": "sha512-qxqJq0nEBwSEZtoqK8bHIR2VwzbPatjtlU+ZH9IPObitTQqa2xMEryoAlCsjOH+ATgIScHt0aiCUBabPG2Mmcg==", + "peerDependencies": { + "complexion": "^0.2.2" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "mime-db": ">= 1.43.0 < 2" }, "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/brfs": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brfs/-/brfs-2.0.2.tgz", - "integrity": "sha512-IrFjVtwu4eTJZyu8w/V2gxU7iLTtcHih67sgEdzrhjLBMHp2uYefUBfdM4k2UvcuWMgV7PQDZHSLeNWnLFKWVQ==", + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "dev": true, "dependencies": { - "quote-stream": "^1.0.1", - "resolve": "^1.1.5", - "static-module": "^3.0.2", - "through2": "^2.0.0" + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" }, - "bin": { - "brfs": "bin/cmd.js" + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/brfs/node_modules/isarray": { + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true }, - "node_modules/brfs/node_modules/readable-stream": { + "node_modules/concat-stream/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", @@ -9062,7 +8635,7 @@ "util-deprecate": "~1.0.1" } }, - "node_modules/brfs/node_modules/string_decoder": { + "node_modules/concat-stream/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", @@ -9071,3378 +8644,1465 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/brfs/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "dev": true, "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" } }, - "node_modules/brotli": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", - "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, - "dependencies": { - "base64-js": "^1.1.2" + "engines": { + "node": ">=0.8" } }, - "node_modules/browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "node_modules/connect-pause": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/connect-pause/-/connect-pause-0.1.1.tgz", + "integrity": "sha512-a1gSWQBQD73krFXdUEYJom2RTFrWUL3YvXDCRkyv//GVXc79cdW9MngtRuN9ih4FDKBtfJAJId+BbDuX+1rh2w==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "dependencies": { - "resolve": "1.1.7" + "ms": "2.0.0" } }, - "node_modules/browser-resolve/node_modules/resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/browserify-optional": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-optional/-/browserify-optional-1.0.1.tgz", - "integrity": "sha512-VrhjbZ+Ba5mDiSYEuPelekQMfTbhcA2DhLk2VQWqdcCROWeFqlTcXZ7yfRkXCIl8E+g4gINJYJiRB7WEtfomAQ==", + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, "dependencies": { - "ast-transform": "0.0.0", - "ast-types": "^0.7.0", - "browser-resolve": "^1.8.1" + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" } }, - "node_modules/browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true, "funding": [ { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" + "type": "github", + "url": "https://github.com/sponsors/feross" }, { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" + "type": "patreon", + "url": "https://www.patreon.com/feross" }, { - "type": "github", - "url": "https://github.com/sponsors/ai" + "type": "consulting", + "url": "https://feross.org/support" } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" - }, - "bin": { - "browserslist": "cli.js" - }, + ] + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "node": ">= 0.6" } }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "node_modules/conventional-changelog-angular": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", + "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", "dev": true, "dependencies": { - "fast-json-stable-stringify": "2.x" + "compare-func": "^2.0.0" }, "engines": { - "node": ">= 6" + "node": ">=16" } }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "node_modules/conventional-changelog-conventionalcommits": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz", + "integrity": "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==", "dev": true, "dependencies": { - "node-int64": "^0.4.0" + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "node_modules/conventional-commits-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "is-text-path": "^2.0.0", + "JSONStream": "^1.3.5", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "conventional-commits-parser": "cli.mjs" + }, + "engines": { + "node": ">=16" } }, - "node_modules/buffer-equal": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", - "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==", + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", "dev": true, "engines": { - "node": ">=0.4.0" + "node": ">= 0.6" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "dev": true }, - "node_modules/builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", "dev": true, "dependencies": { - "semver": "^7.0.0" + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" } }, - "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, "engines": { - "node": ">= 0.8" + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" } }, - "node_modules/cacache": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz", - "integrity": "sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==", + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "dependencies": { - "@npmcli/fs": "^3.1.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^4.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11", - "unique-filename": "^3.0.0" + "is-glob": "^4.0.3" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=10.13.0" } }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" }, "engines": { - "node": ">= 0.4" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/callsite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", - "integrity": "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==", + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", "dev": true, "engines": { - "node": "*" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "node_modules/core-js-compat": { + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz", + "integrity": "sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==", "dev": true, - "optional": true, - "peer": true, "dependencies": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" + "browserslist": "^4.22.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, "engines": { - "node": ">=6" + "node": ">= 0.10" } }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dev": true, "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001591", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz", - "integrity": "sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true } - ] + } }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/cosmiconfig-typescript-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-5.0.0.tgz", + "integrity": "sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "jiti": "^1.19.1" }, "engines": { - "node": ">=4" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" + "node": ">=v16" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=8.2", + "typescript": ">=4" } }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", - "engines": { - "node": "*" - } - }, - "node_modules/cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" - }, - "engines": { - "node": ">= 6" + "argparse": "^2.0.1" }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", "dev": true, "dependencies": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "node_modules/create-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">=8" }, "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "node_modules/create-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "node_modules/create-jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=6.0" + "node": ">=8" } }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "node_modules/create-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { "node": ">=8" } }, - "node_modules/cjs-module-lexer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, - "node_modules/clean-css": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", - "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "node_modules/critters": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.20.tgz", + "integrity": "sha512-CImNRorKOl5d8TWcnAz5n5izQ6HFsvz29k327/ELy6UFcmbiZNOsinaKvzv16WZR0P6etfSWYzE47C4/56B3Uw==", "dev": true, - "optional": true, - "peer": true, "dependencies": { - "source-map": "~0.6.0" - }, - "engines": { - "node": ">= 10.0" + "chalk": "^4.1.0", + "css-select": "^5.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.2", + "htmlparser2": "^8.0.2", + "postcss": "^8.4.23", + "pretty-bytes": "^5.3.0" } }, - "node_modules/clean-css/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/critters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "optional": true, - "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "node_modules/critters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "restore-cursor": "^3.1.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "node_modules/critters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, - "node_modules/cli-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", - "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "node_modules/critters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">= 12" + "node": ">=8" } }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">=12" + "node": ">= 8" } }, - "node_modules/cliui/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "engines": { + "node": "*" + } + }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", + "dev": true + }, + "node_modules/css-loader": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.10.0.tgz", + "integrity": "sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.4", + "postcss-modules-scope": "^3.1.1", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" }, "engines": { - "node": ">=8" + "node": ">= 12.13.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, "engines": { - "node": ">=0.8" + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" + "bin": { + "cssesc": "bin/cssesc" }, "engines": { - "node": ">=6" + "node": ">=4" } }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" + "node": ">=8" } }, - "node_modules/code-block-writer": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-12.0.0.tgz", - "integrity": "sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==", - "dev": true - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "dev": true }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "es5-ext": "^0.10.50", + "type": "^1.0.1" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "node_modules/dag-map": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/dag-map/-/dag-map-1.0.2.tgz", + "integrity": "sha512-+LSAiGFwQ9dRnRdOeaj7g47ZFJcOUPukAP8J3A3fuZ1g9Y44BG+P1sgApjLXTQPOzC4+7S9Wr8kXsfpINM4jpw==" }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "node_modules/dargs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", + "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", "dev": true, - "bin": { - "color-support": "bin.js" + "engines": { + "node": ">=8" } }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "node_modules/dash-ast": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-2.0.1.tgz", + "integrity": "sha512-5TXltWJGc+RdnabUGzhRae1TRq6m4gr+3K2wQX0is5/F2yS6MJXJvLyI3ErAnsAXuJoGqvfVD5icRgim07DrxQ==", "dev": true }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", "dev": true, + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", - "dev": true, - "engines": { - "node": ">=16" - } - }, - "node_modules/commitlint-plugin-function-rules": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/commitlint-plugin-function-rules/-/commitlint-plugin-function-rules-3.1.0.tgz", - "integrity": "sha512-K44912/g7ZZ0bEawrsJTn3giDEwDn6T18g/UcimUblv8hcSIoIxMX5uk6LY+uYO9cb/+3Suilbp7XoxP53Nk9g==", - "dev": true, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@commitlint/lint": ">=9.1.2 <19" - } - }, - "node_modules/common-path-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", - "dev": true - }, - "node_modules/compare-func": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", - "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", - "dev": true, - "dependencies": { - "array-ify": "^1.0.0", - "dot-prop": "^5.1.0" - } - }, - "node_modules/complexion": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/complexion/-/complexion-0.2.2.tgz", - "integrity": "sha512-YAfDsYc27CsPQPzZU4i1OklMCyigN7VHPylWba0AWf5VmVr34NpLhHjJm0gumFh9m2aX8fYGCTTgne7oLfXXug==" - }, - "node_modules/complexion-js": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/complexion-js/-/complexion-js-0.2.2.tgz", - "integrity": "sha512-qxqJq0nEBwSEZtoqK8bHIR2VwzbPatjtlU+ZH9IPObitTQqa2xMEryoAlCsjOH+ATgIScHt0aiCUBabPG2Mmcg==", - "peerDependencies": { - "complexion": "^0.2.2" - } - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dev": true, - "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/concat-stream/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/concat-stream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/concat-stream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", - "dev": true, - "peer": true - }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/connect-pause": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/connect-pause/-/connect-pause-0.1.1.tgz", - "integrity": "sha512-a1gSWQBQD73krFXdUEYJom2RTFrWUL3YvXDCRkyv//GVXc79cdW9MngtRuN9ih4FDKBtfJAJId+BbDuX+1rh2w==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/connect/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/connect/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-disposition/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/conventional-changelog-angular": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", - "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", - "dev": true, - "dependencies": { - "compare-func": "^2.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/conventional-changelog-conventionalcommits": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz", - "integrity": "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==", - "dev": true, - "dependencies": { - "compare-func": "^2.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/conventional-commits-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", - "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", - "dev": true, - "dependencies": { - "is-text-path": "^2.0.0", - "JSONStream": "^1.3.5", - "meow": "^12.0.1", - "split2": "^4.0.0" - }, - "bin": { - "conventional-commits-parser": "cli.mjs" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true - }, - "node_modules/copy-anything": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", - "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", - "dev": true, - "dependencies": { - "is-what": "^3.14.1" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, - "node_modules/copy-webpack-plugin": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", - "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", - "dev": true, - "dependencies": { - "fast-glob": "^3.2.11", - "glob-parent": "^6.0.1", - "globby": "^13.1.1", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0" - }, - "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - } - }, - "node_modules/copy-webpack-plugin/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/copy-webpack-plugin/node_modules/globby": { - "version": "13.2.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", - "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", - "dev": true, - "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.3.0", - "ignore": "^5.2.4", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/copy-webpack-plugin/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/core-js-compat": { - "version": "3.36.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz", - "integrity": "sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==", - "dev": true, - "dependencies": { - "browserslist": "^4.22.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dev": true, - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/cosmiconfig-typescript-loader": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-5.0.0.tgz", - "integrity": "sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==", - "dev": true, - "dependencies": { - "jiti": "^1.19.1" - }, - "engines": { - "node": ">=v16" - }, - "peerDependencies": { - "@types/node": "*", - "cosmiconfig": ">=8.2", - "typescript": ">=4" - } - }, - "node_modules/cosmiconfig/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/cosmiconfig/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/create-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", - "dev": true, - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" - }, - "bin": { - "create-jest": "bin/create-jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/create-jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/create-jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/create-jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/create-jest/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/critters": { - "version": "0.0.20", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.20.tgz", - "integrity": "sha512-CImNRorKOl5d8TWcnAz5n5izQ6HFsvz29k327/ELy6UFcmbiZNOsinaKvzv16WZR0P6etfSWYzE47C4/56B3Uw==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "css-select": "^5.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.2", - "htmlparser2": "^8.0.2", - "postcss": "^8.4.23", - "pretty-bytes": "^5.3.0" - } - }, - "node_modules/critters/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/critters/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/critters/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/critters/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", - "engines": { - "node": "*" - } - }, - "node_modules/crypto-js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", - "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", - "dev": true - }, - "node_modules/css-loader": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.10.0.tgz", - "integrity": "sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==", - "dev": true, - "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.33", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.4", - "postcss-modules-scope": "^3.1.1", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } - } - }, - "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cssom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, - "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "node_modules/dag-map": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/dag-map/-/dag-map-1.0.2.tgz", - "integrity": "sha512-+LSAiGFwQ9dRnRdOeaj7g47ZFJcOUPukAP8J3A3fuZ1g9Y44BG+P1sgApjLXTQPOzC4+7S9Wr8kXsfpINM4jpw==" - }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true, - "peer": true - }, - "node_modules/dargs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-7.0.0.tgz", - "integrity": "sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/dash-ast": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-2.0.1.tgz", - "integrity": "sha512-5TXltWJGc+RdnabUGzhRae1TRq6m4gr+3K2wQX0is5/F2yS6MJXJvLyI3ErAnsAXuJoGqvfVD5icRgim07DrxQ==", - "dev": true - }, - "node_modules/data-urls": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", - "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decache": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/decache/-/decache-4.6.2.tgz", - "integrity": "sha512-2LPqkLeu8XWHU8qNCS3kcF6sCcb5zIzvWaAHYSvPfwhdd7mHuah29NssMzrTYyHN4F5oFy2ko9OBYxegtU0FEw==", - "dev": true, - "dependencies": { - "callsite": "^1.0.0" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", - "dev": true, - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decamelize-keys/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "dev": true - }, - "node_modules/dedent": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", - "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", - "dev": true, - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/deep-equal": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", - "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", - "dev": true, - "dependencies": { - "is-arguments": "^1.1.1", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.5.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" - }, - "node_modules/deep-object-diff": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.9.tgz", - "integrity": "sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==" - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "dev": true, - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/defaults/node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true - }, - "node_modules/dfa": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", - "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==", - "dev": true - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dns-packet": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", - "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", - "dev": true, - "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "utila": "~0.4" - } - }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "deprecated": "Use your platform's native DOMException instead", - "dev": true, - "dependencies": { - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dev": true, - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dot": { - "version": "2.0.0-beta.1", - "resolved": "https://registry.npmjs.org/dot/-/dot-2.0.0-beta.1.tgz", - "integrity": "sha512-kxM7fSnNQTXOmaeGuBSXM8O3fEsBb7XSDBllkGbRwa0lJSJTxxDE/4eSNGLKZUmlFw0f1vJ5qSV2BljrgQtgIA==", - "dev": true - }, - "node_modules/dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dotenv-expand": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", - "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.2" - } - }, - "node_modules/duplexer2/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/duplexer2/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/duplexer2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true - }, - "node_modules/ejs": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", - "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", - "dev": true, - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.687", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.687.tgz", - "integrity": "sha512-Ic85cOuXSP6h7KM0AIJ2hpJ98Bo4hyTUjc4yjMbkvD+8yTxEhfK9+8exT2KKYsSjnCn2tGsKVSZwE7ZgTORQCw==", - "dev": true - }, - "node_modules/emitter-component": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/emitter-component/-/emitter-component-1.1.2.tgz", - "integrity": "sha512-QdXO3nXOzZB4pAjM0n6ZE+R9/+kPpECA/XSELIcc54NeYVnBqIk+4DFiBgK+8QbV3mdvTG6nedl7dTYgO+5wDw==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.1.tgz", - "integrity": "sha512-3d3JRbwsCLJsYgvb6NuWEG44jjPSOMuS73L/6+7BZuoKm3W+qXnSoIYVHi8dG7Qcg4inAY4jbzkZ7MnskePeDg==", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true - }, - "node_modules/errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "dev": true, - "optional": true, - "dependencies": { - "prr": "~1.0.1" - }, - "bin": { - "errno": "cli.js" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/errorhandler": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.5.1.tgz", - "integrity": "sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==", - "dev": true, - "dependencies": { - "accepts": "~1.3.7", - "escape-html": "~1.0.3" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-abstract": { - "version": "1.22.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.5.tgz", - "integrity": "sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.1", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.0", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.5", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-array-method-boxes-properly": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", - "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-iterator-helpers": { - "version": "1.0.17", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.17.tgz", - "integrity": "sha512-lh7BsUqelv4KUbR5a/ZTaGGIMLCjPGPqJ6q+Oq24YP0RdyptX1uzm4vvaqzk7Zx3bpl/76YLTTDj9L7uYQ92oQ==", - "dev": true, - "peer": true, - "dependencies": { - "asynciterator.prototype": "^1.0.0", - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.4", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.2", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "globalthis": "^1.0.3", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-module-lexer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", - "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", - "dev": true - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", - "dependencies": { - "get-intrinsic": "^1.2.4", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dependencies": { - "hasown": "^2.0.0" + "node": ">=12" } }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "ms": "2.1.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es5-ext": { - "version": "0.10.64", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", - "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.3", - "esniff": "^2.0.1", - "next-tick": "^1.1.0" + "node": ">=6.0" }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha512-mz3UqCh0uPCIqsw1SSAkB/p0rOzF/M0V++vyN7JqlPtSW/VsYgQBvVvqMLmfBuyMzTpLnNqi6JmcSizs4jy19A==", - "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-set": "~0.1.5", - "es6-symbol": "~3.1.1", - "event-emitter": "~0.3.5" + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/es6-set": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.6.tgz", - "integrity": "sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==", + "node_modules/decache": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/decache/-/decache-4.6.2.tgz", + "integrity": "sha512-2LPqkLeu8XWHU8qNCS3kcF6sCcb5zIzvWaAHYSvPfwhdd7mHuah29NssMzrTYyHN4F5oFy2ko9OBYxegtU0FEw==", "dev": true, "dependencies": { - "d": "^1.0.1", - "es5-ext": "^0.10.62", - "es6-iterator": "~2.0.3", - "es6-symbol": "^3.1.3", - "event-emitter": "^0.3.5", - "type": "^2.7.2" - }, - "engines": { - "node": ">=0.12" + "callsite": "^1.0.0" } }, - "node_modules/es6-set/node_modules/type": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", - "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", - "dev": true - }, - "node_modules/es6-shim": { - "version": "0.35.8", - "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.8.tgz", - "integrity": "sha512-Twf7I2v4/1tLoIXMT8HlqaBSS5H2wQTs2wx3MNYCI8K1R1/clXyCazrcVCPm/FuO9cyV8+leEaZOWD5C253NDg==", - "dev": true - }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", "dev": true, "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "node_modules/esbuild": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.0.tgz", - "integrity": "sha512-6iwE3Y2RVYCME1jLpBqq7LQWK3MW6vjV2bZy6gt/WrqkY+WE74Spyc0ThAOYpMtITvnjX09CrC6ym7A/m9mebA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "bin": { - "esbuild": "bin/esbuild" + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" }, "engines": { - "node": ">=12" + "node": ">=0.10.0" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.0", - "@esbuild/android-arm": "0.20.0", - "@esbuild/android-arm64": "0.20.0", - "@esbuild/android-x64": "0.20.0", - "@esbuild/darwin-arm64": "0.20.0", - "@esbuild/darwin-x64": "0.20.0", - "@esbuild/freebsd-arm64": "0.20.0", - "@esbuild/freebsd-x64": "0.20.0", - "@esbuild/linux-arm": "0.20.0", - "@esbuild/linux-arm64": "0.20.0", - "@esbuild/linux-ia32": "0.20.0", - "@esbuild/linux-loong64": "0.20.0", - "@esbuild/linux-mips64el": "0.20.0", - "@esbuild/linux-ppc64": "0.20.0", - "@esbuild/linux-riscv64": "0.20.0", - "@esbuild/linux-s390x": "0.20.0", - "@esbuild/linux-x64": "0.20.0", - "@esbuild/netbsd-x64": "0.20.0", - "@esbuild/openbsd-x64": "0.20.0", - "@esbuild/sunos-x64": "0.20.0", - "@esbuild/win32-arm64": "0.20.0", - "@esbuild/win32-ia32": "0.20.0", - "@esbuild/win32-x64": "0.20.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/esbuild-wasm": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.20.0.tgz", - "integrity": "sha512-Lc9KeQCg1Zf8kCtfDXgy29rx0x8dOuhDWbkP76Wc64q7ctOOc1Zv1C39AxiE+y4N6ONyXtJk4HKpM7jlU7/jSA==", + "node_modules/decamelize-keys/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, - "bin": { - "esbuild": "bin/esbuild" - }, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", "dev": true, "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", "dev": true }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "node_modules/dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", "dev": true, - "engines": { - "node": ">=0.8.0" + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } } }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "node_modules/deep-equal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", + "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", "dev": true, "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.5.1" }, "engines": { - "node": ">=6.0" + "node": ">= 0.4" }, - "optionalDependencies": { - "source-map": "~0.6.1" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, + "node_modules/deep-object-diff": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.9.tgz", + "integrity": "sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=0.10.0" } }, - "node_modules/eslint-config-airbnb-base": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", - "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "dev": true, - "peer": true, "dependencies": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5", - "semver": "^6.3.0" + "execa": "^5.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.2" - } - }, - "node_modules/eslint-config-airbnb-base/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "peer": true, - "bin": { - "semver": "bin/semver.js" + "node": ">= 10" } }, - "node_modules/eslint-config-airbnb-typescript": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.1.0.tgz", - "integrity": "sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==", + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, - "peer": true, "dependencies": { - "eslint-config-airbnb-base": "^15.0.0" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.13.0 || ^6.0.0", - "@typescript-eslint/parser": "^5.0.0 || ^6.0.0", - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.3" - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" + "clone": "^1.0.2" }, - "peerDependencies": { - "eslint": ">=7.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-etc": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-etc/-/eslint-etc-5.2.1.tgz", - "integrity": "sha512-lFJBSiIURdqQKq9xJhvSJFyPA+VeTh5xvk24e8pxVL7bwLBtGF60C/KRkLTMrvCZ6DA3kbPuYhLWY0TZMlqTsg==", + "node_modules/defaults/node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, - "dependencies": { - "@typescript-eslint/experimental-utils": "^5.0.0", - "tsutils": "^3.17.1", - "tsutils-etc": "^1.4.1" - }, - "peerDependencies": { - "eslint": "^8.0.0", - "typescript": ">=4.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" + "engines": { + "node": ">=0.8" } }, - "node_modules/eslint-import-resolver-typescript": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", - "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dependencies": { - "debug": "^4.3.4", - "enhanced-resolve": "^5.12.0", - "eslint-module-utils": "^2.7.4", - "fast-glob": "^3.3.1", - "get-tsconfig": "^4.5.0", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-module-utils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", - "dependencies": { - "debug": "^3.2.7" - }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" + "node": ">=8" } }, - "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", - "semver": "^6.3.1", - "tsconfig-paths": "^3.15.0" + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { - "node": ">=4" + "node": ">= 0.4" }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" } }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dependencies": { - "esutils": "^2.0.2" - }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, "engines": { - "node": "*" + "node": ">=8" } }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/dfa": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", + "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==", + "dev": true }, - "node_modules/eslint-plugin-jest": { - "version": "27.9.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz", - "integrity": "sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==", + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, - "peer": true, - "dependencies": { - "@typescript-eslint/utils": "^5.10.0" - }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0 || ^7.0.0", - "eslint": "^7.0.0 || ^8.0.0", - "jest": "*" - }, - "peerDependenciesMeta": { - "@typescript-eslint/eslint-plugin": { - "optional": true - }, - "jest": { - "optional": true - } } }, - "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, - "peer": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "path-type": "^4.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", - "dev": true, - "peer": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=8" } }, - "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, - "peer": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "@leichtgewicht/ip-codec": "^2.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "node": ">=6" } }, - "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", "dev": true, + "optional": true, "peer": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "utila": "~0.4" } }, - "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, - "peer": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/eslint-plugin-jest/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", "dev": true, - "peer": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-plugin-jest/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4.0" + "node": ">=12" } }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", - "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, - "peer": true, "dependencies": { - "@babel/runtime": "^7.23.2", - "aria-query": "^5.3.0", - "array-includes": "^3.1.7", - "array.prototype.flatmap": "^1.3.2", - "ast-types-flow": "^0.0.8", - "axe-core": "=4.7.0", - "axobject-query": "^3.2.1", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "es-iterator-helpers": "^1.0.15", - "hasown": "^2.0.0", - "jsx-ast-utils": "^3.3.5", - "language-tags": "^1.0.9", - "minimatch": "^3.1.2", - "object.entries": "^1.1.7", - "object.fromentries": "^2.0.7" + "domelementtype": "^2.3.0" }, "engines": { - "node": ">=4.0" + "node": ">= 4" }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/axobject-query": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", - "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, - "peer": true, "dependencies": { - "dequal": "^2.0.3" + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/dot": { + "version": "2.0.0-beta.1", + "resolved": "https://registry.npmjs.org/dot/-/dot-2.0.0-beta.1.tgz", + "integrity": "sha512-kxM7fSnNQTXOmaeGuBSXM8O3fEsBb7XSDBllkGbRwa0lJSJTxxDE/4eSNGLKZUmlFw0f1vJ5qSV2BljrgQtgIA==", + "dev": true + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", "dev": true, + "optional": true, "peer": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "no-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", "dev": true, - "peer": true, "dependencies": { - "brace-expansion": "^1.1.7" + "is-obj": "^2.0.0" }, "engines": { - "node": "*" + "node": ">=8" } }, - "node_modules/eslint-plugin-ngrx": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-ngrx/-/eslint-plugin-ngrx-2.1.4.tgz", - "integrity": "sha512-ynPPqguIpeiRPcqmkUBx+cZxzMKpx1W2T3bvraai+KZ+LZnkRouWhnr/9L0buN/Efrk7BkpAFKGy+OojPHo+ug==", + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", "dev": true, - "dependencies": { - "@angular-devkit/schematics": "^13.0.3", - "@typescript-eslint/experimental-utils": "^5.4.0", - "eslint-etc": "^5.1.0", - "semver": "^7.3.5", - "strip-json-comments": "3.1.1" + "engines": { + "node": ">=12" }, - "peerDependencies": { - "eslint": ">=8.0.0", - "typescript": ">=4.3.5" + "funding": { + "url": "https://dotenvx.com" } }, - "node_modules/eslint-plugin-ngrx/node_modules/@angular-devkit/core": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.3.11.tgz", - "integrity": "sha512-rfqoLMRYhlz0wzKlHx7FfyIyQq8dKTsmbCoIVU1cEIH0gyTMVY7PbVzwRRcO6xp5waY+0hA+0Brriujpuhkm4w==", + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", "dev": true, "dependencies": { - "ajv": "8.9.0", - "ajv-formats": "2.1.1", - "fast-json-stable-stringify": "2.1.0", - "magic-string": "0.25.7", - "rxjs": "6.6.7", - "source-map": "0.7.3" - }, - "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } + "readable-stream": "^2.0.2" } }, - "node_modules/eslint-plugin-ngrx/node_modules/@angular-devkit/schematics": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-13.3.11.tgz", - "integrity": "sha512-ben+EGXpCrClnIVAAnEQmhQdKmnnqFhMp5BqMxgOslSYBAmCutLA6rBu5vsc8kZcGian1wt+lueF7G1Uk5cGBg==", + "node_modules/duplexer2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "dependencies": { - "@angular-devkit/core": "13.3.11", - "jsonc-parser": "3.0.0", - "magic-string": "0.25.7", - "ora": "5.4.1", - "rxjs": "6.6.7" - }, - "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/eslint-plugin-ngrx/node_modules/ajv": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "safe-buffer": "~5.1.0" } }, - "node_modules/eslint-plugin-ngrx/node_modules/jsonc-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", - "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, - "node_modules/eslint-plugin-ngrx/node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "dependencies": { - "sourcemap-codec": "^1.4.4" - } + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true }, - "node_modules/eslint-plugin-ngrx/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "node_modules/electron-to-chromium": { + "version": "1.4.687", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.687.tgz", + "integrity": "sha512-Ic85cOuXSP6h7KM0AIJ2hpJ98Bo4hyTUjc4yjMbkvD+8yTxEhfK9+8exT2KKYsSjnCn2tGsKVSZwE7ZgTORQCw==", + "dev": true + }, + "node_modules/emitter-component": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/emitter-component/-/emitter-component-1.1.2.tgz", + "integrity": "sha512-QdXO3nXOzZB4pAjM0n6ZE+R9/+kPpECA/XSELIcc54NeYVnBqIk+4DFiBgK+8QbV3mdvTG6nedl7dTYgO+5wDw==", "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-plugin-ngrx/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, "engines": { - "node": ">= 8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" } }, - "node_modules/eslint-plugin-ngrx/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, - "node_modules/eslint-plugin-prettier": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" - }, "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": "*", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } + "node": ">= 4" } }, - "node_modules/eslint-plugin-react": { - "version": "7.33.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", - "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true, - "peer": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.12", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.8" - }, "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "node": ">= 0.8" } }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, - "peer": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "once": "^1.4.0" } }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/enhanced-resolve": { + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.1.tgz", + "integrity": "sha512-3d3JRbwsCLJsYgvb6NuWEG44jjPSOMuS73L/6+7BZuoKm3W+qXnSoIYVHi8dG7Qcg4inAY4jbzkZ7MnskePeDg==", "dev": true, - "peer": true, "dependencies": { - "esutils": "^2.0.2" + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10.13.0" } }, - "node_modules/eslint-plugin-react/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" + "engines": { + "node": ">=0.12" }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, "engines": { - "node": "*" + "node": ">=6" } }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, - "peer": true, + "optional": true, "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "prr": "~1.0.1" }, "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "errno": "cli.js" } }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, - "peer": true, - "bin": { - "semver": "bin/semver.js" + "dependencies": { + "is-arrayish": "^0.2.1" } }, - "node_modules/eslint-plugin-security": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-2.1.1.tgz", - "integrity": "sha512-7cspIGj7WTfR3EhaILzAPcfCo5R9FbeWvbgsPYWivSurTBKW88VQxtP3c4aWMG9Hz/GfJlJVdXEJ3c8LqS+u2w==", + "node_modules/errorhandler": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.5.1.tgz", + "integrity": "sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==", "dev": true, - "peer": true, "dependencies": { - "safe-regex": "^2.1.1" + "accepts": "~1.3.7", + "escape-html": "~1.0.3" + }, + "engines": { + "node": ">= 0.8" } }, - "node_modules/eslint-scope": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.0.tgz", - "integrity": "sha512-zj3Byw6jX4TcFCJmxOzLt6iol5FAr9xQyZZSQjEzW2UiCJXLwXdRIKCYVFftnpZckaC9Ps9xlC7jB8tSeWWOaw==", - "dev": true, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "get-intrinsic": "^1.2.4" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">= 0.4" } }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">= 0.4" } }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } + "node_modules/es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "dev": true }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "dev": true, + "hasInstallScript": true, "dependencies": { - "color-convert": "^2.0.1" + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=0.10" } }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha512-mz3UqCh0uPCIqsw1SSAkB/p0rOzF/M0V++vyN7JqlPtSW/VsYgQBvVvqMLmfBuyMzTpLnNqi6JmcSizs4jy19A==", + "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" } }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/es6-set": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.6.tgz", + "integrity": "sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==", + "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "es6-iterator": "~2.0.3", + "es6-symbol": "^3.1.3", + "event-emitter": "^0.3.5", + "type": "^2.7.2" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=0.12" } }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "node_modules/es6-set/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, + "node_modules/es6-shim": { + "version": "0.35.8", + "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.8.tgz", + "integrity": "sha512-Twf7I2v4/1tLoIXMT8HlqaBSS5H2wQTs2wx3MNYCI8K1R1/clXyCazrcVCPm/FuO9cyV8+leEaZOWD5C253NDg==", + "dev": true }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/esbuild": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.0.tgz", + "integrity": "sha512-6iwE3Y2RVYCME1jLpBqq7LQWK3MW6vjV2bZy6gt/WrqkY+WE74Spyc0ThAOYpMtITvnjX09CrC6ym7A/m9mebA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=12" }, - "funding": { - "url": "https://opencollective.com/eslint" + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.0", + "@esbuild/android-arm": "0.20.0", + "@esbuild/android-arm64": "0.20.0", + "@esbuild/android-x64": "0.20.0", + "@esbuild/darwin-arm64": "0.20.0", + "@esbuild/darwin-x64": "0.20.0", + "@esbuild/freebsd-arm64": "0.20.0", + "@esbuild/freebsd-x64": "0.20.0", + "@esbuild/linux-arm": "0.20.0", + "@esbuild/linux-arm64": "0.20.0", + "@esbuild/linux-ia32": "0.20.0", + "@esbuild/linux-loong64": "0.20.0", + "@esbuild/linux-mips64el": "0.20.0", + "@esbuild/linux-ppc64": "0.20.0", + "@esbuild/linux-riscv64": "0.20.0", + "@esbuild/linux-s390x": "0.20.0", + "@esbuild/linux-x64": "0.20.0", + "@esbuild/netbsd-x64": "0.20.0", + "@esbuild/openbsd-x64": "0.20.0", + "@esbuild/sunos-x64": "0.20.0", + "@esbuild/win32-arm64": "0.20.0", + "@esbuild/win32-ia32": "0.20.0", + "@esbuild/win32-x64": "0.20.0" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dependencies": { - "is-glob": "^4.0.3" + "node_modules/esbuild-wasm": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.20.0.tgz", + "integrity": "sha512-Lc9KeQCg1Zf8kCtfDXgy29rx0x8dOuhDWbkP76Wc64q7ctOOc1Zv1C39AxiE+y4N6ONyXtJk4HKpM7jlU7/jSA==", + "dev": true, + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": ">=10.13.0" + "node": ">=12" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dependencies": { - "type-fest": "^0.20.2" - }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, "engines": { - "node": ">=8" + "node": ">=0.8.0" } }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, "dependencies": { - "argparse": "^2.0.1" + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" }, "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" }, "engines": { - "node": "*" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" + "node": ">=6.0" }, - "engines": { - "node": ">=8" + "optionalDependencies": { + "source-map": "~0.6.1" } }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, "node_modules/esniff": { @@ -12466,22 +10126,6 @@ "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", "dev": true }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -12495,21 +10139,11 @@ "node": ">=4" } }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -12521,6 +10155,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, "engines": { "node": ">=4.0" } @@ -12535,6 +10170,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -12835,16 +10471,11 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -12859,17 +10490,20 @@ "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -12910,42 +10544,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "dev": true, - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -13011,6 +10614,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -13031,24 +10635,6 @@ "flat": "cli.js" } }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==" - }, "node_modules/follow-redirects": { "version": "1.15.5", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", @@ -13156,12 +10742,6 @@ "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", "dev": true }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, "node_modules/fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", @@ -13197,7 +10777,8 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true }, "node_modules/fsevents": { "version": "2.3.3", @@ -13221,27 +10802,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -13309,33 +10874,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", - "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-tsconfig": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", - "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, "node_modules/git-raw-commits": { "version": "2.0.11", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.11.tgz", @@ -13472,6 +11010,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -13526,40 +11065,6 @@ "node": ">=4" } }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -13582,12 +11087,8 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true }, "node_modules/hammerjs": { "version": "2.0.8", @@ -13652,14 +11153,6 @@ "node": ">= 0.4.0" } }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -14161,6 +11654,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, "engines": { "node": ">= 4" } @@ -14206,6 +11700,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -14221,6 +11716,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, "engines": { "node": ">=4" } @@ -14312,6 +11808,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, "engines": { "node": ">=0.8.19" } @@ -14329,6 +11826,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -14386,19 +11884,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/ip-address": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", @@ -14442,79 +11927,22 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, - "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", - "dev": true, - "peer": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "binary-extensions": "^2.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, "node_modules/is-buffer": { @@ -14537,6 +11965,7 @@ "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, "dependencies": { "hasown": "^2.0.0" }, @@ -14548,6 +11977,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -14577,23 +12007,11 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", - "dev": true, - "peer": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -14630,6 +12048,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -14682,49 +12101,15 @@ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", "dev": true }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true, - "peer": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "engines": { "node": ">=0.12.0" } }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", @@ -14734,14 +12119,6 @@ "node": ">=8" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-obj": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", @@ -14782,6 +12159,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -14793,30 +12171,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true, - "peer": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -14829,34 +12183,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-text-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", @@ -14906,41 +12232,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true, - "peer": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-what": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", @@ -14959,11 +12250,6 @@ "node": ">=8" } }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -15098,20 +12384,6 @@ "node": ">=8" } }, - "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", - "dev": true, - "peer": true, - "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" - } - }, "node_modules/jackspeak": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", @@ -15130,98 +12402,6 @@ "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/jake": { - "version": "10.8.7", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", - "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", - "dev": true, - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jake/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jake/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/jake/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jake/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jake/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/jake/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", @@ -17166,11 +14346,6 @@ "node": ">=4" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" - }, "node_modules/json-parse-even-better-errors": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", @@ -17297,11 +14472,6 @@ "node": ">=8" } }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" - }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -17357,22 +14527,6 @@ "node": "*" } }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dev": true, - "peer": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, - "engines": { - "node": ">=4.0" - } - }, "node_modules/jwt-decode": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", @@ -17396,14 +14550,6 @@ "integrity": "sha512-i/XBRTiLqRConPKioy2oq45vbv04e8x59b0mnsIRQM+7Ec/8BC7UcL5pnC4FMeGb8KwG7q4wOMw7CtNZf5tiIg==", "dev": true }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dependencies": { - "json-buffer": "3.0.1" - } - }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -17431,26 +14577,6 @@ "node": ">= 8" } }, - "node_modules/language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", - "dev": true, - "peer": true - }, - "node_modules/language-tags": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", - "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", - "dev": true, - "peer": true, - "dependencies": { - "language-subtag-registry": "^0.3.20" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/launch-editor": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", @@ -17560,18 +14686,6 @@ "node": ">=6" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/license-webpack-plugin": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", @@ -17598,15 +14712,6 @@ "immediate": "~3.0.5" } }, - "node_modules/lines-and-columns": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", - "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -17638,6 +14743,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -17822,21 +14928,8 @@ "node_modules/loglevel-plugin-prefix": { "version": "0.8.4", "resolved": "https://registry.npmjs.org/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.4.tgz", - "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==", - "dev": true - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "peer": true, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } + "integrity": "sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==", + "dev": true }, "node_modules/lowdb": { "version": "1.0.0", @@ -18062,6 +15155,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, "engines": { "node": ">= 8" } @@ -18092,1212 +15186,883 @@ }, "node_modules/method-override/node_modules/ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/mini-css-extract-plugin": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.8.0.tgz", - "integrity": "sha512-CxmUYPFcTgET1zImteG/LZOy/4T5rTojesQXkSNBiquhydn78tfbCE9sjIjnJ/UcjNjOC1bphTCCW5rrS7cXAg==", - "dev": true, - "dependencies": { - "schema-utils": "^4.0.0", - "tapable": "^2.2.1" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dev": true, - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/minimist-options/node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minipass-collect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", - "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minipass-fetch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-json-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", - "dev": true, - "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "node_modules/minipass-json-stream/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-json-stream/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=8" + "node": ">=8.6" } }, - "node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, "engines": { - "node": ">=8" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, - "dependencies": { - "yallist": "^4.0.0" + "bin": { + "mime": "cli.js" }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, "engines": { - "node": ">= 8" + "node": ">= 0.6" } }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "mime-db": "1.52.0" }, "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=6" } }, - "node_modules/moment": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true, "engines": { - "node": "*" + "node": ">=4" } }, - "node_modules/morgan": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "node_modules/mini-css-extract-plugin": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.8.0.tgz", + "integrity": "sha512-CxmUYPFcTgET1zImteG/LZOy/4T5rTojesQXkSNBiquhydn78tfbCE9sjIjnJ/UcjNjOC1bphTCCW5rrS7cXAg==", "dev": true, "dependencies": { - "basic-auth": "~2.0.1", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-finished": "~2.3.0", - "on-headers": "~1.0.2" + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" }, "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/morgan/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" } }, - "node_modules/morgan/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "dev": true }, - "node_modules/morgan/node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { - "ee-first": "1.1.1" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/mrmime": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", - "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, - "engines": { - "node": ">=10" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", "dev": true, "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" }, - "bin": { - "multicast-dns": "cli.js" + "engines": { + "node": ">= 6" } }, - "node_modules/mute-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", - "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "node_modules/minimist-options/node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", "dev": true, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=0.10.0" } }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=16 || 14 >=14.17" } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" - }, - "node_modules/needle": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", - "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "dev": true, - "optional": true, "dependencies": { - "iconv-lite": "^0.6.3", - "sax": "^1.2.4" - }, - "bin": { - "needle": "bin/needle" + "minipass": "^7.0.3" }, "engines": { - "node": ">= 4.4.x" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/needle/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", "dev": true, - "optional": true, "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" }, "engines": { - "node": ">=0.10.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" } }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">= 8" } }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/next-tick": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", - "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", - "dev": true - }, - "node_modules/ngrx-store-localstorage": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/ngrx-store-localstorage/-/ngrx-store-localstorage-17.0.0.tgz", - "integrity": "sha512-tub6zwYsU+5aG8y2pV30C9Gz7ff2nlmUDOB4O9JVxU6ZrgogDzDR/+FpY5BgPv/1KNYD0aNXCfv0iCuxDVMBEQ==", + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, "dependencies": { - "deepmerge": "^4.2.2", - "tslib": "^2.3.0" + "yallist": "^4.0.0" }, - "peerDependencies": { - "@angular/common": "^17.0.4", - "@angular/core": "^17.0.4", - "@ngrx/store": "^17.0.0" + "engines": { + "node": ">=8" } }, - "node_modules/nice-napi": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", - "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "!win32" - ], "dependencies": { - "node-addon-api": "^3.0.0", - "node-gyp-build": "^4.2.2" + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" } }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "optional": true, - "peer": true, "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", - "dev": true, - "optional": true + "node_modules/minipass-json-stream/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, - "node_modules/node-downloader-helper": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/node-downloader-helper/-/node-downloader-helper-2.1.9.tgz", - "integrity": "sha512-FSvAol2Z8UP191sZtsUZwHIN0eGoGue3uEXGdWIH5228e9KH1YHXT7fN8Oa33UGf+FbqGTQg3sJfrRGzmVCaJA==", + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", "dev": true, - "bin": { - "ndh": "bin/ndh" + "dependencies": { + "minipass": "^3.0.0" }, "engines": { - "node": ">=14.18" + "node": ">=8" } }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, "dependencies": { - "whatwg-url": "^5.0.0" + "yallist": "^4.0.0" }, "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "node": ">=8" } }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, "engines": { - "node": ">= 6.13.0" + "node": ">=8" } }, - "node_modules/node-gyp": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz", - "integrity": "sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==", + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^10.3.10", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^13.0.0", - "nopt": "^7.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^4.0.0" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" + "yallist": "^4.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/node-gyp-build": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", - "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", - "dev": true, - "optional": true, - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, - "node_modules/node-gyp/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, "engines": { - "node": ">=16" - } - }, - "node_modules/node-gyp/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" + "yallist": "^4.0.0" }, "engines": { - "node": "^16.13.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-machine-id": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/node-machine-id/-/node-machine-id-1.1.12.tgz", - "integrity": "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/nopt": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", - "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", "dev": true, - "dependencies": { - "abbrev": "^2.0.0" - }, "bin": { - "nopt": "bin/nopt.js" + "mkdirp": "dist/cjs/src/bin.js" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/normalize-package-data": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", - "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", "dev": true, - "dependencies": { - "hosted-git-info": "^7.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "*" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", "dev": true, + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "node_modules/morgan/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "engines": { - "node": ">=0.10.0" + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/npm-bundled": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", - "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "node_modules/morgan/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "dev": true, "dependencies": { - "npm-normalize-package-bin": "^3.0.0" + "ee-first": "1.1.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 0.8" } }, - "node_modules/npm-install-checks": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", - "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, "dependencies": { - "semver": "^7.1.1" + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "bin": { + "multicast-dns": "cli.js" } }, - "node_modules/npm-normalize-package-bin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", "dev": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm-package-arg": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", - "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, - "dependencies": { - "hosted-git-info": "^7.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/npm-packlist": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", - "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/needle": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", "dev": true, + "optional": true, "dependencies": { - "ignore-walk": "^6.0.4" + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 4.4.x" } }, - "node_modules/npm-pick-manifest": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz", - "integrity": "sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg==", + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "optional": true, "dependencies": { - "npm-install-checks": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0", - "npm-package-arg": "^11.0.0", - "semver": "^7.3.5" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=0.10.0" } }, - "node_modules/npm-registry-fetch": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.1.0.tgz", - "integrity": "sha512-PQCELXKt8Azvxnt5Y85GseQDJJlglTFM9L9U9gkv2y4e9s0k3GVDdOx3YoB6gm2Do0hlkzC39iCGXby+Wve1Bw==", + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "node_modules/ngrx-store-localstorage": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/ngrx-store-localstorage/-/ngrx-store-localstorage-17.0.0.tgz", + "integrity": "sha512-tub6zwYsU+5aG8y2pV30C9Gz7ff2nlmUDOB4O9JVxU6ZrgogDzDR/+FpY5BgPv/1KNYD0aNXCfv0iCuxDVMBEQ==", "dependencies": { - "make-fetch-happen": "^13.0.0", - "minipass": "^7.0.2", - "minipass-fetch": "^3.0.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^11.0.0", - "proc-log": "^3.0.0" + "deepmerge": "^4.2.2", + "tslib": "^2.3.0" }, - "engines": { - "node": "^16.14.0 || >=18.0.0" + "peerDependencies": { + "@angular/common": "^17.0.4", + "@angular/core": "^17.0.4", + "@ngrx/store": "^17.0.0" } }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "!win32" + ], "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" } }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" + "lower-case": "^2.0.2", + "tslib": "^2.0.3" } }, - "node_modules/nwsapi": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", - "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", - "dev": true + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true }, - "node_modules/nx": { - "version": "17.2.8", - "resolved": "https://registry.npmjs.org/nx/-/nx-17.2.8.tgz", - "integrity": "sha512-rM5zXbuXLEuqQqcjVjClyvHwRJwt+NVImR2A6KFNG40Z60HP6X12wAxxeLHF5kXXTDRU0PFhf/yACibrpbPrAw==", + "node_modules/node-downloader-helper": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/node-downloader-helper/-/node-downloader-helper-2.1.9.tgz", + "integrity": "sha512-FSvAol2Z8UP191sZtsUZwHIN0eGoGue3uEXGdWIH5228e9KH1YHXT7fN8Oa33UGf+FbqGTQg3sJfrRGzmVCaJA==", "dev": true, - "hasInstallScript": true, - "dependencies": { - "@nrwl/tao": "17.2.8", - "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "3.0.0-rc.46", - "@zkochan/js-yaml": "0.0.6", - "axios": "^1.5.1", - "chalk": "^4.1.0", - "cli-cursor": "3.1.0", - "cli-spinners": "2.6.1", - "cliui": "^8.0.1", - "dotenv": "~16.3.1", - "dotenv-expand": "~10.0.0", - "enquirer": "~2.3.6", - "figures": "3.2.0", - "flat": "^5.0.2", - "fs-extra": "^11.1.0", - "glob": "7.1.4", - "ignore": "^5.0.4", - "jest-diff": "^29.4.1", - "js-yaml": "4.1.0", - "jsonc-parser": "3.2.0", - "lines-and-columns": "~2.0.3", - "minimatch": "3.0.5", - "node-machine-id": "1.1.12", - "npm-run-path": "^4.0.1", - "open": "^8.4.0", - "semver": "7.5.3", - "string-width": "^4.2.3", - "strong-log-transformer": "^2.1.0", - "tar-stream": "~2.2.0", - "tmp": "~0.2.1", - "tsconfig-paths": "^4.1.2", - "tslib": "^2.3.0", - "yargs": "^17.6.2", - "yargs-parser": "21.1.1" - }, "bin": { - "nx": "bin/nx.js", - "nx-cloud": "bin/nx-cloud.js" + "ndh": "bin/ndh" }, - "optionalDependencies": { - "@nx/nx-darwin-arm64": "17.2.8", - "@nx/nx-darwin-x64": "17.2.8", - "@nx/nx-freebsd-x64": "17.2.8", - "@nx/nx-linux-arm-gnueabihf": "17.2.8", - "@nx/nx-linux-arm64-gnu": "17.2.8", - "@nx/nx-linux-arm64-musl": "17.2.8", - "@nx/nx-linux-x64-gnu": "17.2.8", - "@nx/nx-linux-x64-musl": "17.2.8", - "@nx/nx-win32-arm64-msvc": "17.2.8", - "@nx/nx-win32-x64-msvc": "17.2.8" + "engines": { + "node": ">=14.18" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" }, "peerDependencies": { - "@swc-node/register": "^1.6.7", - "@swc/core": "^1.3.85" + "encoding": "^0.1.0" }, "peerDependenciesMeta": { - "@swc-node/register": { - "optional": true - }, - "@swc/core": { + "encoding": { "optional": true } } }, - "node_modules/nx/node_modules/@nx/nx-darwin-arm64": { - "version": "17.2.8", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-17.2.8.tgz", - "integrity": "sha512-dMb0uxug4hM7tusISAU1TfkDK3ixYmzc1zhHSZwpR7yKJIyKLtUpBTbryt8nyso37AS1yH+dmfh2Fj2WxfBHTg==", - "cpu": [ - "arm64" - ], + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">= 10" + "node": ">= 6.13.0" } }, - "node_modules/nx/node_modules/@nx/nx-darwin-x64": { - "version": "17.2.8", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-17.2.8.tgz", - "integrity": "sha512-0cXzp1tGr7/6lJel102QiLA4NkaLCkQJj6VzwbwuvmuCDxPbpmbz7HC1tUteijKBtOcdXit1/MEoEU007To8Bw==", - "cpu": [ - "x64" - ], + "node_modules/node-gyp": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz", + "integrity": "sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==", "dev": true, - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, "engines": { - "node": ">= 10" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/@nx/nx-linux-x64-gnu": { - "version": "17.2.8", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-17.2.8.tgz", - "integrity": "sha512-sjG1bwGsjLxToasZ3lShildFsF0eyeGu+pOQZIp9+gjFbeIkd19cTlCnHrOV9hoF364GuKSXQyUlwtFYFR4VTQ==", - "cpu": [ - "x64" - ], + "node_modules/node-gyp-build": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", + "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", "dev": true, "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" } }, - "node_modules/nx/node_modules/@nx/nx-win32-x64-msvc": { - "version": "17.2.8", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-17.2.8.tgz", - "integrity": "sha512-HTqDv+JThlLzbcEm/3f+LbS5/wYQWzb5YDXbP1wi7nlCTihNZOLNqGOkEmwlrR5tAdNHPRpHSmkYg4305W0CtA==", - "cpu": [ - "x64" - ], + "node_modules/node-gyp/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">= 10" + "node": ">=16" } }, - "node_modules/nx/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/node-gyp/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "isexe": "^3.1.1" }, - "engines": { - "node": ">=8" + "bin": { + "node-which": "bin/which.js" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "engines": { + "node": "^16.13.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", "dev": true }, - "node_modules/nx/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/nopt": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", + "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/normalize-package-data": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/dotenv": { - "version": "16.3.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.2.tgz", - "integrity": "sha512-HTlk5nmhkm8F6JcdXvHIzaorzCoziNQT9mGxLPVXW8wJF1TiGSL60ZGB4gHWabHOaMmWmhvk2/lPHfnBiT78AQ==", + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" + "node": ">=0.10.0" } }, - "node_modules/nx/node_modules/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/nx/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/npm-bundled": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, "engines": { - "node": ">=8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", "dev": true, "dependencies": { - "argparse": "^2.0.1" + "semver": "^7.1.1" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, - "node_modules/nx/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/npm-package-arg": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", + "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "hosted-git-info": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" }, "engines": { - "node": ">=10" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", + "node_modules/npm-packlist": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", + "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "ignore-walk": "^6.0.4" }, "engines": { - "node": "*" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "node_modules/npm-pick-manifest": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz", + "integrity": "sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" }, "engines": { - "node": ">=10" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "node_modules/npm-registry-fetch": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.1.0.tgz", + "integrity": "sha512-PQCELXKt8Azvxnt5Y85GseQDJJlglTFM9L9U9gkv2y4e9s0k3GVDdOx3YoB6gm2Do0hlkzC39iCGXby+Wve1Bw==", "dev": true, + "dependencies": { + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^3.0.0" + }, "engines": { - "node": ">=4" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "path-key": "^3.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/nx/node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" + "boolbase": "^1.0.0" }, - "engines": { - "node": ">=6" + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/nx/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/nwsapi": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", + "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", "dev": true }, - "node_modules/nx/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -19311,6 +16076,7 @@ "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -19335,98 +16101,9 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", - "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", - "dev": true, - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.2.tgz", - "integrity": "sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw==", - "dependencies": { - "array.prototype.filter": "^1.0.3", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.0.0" - } - }, - "node_modules/object.hasown": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", - "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", "dev": true, - "peer": true, - "dependencies": { - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/obuf": { @@ -19460,6 +16137,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, "dependencies": { "wrappy": "1" } @@ -19510,22 +16188,6 @@ "resolved": "https://registry.npmjs.org/option-parser/-/option-parser-1.0.2.tgz", "integrity": "sha512-Q56FmRi6TZX+S9jAl9f0Tnrk7W8faAZULf6Y0IgJR6Cy7/MxhzvBFoyL1Sz2DD7WbOY2Fxtkz2S/3kzlbn/VsQ==" }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/ora": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", @@ -19630,6 +16292,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -19644,6 +16307,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -19754,6 +16418,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, "dependencies": { "callsites": "^3.0.0" }, @@ -19882,6 +16547,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, "engines": { "node": ">=8" } @@ -19890,6 +16556,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -19898,6 +16565,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "engines": { "node": ">=8" } @@ -19905,7 +16573,8 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true }, "node_modules/path-scurry": { "version": "1.10.1", @@ -20252,41 +16921,6 @@ "integrity": "sha512-O3kKP+1YdgqHOFsZF2a9JVdtqD+RPzCQc3rP+Ualf7V6rmRDchZ9MJbiGTT7LuyqFKZqlHSOyO/oMFmI2lVTsw==", "hasInstallScript": true }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -20394,25 +17028,6 @@ "node": ">= 6" } }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "peer": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true, - "peer": true - }, "node_modules/propagating-hammerjs": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/propagating-hammerjs/-/propagating-hammerjs-1.5.0.tgz", @@ -20506,6 +17121,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, "funding": [ { "type": "github", @@ -20840,28 +17456,6 @@ "integrity": "sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==", "dev": true }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.5.tgz", - "integrity": "sha512-62wgfC8dJWrmxv44CA36pLDnP6KKl3Vhxb7PL+8+qrrFMMoJij4vgiMP8zV4O8+CBMXY1mHxI5fITGHXFHVmQQ==", - "dev": true, - "peer": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.0.0", - "get-intrinsic": "^1.2.3", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -20901,20 +17495,11 @@ "integrity": "sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg==", "dev": true }, - "node_modules/regexp-tree": { - "version": "0.1.27", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", - "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", - "dev": true, - "peer": true, - "bin": { - "regexp-tree": "bin/regexp-tree" - } - }, "node_modules/regexp.prototype.flags": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, "dependencies": { "call-bind": "^1.0.6", "define-properties": "^1.2.1", @@ -21118,6 +17703,7 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -21181,14 +17767,6 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, "node_modules/resolve-url-loader": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", @@ -21263,6 +17841,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -21272,6 +17851,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -21286,6 +17866,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -21295,6 +17876,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -21314,6 +17896,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -21366,6 +17949,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, "funding": [ { "type": "github", @@ -21387,26 +17971,9 @@ "node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", - "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "tslib": "^2.1.0" } }, "node_modules/safe-buffer": { @@ -21415,32 +17982,6 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "node_modules/safe-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz", - "integrity": "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==", - "dev": true, - "peer": true, - "dependencies": { - "regexp-tree": "~0.1.1" - } - }, - "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -21787,6 +18328,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -21825,6 +18367,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -21836,6 +18379,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "engines": { "node": ">=8" } @@ -21853,6 +18397,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "dev": true, "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -22475,73 +19020,11 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/string.prototype.matchall": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", - "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", - "dev": true, - "peer": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "regexp.prototype.flags": "^1.5.0", - "set-function-name": "^2.0.0", - "side-channel": "^1.0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -22596,6 +19079,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, "engines": { "node": ">=8" }, @@ -22603,23 +19087,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strong-log-transformer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", - "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", - "dev": true, - "dependencies": { - "duplexer": "^0.1.1", - "minimist": "^1.2.0", - "through": "^2.3.4" - }, - "bin": { - "sl-log-transformer": "bin/sl-log-transformer.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -22636,6 +19103,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -22664,22 +19132,6 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "node_modules/synckit": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", - "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", - "dev": true, - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, "node_modules/tablesort": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/tablesort/-/tablesort-5.3.0.tgz", @@ -22690,6 +19142,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, "engines": { "node": ">=6" } @@ -22711,22 +19164,6 @@ "node": ">=10" } }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/tar/node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -22991,11 +19428,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" - }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -23023,18 +19455,6 @@ "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", "dev": true }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -23054,6 +19474,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -23135,18 +19556,6 @@ "node": ">=8" } }, - "node_modules/ts-api-utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", - "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, "node_modules/ts-jest": { "version": "29.1.2", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.2.tgz", @@ -23331,80 +19740,11 @@ "node": ">=8" } }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "engines": { - "node": ">=4" - } - }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils-etc": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/tsutils-etc/-/tsutils-etc-1.4.2.tgz", - "integrity": "sha512-2Dn5SxTDOu6YWDNKcx1xu2YUy6PUeKrWZB/x2cQ8vY2+iz3JRembKn/iZ0JLT1ZudGNwQQvtFX9AwvRHbXuPUg==", - "dev": true, - "dependencies": { - "@types/yargs": "^17.0.0", - "yargs": "^17.0.0" - }, - "bin": { - "ts-flags": "bin/ts-flags", - "ts-kind": "bin/ts-kind" - }, - "peerDependencies": { - "tsutils": "^3.0.0", - "typescript": ">=4.0.0" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/tuf-js": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.0.tgz", @@ -23425,17 +19765,6 @@ "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", "dev": true }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -23458,75 +19787,6 @@ "node": ">= 0.6" } }, - "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.5.tgz", - "integrity": "sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/typed-assert": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", @@ -23565,20 +19825,6 @@ "node": ">=0.8.0" } }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/undici": { "version": "6.6.2", "resolved": "https://registry.npmjs.org/undici/-/undici-6.6.2.tgz", @@ -24781,64 +21027,6 @@ "node": ">= 8" } }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", - "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", - "dev": true, - "peer": true, - "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", - "is-async-function": "^2.0.0", - "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", - "is-generator-function": "^1.0.10", - "is-regex": "^1.1.4", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, - "peer": true, - "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/which-typed-array": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz", @@ -25005,7 +21193,8 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true }, "node_modules/write-file-atomic": { "version": "4.0.2", @@ -25144,6 +21333,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index 3ba5236ca5..25ba561a0f 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,8 @@ "watch": "ng build --watch", "sonar-scanner": "npm run test:ci && sonar-scanner", "security-checks": "git secrets --scan", - "lint": "eslint --ext .ts .", - "lint:fix": "eslint --ext .ts . --fix", - "format": "npx prettier '!src/app/api/**/*.{js,ts}' 'src/**/*.{js,jsx,ts,tsx,html,css,scss}' --write", + "lint": "biome check src", + "lint:fix": "npm run lint -- --write", "docs:json": "compodoc -p ./tsconfig.json -e json -d .", "test": "jest --colors --maxWorkers=50% --coverage", "test:workflow": "jest --maxWorkers=50%", @@ -54,7 +53,6 @@ "accessible-autocomplete": "^2.0.4", "angular-google-tag-manager": "^1.9.0", "deep-object-diff": "^1.1.9", - "eslint-import-resolver-typescript": "^3.6.1", "govuk-frontend": "^4.7.0", "jwt-decode": "^4.0.0", "lodash": "^4.17.21", @@ -69,18 +67,14 @@ }, "devDependencies": { "@angular-devkit/build-angular": "^17.2.0", - "@angular-eslint/builder": "^17.2.1", - "@angular-eslint/eslint-plugin": "^17.2.1", - "@angular-eslint/eslint-plugin-template": "^17.2.1", - "@angular-eslint/schematics": "^17.2.1", - "@angular-eslint/template-parser": "^17.2.1", "@angular/cli": "^17.2.0", "@angular/compiler-cli": "^17.2.1", "@babel/core": "^7.23.9", + "@biomejs/biome": "1.8.3", "@commitlint/cli": "^18.6.1", "@commitlint/config-conventional": "^18.6.2", "@compodoc/compodoc": "^1.1.23", - "@dvsa/eslint-config-ts": "^3.0.1", + "@dvsa/biome-config": "^0.1.0", "@ngrx/schematics": "^17.1.0", "@types/jest": "^29.5.12", "@types/json-server": "^0.14.7", @@ -88,22 +82,14 @@ "@types/lodash.merge": "^4.6.9", "@types/node": "^18.18.0", "@types/uuid": "^9.0.8", - "@typescript-eslint/eslint-plugin": "^6.0.0", - "@typescript-eslint/parser": "^6.0.0", "babel-loader": "^9.1.3", "commitlint-plugin-function-rules": "^3.1.0", "dotenv": "^16.4.5", - "eslint": "^8.56.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-ngrx": "^2.1.4", - "eslint-plugin-prettier": "^5.1.3", "husky": "^9.0.11", "jest": "^29.7.0", "jest-preset-angular": "^14.0.3", "jest-sonar-reporter": "^2.0.0", "json-server": "^0.17.3", - "prettier": "^3.2.5", "sonarqube-scanner": "^3.3.0", "ts-jest": "^29.1.2", "ts-node": "^10.9.2", diff --git a/src/app/accessible-autocomplete.d.ts b/src/app/accessible-autocomplete.d.ts index d0950ffeaf..8975a41770 100644 --- a/src/app/accessible-autocomplete.d.ts +++ b/src/app/accessible-autocomplete.d.ts @@ -1,25 +1,25 @@ declare module 'accessible-autocomplete/dist/accessible-autocomplete.min' { - interface ElementParam { - element: HTMLElement; - } - interface EnhancedElementParam { - selectElement: HTMLElement | null; - } - interface DefaultParams { - id?: string; - source?: Array; - onConfirm?: (value: string) => void; - confirmOnBlur?: boolean; - required?: true; - defaultValue?: string; - autoselect?: boolean; - showAllValues?: boolean; - dropdownArrow?: Function; - } + interface ElementParam { + element: HTMLElement; + } + interface EnhancedElementParam { + selectElement: HTMLElement | null; + } + interface DefaultParams { + id?: string; + source?: Array; + onConfirm?: (value: string) => void; + confirmOnBlur?: boolean; + required?: true; + defaultValue?: string; + autoselect?: boolean; + showAllValues?: boolean; + dropdownArrow?: Function; + } - export interface AutocompleteParams extends DefaultParams, ElementParam {} - export interface AutocompleteEnhanceParams extends DefaultParams, EnhancedElementParam {} + export interface AutocompleteParams extends DefaultParams, ElementParam {} + export interface AutocompleteEnhanceParams extends DefaultParams, EnhancedElementParam {} - export default function accesibleAutocomplete(params: AutocompleteParams): void; - export function enhanceSelectElement(params: AutocompleteEnhanceParams): void; + export default function accesibleAutocomplete(params: AutocompleteParams): void; + export function enhanceSelectElement(params: AutocompleteEnhanceParams): void; } diff --git a/src/app/api/document-retrieval/api/document-retrieval.service.ts b/src/app/api/document-retrieval/api/document-retrieval.service.ts index de1b06b570..5d1ef449ea 100644 --- a/src/app/api/document-retrieval/api/document-retrieval.service.ts +++ b/src/app/api/document-retrieval/api/document-retrieval.service.ts @@ -7,176 +7,206 @@ import { DOCUMENT_RETRIEVAL_BASE_PATH } from '../variables'; @Injectable() export class DocumentRetrievalService { - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor( - protected httpClient: HttpClient, - @Optional() @Inject(DOCUMENT_RETRIEVAL_BASE_PATH) basePath: string, - @Optional() configuration: Configuration - ) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * Submitting a new test records - * - * @param body Post the test results - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public testCertificateGet(testNumber?: string, vin?: string, observe?: 'body', reportProgress?: boolean): Observable; - public testCertificateGet(testNumber?: string, vin?: string, observe?: 'response', reportProgress?: boolean): Observable>; - public testCertificateGet(testNumber?: string, vin?: string, observe?: 'events', reportProgress?: boolean): Observable>; - public testCertificateGet(testNumber?: string, vin?: string, observe: any = 'body', reportProgress = false): Observable { - if (!vin) { - throw new Error('Required parameter vin was null or undefined when calling testCertificateGet.'); - } - if (!testNumber) { - throw new Error('Required parameter testNumber was null or undefined when calling testCertificateGet.'); - } - - // Set query parameters - let params = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); - if (testNumber) { - params = params.set('testNumber', testNumber); - } - if (vin) { - params = params.set('vinNumber', vin); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); - } - - // api keys - if (this.configuration.apiKeys) { - for (const key in this.configuration.apiKeys) { - headers = headers.set(key, this.configuration.apiKeys[key]); - } - } - - // to determine the Accept header - let httpHeaderAccepts: string[] = []; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = ['application/pdf; charset=utf-8']; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.get(`${this.basePath}/v1/document-retrieval`, { - headers, - params, - reportProgress, - observe, - responseType: 'text', - withCredentials: this.configuration.withCredentials - }); - } - - public testPlateGet(serialNumber?: string, observe?: 'body', reportProgress?: boolean): Observable; - public testPlateGet(serialNumber?: string, observe?: 'response', reportProgress?: boolean): Observable>; - public testPlateGet(serialNumber?: string, observe?: 'events', reportProgress?: boolean): Observable>; - public testPlateGet(serialNumber?: string, observe: any = 'body', reportProgress = false): Observable { - if (!serialNumber) { - throw new Error('Required parameter serialNumber was null or undefined when calling testCertificateGet.'); - } - - // Set query parameters - let params = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); - if (serialNumber) { - params = params.set('plateSerialNumber', serialNumber); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); - } - - // api keys - if (this.configuration.apiKeys) { - for (const key in this.configuration.apiKeys) { - headers = headers.set(key, this.configuration.apiKeys[key]); - } - } - - // to determine the Accept header - let httpHeaderAccepts: string[] = []; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = ['application/pdf; charset=utf-8']; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.get(`${this.basePath}/v1/document-retrieval`, { - headers, - params, - reportProgress, - observe, - responseType: 'text', - withCredentials: this.configuration.withCredentials - }); - } - - getDocument(paramMap: Map): Observable> { - let headers = this.defaultHeaders; - - if (this.configuration.accessToken) { - const accessToken = typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); - } - - if (this.configuration.apiKeys) { - for (const key in this.configuration.apiKeys) { - headers = headers.set(key, this.configuration.apiKeys[key]); - } - } - - const httpContentTypeSelected = this.configuration.selectHeaderContentType(['application/pdf; charset=utf-8']); - if (httpContentTypeSelected) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - let params = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); - - paramMap.forEach((value, key) => params = params.set(key, value)); - - return this.httpClient.get( - `${this.basePath}/v1/document-retrieval`, - { - headers, - observe: 'events', - params, - reportProgress: true, - responseType: 'text', - withCredentials: this.configuration.withCredentials - } - ); - } + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor( + protected httpClient: HttpClient, + @Optional() @Inject(DOCUMENT_RETRIEVAL_BASE_PATH) basePath: string, + @Optional() configuration: Configuration + ) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * Submitting a new test records + * + * @param body Post the test results + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public testCertificateGet( + testNumber?: string, + vin?: string, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public testCertificateGet( + testNumber?: string, + vin?: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public testCertificateGet( + testNumber?: string, + vin?: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public testCertificateGet( + testNumber?: string, + vin?: string, + observe: any = 'body', + reportProgress = false + ): Observable { + if (!vin) { + throw new Error('Required parameter vin was null or undefined when calling testCertificateGet.'); + } + if (!testNumber) { + throw new Error('Required parameter testNumber was null or undefined when calling testCertificateGet.'); + } + + // Set query parameters + let params = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); + if (testNumber) { + params = params.set('testNumber', testNumber); + } + if (vin) { + params = params.set('vinNumber', vin); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // api keys + if (this.configuration.apiKeys) { + for (const key in this.configuration.apiKeys) { + headers = headers.set(key, this.configuration.apiKeys[key]); + } + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = []; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = ['application/pdf; charset=utf-8']; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.get(`${this.basePath}/v1/document-retrieval`, { + headers, + params, + reportProgress, + observe, + responseType: 'text', + withCredentials: this.configuration.withCredentials, + }); + } + + public testPlateGet(serialNumber?: string, observe?: 'body', reportProgress?: boolean): Observable; + public testPlateGet( + serialNumber?: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public testPlateGet(serialNumber?: string, observe?: 'events', reportProgress?: boolean): Observable>; + public testPlateGet(serialNumber?: string, observe: any = 'body', reportProgress = false): Observable { + if (!serialNumber) { + throw new Error('Required parameter serialNumber was null or undefined when calling testCertificateGet.'); + } + + // Set query parameters + let params = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); + if (serialNumber) { + params = params.set('plateSerialNumber', serialNumber); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // api keys + if (this.configuration.apiKeys) { + for (const key in this.configuration.apiKeys) { + headers = headers.set(key, this.configuration.apiKeys[key]); + } + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = []; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = ['application/pdf; charset=utf-8']; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.get(`${this.basePath}/v1/document-retrieval`, { + headers, + params, + reportProgress, + observe, + responseType: 'text', + withCredentials: this.configuration.withCredentials, + }); + } + + getDocument(paramMap: Map): Observable> { + let headers = this.defaultHeaders; + + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + if (this.configuration.apiKeys) { + for (const key in this.configuration.apiKeys) { + headers = headers.set(key, this.configuration.apiKeys[key]); + } + } + + const httpContentTypeSelected = this.configuration.selectHeaderContentType(['application/pdf; charset=utf-8']); + if (httpContentTypeSelected) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + let params = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); + + paramMap.forEach((value, key) => (params = params.set(key, value))); + + return this.httpClient.get(`${this.basePath}/v1/document-retrieval`, { + headers, + observe: 'events', + params, + reportProgress: true, + responseType: 'text', + withCredentials: this.configuration.withCredentials, + }); + } } diff --git a/src/app/api/document-retrieval/configuration.ts b/src/app/api/document-retrieval/configuration.ts index 82e8458f39..698dce114c 100644 --- a/src/app/api/document-retrieval/configuration.ts +++ b/src/app/api/document-retrieval/configuration.ts @@ -1,79 +1,82 @@ export interface ConfigurationParameters { - apiKeys?: {[ key: string ]: string}; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: { [key: string]: string }; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; } export class Configuration { - apiKeys?: {[ key: string ]: string}; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: { [key: string]: string }; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; - constructor(configurationParameters: ConfigurationParameters = {}) { - this.apiKeys = configurationParameters.apiKeys; - this.username = configurationParameters.username; - this.password = configurationParameters.password; - this.accessToken = configurationParameters.accessToken; - this.basePath = configurationParameters.basePath; - this.withCredentials = configurationParameters.withCredentials; - } + constructor(configurationParameters: ConfigurationParameters = {}) { + this.apiKeys = configurationParameters.apiKeys; + this.username = configurationParameters.username; + this.password = configurationParameters.password; + this.accessToken = configurationParameters.accessToken; + this.basePath = configurationParameters.basePath; + this.withCredentials = configurationParameters.withCredentials; + } - /** - * Select the correct content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param contentTypes - the array of content types that are available for selection - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderContentType (contentTypes: string[]): string | undefined { - if (contentTypes.length == 0) { - return undefined; - } + /** + * Select the correct content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param contentTypes - the array of content types that are available for selection + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderContentType(contentTypes: string[]): string | undefined { + if (contentTypes.length == 0) { + return undefined; + } - let type = contentTypes.find(x => this.isJsonMime(x)); - if (type === undefined) { - return contentTypes[0]; - } - return type; - } + const type = contentTypes.find((x) => this.isJsonMime(x)); + if (type === undefined) { + return contentTypes[0]; + } + return type; + } - /** - * Select the correct accept content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param accepts - the array of content types that are available for selection. - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderAccept(accepts: string[]): string | undefined { - if (accepts.length == 0) { - return undefined; - } + /** + * Select the correct accept content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param accepts - the array of content types that are available for selection. + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderAccept(accepts: string[]): string | undefined { + if (accepts.length == 0) { + return undefined; + } - let type = accepts.find(x => this.isJsonMime(x)); - if (type === undefined) { - return accepts[0]; - } - return type; - } + const type = accepts.find((x) => this.isJsonMime(x)); + if (type === undefined) { + return accepts[0]; + } + return type; + } - /** - * Check if the given MIME is a JSON MIME. - * JSON MIME examples: - * application/json - * application/json; charset=UTF8 - * APPLICATION/JSON - * application/vnd.company+json - * @param mime - MIME (Multipurpose Internet Mail Extensions) - * @return True if the given MIME is JSON, false otherwise. - */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); - return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = /^(application\\/jnos | [^;\/ \t]+\; + \/[^ + \/ \t]+[+]json)[ \t]*( + .*)?$/i + return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } } diff --git a/src/app/api/document-retrieval/document-retrieval-api.module.ts b/src/app/api/document-retrieval/document-retrieval-api.module.ts index 2056d2cd63..1d5ab72f50 100644 --- a/src/app/api/document-retrieval/document-retrieval-api.module.ts +++ b/src/app/api/document-retrieval/document-retrieval-api.module.ts @@ -1,28 +1,31 @@ -import { NgModule, ModuleWithProviders, SkipSelf, Optional } from '@angular/core'; -import { Configuration } from './configuration'; import { HttpClient } from '@angular/common/http'; +import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; import { DocumentRetrievalService } from './api/document-retrieval.service'; +import { Configuration } from './configuration'; @NgModule({ - imports: [], - declarations: [], - exports: [], - providers: [DocumentRetrievalService] + imports: [], + declarations: [], + exports: [], + providers: [DocumentRetrievalService], }) export class DocumentRetrievalApiModule { - public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { - return { - ngModule: DocumentRetrievalApiModule, - providers: [{ provide: Configuration, useFactory: configurationFactory }] - }; - } + public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { + return { + ngModule: DocumentRetrievalApiModule, + providers: [{ provide: Configuration, useFactory: configurationFactory }], + }; + } - constructor(@Optional() @SkipSelf() parentModule: DocumentRetrievalApiModule, @Optional() http: HttpClient) { - if (parentModule) { - throw new Error('DocumentRetrievalApiModule is already loaded. Import in your base AppModule only.'); - } - if (!http) { - throw new Error('You need to import the HttpClientModule in your AppModule! \n' + 'See also https://github.com/angular/angular/issues/20575'); - } - } + constructor(@Optional() @SkipSelf() parentModule: DocumentRetrievalApiModule, @Optional() http: HttpClient) { + if (parentModule) { + throw new Error('DocumentRetrievalApiModule is already loaded. Import in your base AppModule only.'); + } + if (!http) { + throw new Error( + 'You need to import the HttpClientModule in your AppModule! \n' + + 'See also https://github.com/angular/angular/issues/20575' + ); + } + } } diff --git a/src/app/api/document-retrieval/encoder.ts b/src/app/api/document-retrieval/encoder.ts index 5d0fb0e90c..233fb78e4a 100644 --- a/src/app/api/document-retrieval/encoder.ts +++ b/src/app/api/document-retrieval/encoder.ts @@ -6,12 +6,12 @@ import { HttpUrlEncodingCodec } from '@angular/common/http'; * See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 */ export class CustomHttpUrlEncodingCodec extends HttpUrlEncodingCodec { - override encodeKey(k: string): string { - k = super.encodeKey(k); - return k.replace(/\+/gi, '%2B'); - } - override encodeValue(v: string): string { - v = super.encodeValue(v); - return v.replace(/\+/gi, '%2B'); - } + override encodeKey(k: string): string { + k = super.encodeKey(k); + return k.replace(/\+/gi, '%2B'); + } + override encodeValue(v: string): string { + v = super.encodeValue(v); + return v.replace(/\+/gi, '%2B'); + } } diff --git a/src/app/api/reference-data/api.module.ts b/src/app/api/reference-data/api.module.ts index c368284e6e..aec62543e7 100644 --- a/src/app/api/reference-data/api.module.ts +++ b/src/app/api/reference-data/api.module.ts @@ -1,33 +1,32 @@ -import { NgModule, ModuleWithProviders, SkipSelf, Optional } from '@angular/core'; -import { Configuration } from './configuration'; import { HttpClient } from '@angular/common/http'; - +import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; +import { Configuration } from './configuration'; import { ReferenceDataService } from './api/referenceData.service'; @NgModule({ - imports: [], - declarations: [], - exports: [], - providers: [ - ReferenceDataService ] + imports: [], + declarations: [], + exports: [], + providers: [ReferenceDataService], }) export class ApiModule { - public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { - return { - ngModule: ApiModule, - providers: [ { provide: Configuration, useFactory: configurationFactory } ] - }; - } + public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { + return { + ngModule: ApiModule, + providers: [{ provide: Configuration, useFactory: configurationFactory }], + }; + } - constructor( @Optional() @SkipSelf() parentModule: ApiModule, - @Optional() http: HttpClient) { - if (parentModule) { - throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); - } - if (!http) { - throw new Error('You need to import the HttpClientModule in your AppModule! \n' + - 'See also https://github.com/angular/angular/issues/20575'); - } - } + constructor(@Optional() @SkipSelf() parentModule: ApiModule, @Optional() http: HttpClient) { + if (parentModule) { + throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); + } + if (!http) { + throw new Error( + 'You need to import the HttpClientModule in your AppModule! \n' + + 'See also https://github.com/angular/angular/issues/20575' + ); + } + } } diff --git a/src/app/api/reference-data/api/referenceData.service.ts b/src/app/api/reference-data/api/referenceData.service.ts index 573cd35d30..92a638ec0e 100644 --- a/src/app/api/reference-data/api/referenceData.service.ts +++ b/src/app/api/reference-data/api/referenceData.service.ts @@ -7,549 +7,559 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - *//* tslint:disable:no-unused-variable member-ordering */ + */ /* tslint:disable:no-unused-variable member-ordering */ +import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpHeaders, HttpParams, HttpResponse, HttpEvent } from '@angular/common/http'; import { CustomHttpUrlEncodingCodec } from '../encoder'; import { Observable } from 'rxjs'; -import { DeleteItem } from '../model/deleteItem';import { ReferenceDataApiResponse } from '../model/referenceDataApiResponse'; +import { DeleteItem } from '../model/deleteItem'; +import { ReferenceDataApiResponse } from '../model/referenceDataApiResponse'; import { ReferenceDataItem } from '../model/referenceDataItem'; import { ReferenceDataItemApiResponse } from '../model/referenceDataItemApiResponse'; import { ResourceKey } from '../model/resourceKey'; -import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; import { Configuration } from '../configuration'; - +import { BASE_PATH } from '../variables'; @Injectable() export class ReferenceDataService { - - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - - /** - * Lookup any resourceType with its key, allows partials. - * - * @param resourceType - * @param resourceKey - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public referenceLookupResourceTypeResourceKeyGet( - resourceType: string, - resourceKey: ResourceKey, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public referenceLookupResourceTypeResourceKeyGet( - resourceType: string, - resourceKey: ResourceKey, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public referenceLookupResourceTypeResourceKeyGet( - resourceType: string, - resourceKey: ResourceKey, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public referenceLookupResourceTypeResourceKeyGet( - resourceType: string, - resourceKey: ResourceKey, - observe: any = 'body', - reportProgress: boolean = false - ): Observable { - if (resourceType === null || resourceType === undefined) { - throw new Error('Required parameter resourceType was null or undefined when calling referenceLookupResourceTypeResourceKeyGet.'); - } - - if (resourceKey === null || resourceKey === undefined) { - throw new Error('Required parameter resourceKey was null or undefined when calling referenceLookupResourceTypeResourceKeyGet.'); - } - - let headers = this.defaultHeaders; - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/json' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - ]; - - return this.httpClient.request('get',`${this.basePath}/reference/lookup/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, - { - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - - /** - * Search the tyres by plyRating, singleIndex and doubleIndex, allows partials. - * - * @param searchKey - * @param param - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public referenceLookupTyresSearchKeyParamGet( - searchKey: string, - param: string, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public referenceLookupTyresSearchKeyParamGet( - searchKey: string, - param: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public referenceLookupTyresSearchKeyParamGet( - searchKey: string, - param: string, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public referenceLookupTyresSearchKeyParamGet( - searchKey: string, - param: string, - observe: any = 'body', - reportProgress: boolean = false - ): Observable { - if (searchKey === null || searchKey === undefined) { - throw new Error('Required parameter searchKey was null or undefined when calling referenceLookupTyresSearchKeyParamGet.'); - } - - if (param === null || param === undefined) { - throw new Error('Required parameter param was null or undefined when calling referenceLookupTyresSearchKeyParamGet.'); - } - - let headers = this.defaultHeaders; - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/json' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - ]; - - return this.httpClient.request('get',`${this.basePath}/reference/lookup/tyres/${encodeURIComponent(String(searchKey))}/${encodeURIComponent(String(param))}`, - { - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - - /** - * Get reference data for a particular resourceType. - * - * @param resourceType - * @param paginationToken - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public referenceResourceTypeGet( - resourceType: string, - paginationToken?: string, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public referenceResourceTypeGet( - resourceType: string, - paginationToken?: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeGet( - resourceType: string, - paginationToken?: string, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeGet( - resourceType: string, - paginationToken?: string, - observe: any = 'body', - reportProgress: boolean = false - ): Observable { - - if (resourceType === null || resourceType === undefined) { - throw new Error('Required parameter resourceType was null or undefined when calling referenceResourceTypeGet.'); - } - - let queryParameters = new HttpParams({encoder: new CustomHttpUrlEncodingCodec()}); - if (paginationToken !== undefined && paginationToken !== null) { - queryParameters = queryParameters.set('paginationToken', paginationToken); - } - - let headers = this.defaultHeaders; - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/json' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - ]; - - return this.httpClient.request('get',`${this.basePath}/reference/${encodeURIComponent(String(resourceType))}`, - { - params: queryParameters, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - - /** - * Delete reference data for a particular resourceType and resourceKey. - * - * @param resourceType - * @param resourceKey - * @param body - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public referenceResourceTypeResourceKeyDelete( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public referenceResourceTypeResourceKeyDelete( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeResourceKeyDelete( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeResourceKeyDelete( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe: any = 'body', - reportProgress: boolean = false - ): Observable { - - if (resourceType === null || resourceType === undefined) { - throw new Error('Required parameter resourceType was null or undefined when calling referenceResourceTypeResourceKeyDelete.'); - } - - if (resourceKey === null || resourceKey === undefined) { - throw new Error('Required parameter resourceKey was null or undefined when calling referenceResourceTypeResourceKeyDelete.'); - } - - let headers = this.defaultHeaders; - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/json' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - 'application/json' - ]; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request('delete',`${this.basePath}/reference/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, - { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - - /** - * Get reference data for a particular resourceType and resourceKey. - * - * @param resourceType - * @param resourceKey - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public referenceResourceTypeResourceKeyGet( - resourceType: string, - resourceKey: ResourceKey, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public referenceResourceTypeResourceKeyGet( - resourceType: string, - resourceKey: ResourceKey, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeResourceKeyGet( - resourceType: string, - resourceKey: ResourceKey, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeResourceKeyGet( - resourceType: string, - resourceKey: ResourceKey, - observe: any = 'body', - reportProgress: boolean = false - ): Observable { - - if (resourceType === null || resourceType === undefined) { - throw new Error('Required parameter resourceType was null or undefined when calling referenceResourceTypeResourceKeyGet.'); - } - - if (resourceKey === null || resourceKey === undefined) { - throw new Error('Required parameter resourceKey was null or undefined when calling referenceResourceTypeResourceKeyGet.'); - } - - let headers = this.defaultHeaders; - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/json' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - ]; - - return this.httpClient.request('get',`${this.basePath}/reference/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, - { - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - - /** - * Create reference data for a particular resourceType and resourceKey. - * - * @param resourceType - * @param resourceKey - * @param body - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public referenceResourceTypeResourceKeyPost( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public referenceResourceTypeResourceKeyPost( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeResourceKeyPost( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeResourceKeyPost( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe: any = 'body', - reportProgress: boolean = false - ): Observable { - - if (resourceType === null || resourceType === undefined) { - throw new Error('Required parameter resourceType was null or undefined when calling referenceResourceTypeResourceKeyPost.'); - } - - if (resourceKey === null || resourceKey === undefined) { - throw new Error('Required parameter resourceKey was null or undefined when calling referenceResourceTypeResourceKeyPost.'); - } - - let headers = this.defaultHeaders; - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/json' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - 'application/json' - ]; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request('post',`${this.basePath}/reference/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, - { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - - /** - * Update/Create reference data for a particular resourceType and resourceKey. - * - * @param resourceType - * @param resourceKey - * @param body - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public referenceResourceTypeResourceKeyPut( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public referenceResourceTypeResourceKeyPut( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeResourceKeyPut( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeResourceKeyPut( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe: any = 'body', - reportProgress: boolean = false - ): Observable { - - if (resourceType === null || resourceType === undefined) { - throw new Error('Required parameter resourceType was null or undefined when calling referenceResourceTypeResourceKeyPut.'); - } - - if (resourceKey === null || resourceKey === undefined) { - throw new Error('Required parameter resourceKey was null or undefined when calling referenceResourceTypeResourceKeyPut.'); - } - - let headers = this.defaultHeaders; - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/json' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - 'application/json' - ]; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request('put',`${this.basePath}/reference/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, - { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor( + protected httpClient: HttpClient, + @Optional() @Inject(BASE_PATH) basePath: string, + @Optional() configuration: Configuration + ) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + /** + * Lookup any resourceType with its key, allows partials. + * + * @param resourceType + * @param resourceKey + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public referenceLookupResourceTypeResourceKeyGet( + resourceType: string, + resourceKey: ResourceKey, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public referenceLookupResourceTypeResourceKeyGet( + resourceType: string, + resourceKey: ResourceKey, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public referenceLookupResourceTypeResourceKeyGet( + resourceType: string, + resourceKey: ResourceKey, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public referenceLookupResourceTypeResourceKeyGet( + resourceType: string, + resourceKey: ResourceKey, + observe: any = 'body', + reportProgress = false + ): Observable { + if (resourceType === null || resourceType === undefined) { + throw new Error( + 'Required parameter resourceType was null or undefined when calling referenceLookupResourceTypeResourceKeyGet.' + ); + } + + if (resourceKey === null || resourceKey === undefined) { + throw new Error( + 'Required parameter resourceKey was null or undefined when calling referenceLookupResourceTypeResourceKeyGet.' + ); + } + + let headers = this.defaultHeaders; + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = []; + + return this.httpClient.request( + 'get', + `${this.basePath}/reference/lookup/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, + { + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + } + ); + } + + /** + * Search the tyres by plyRating, singleIndex and doubleIndex, allows partials. + * + * @param searchKey + * @param param + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public referenceLookupTyresSearchKeyParamGet( + searchKey: string, + param: string, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public referenceLookupTyresSearchKeyParamGet( + searchKey: string, + param: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public referenceLookupTyresSearchKeyParamGet( + searchKey: string, + param: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public referenceLookupTyresSearchKeyParamGet( + searchKey: string, + param: string, + observe: any = 'body', + reportProgress = false + ): Observable { + if (searchKey === null || searchKey === undefined) { + throw new Error( + 'Required parameter searchKey was null or undefined when calling referenceLookupTyresSearchKeyParamGet.' + ); + } + + if (param === null || param === undefined) { + throw new Error( + 'Required parameter param was null or undefined when calling referenceLookupTyresSearchKeyParamGet.' + ); + } + + let headers = this.defaultHeaders; + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = []; + + return this.httpClient.request( + 'get', + `${this.basePath}/reference/lookup/tyres/${encodeURIComponent(String(searchKey))}/${encodeURIComponent(String(param))}`, + { + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + } + ); + } + + /** + * Get reference data for a particular resourceType. + * + * @param resourceType + * @param paginationToken + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public referenceResourceTypeGet( + resourceType: string, + paginationToken?: string, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public referenceResourceTypeGet( + resourceType: string, + paginationToken?: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeGet( + resourceType: string, + paginationToken?: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeGet( + resourceType: string, + paginationToken?: string, + observe: any = 'body', + reportProgress = false + ): Observable { + if (resourceType === null || resourceType === undefined) { + throw new Error('Required parameter resourceType was null or undefined when calling referenceResourceTypeGet.'); + } + + let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); + if (paginationToken !== undefined && paginationToken !== null) { + queryParameters = queryParameters.set('paginationToken', paginationToken); + } + + let headers = this.defaultHeaders; + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = []; + + return this.httpClient.request( + 'get', + `${this.basePath}/reference/${encodeURIComponent(String(resourceType))}`, + { + params: queryParameters, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + } + ); + } + + /** + * Delete reference data for a particular resourceType and resourceKey. + * + * @param resourceType + * @param resourceKey + * @param body + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public referenceResourceTypeResourceKeyDelete( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public referenceResourceTypeResourceKeyDelete( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeResourceKeyDelete( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeResourceKeyDelete( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe: any = 'body', + reportProgress = false + ): Observable { + if (resourceType === null || resourceType === undefined) { + throw new Error( + 'Required parameter resourceType was null or undefined when calling referenceResourceTypeResourceKeyDelete.' + ); + } + + if (resourceKey === null || resourceKey === undefined) { + throw new Error( + 'Required parameter resourceKey was null or undefined when calling referenceResourceTypeResourceKeyDelete.' + ); + } + + let headers = this.defaultHeaders; + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = ['application/json']; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request( + 'delete', + `${this.basePath}/reference/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, + { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + } + ); + } + + /** + * Get reference data for a particular resourceType and resourceKey. + * + * @param resourceType + * @param resourceKey + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public referenceResourceTypeResourceKeyGet( + resourceType: string, + resourceKey: ResourceKey, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public referenceResourceTypeResourceKeyGet( + resourceType: string, + resourceKey: ResourceKey, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeResourceKeyGet( + resourceType: string, + resourceKey: ResourceKey, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeResourceKeyGet( + resourceType: string, + resourceKey: ResourceKey, + observe: any = 'body', + reportProgress = false + ): Observable { + if (resourceType === null || resourceType === undefined) { + throw new Error( + 'Required parameter resourceType was null or undefined when calling referenceResourceTypeResourceKeyGet.' + ); + } + + if (resourceKey === null || resourceKey === undefined) { + throw new Error( + 'Required parameter resourceKey was null or undefined when calling referenceResourceTypeResourceKeyGet.' + ); + } + + let headers = this.defaultHeaders; + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = []; + + return this.httpClient.request( + 'get', + `${this.basePath}/reference/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, + { + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + } + ); + } + + /** + * Create reference data for a particular resourceType and resourceKey. + * + * @param resourceType + * @param resourceKey + * @param body + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public referenceResourceTypeResourceKeyPost( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public referenceResourceTypeResourceKeyPost( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeResourceKeyPost( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeResourceKeyPost( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe: any = 'body', + reportProgress = false + ): Observable { + if (resourceType === null || resourceType === undefined) { + throw new Error( + 'Required parameter resourceType was null or undefined when calling referenceResourceTypeResourceKeyPost.' + ); + } + + if (resourceKey === null || resourceKey === undefined) { + throw new Error( + 'Required parameter resourceKey was null or undefined when calling referenceResourceTypeResourceKeyPost.' + ); + } + + let headers = this.defaultHeaders; + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = ['application/json']; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request( + 'post', + `${this.basePath}/reference/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, + { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + } + ); + } + + /** + * Update/Create reference data for a particular resourceType and resourceKey. + * + * @param resourceType + * @param resourceKey + * @param body + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public referenceResourceTypeResourceKeyPut( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public referenceResourceTypeResourceKeyPut( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeResourceKeyPut( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeResourceKeyPut( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe: any = 'body', + reportProgress = false + ): Observable { + if (resourceType === null || resourceType === undefined) { + throw new Error( + 'Required parameter resourceType was null or undefined when calling referenceResourceTypeResourceKeyPut.' + ); + } + + if (resourceKey === null || resourceKey === undefined) { + throw new Error( + 'Required parameter resourceKey was null or undefined when calling referenceResourceTypeResourceKeyPut.' + ); + } + + let headers = this.defaultHeaders; + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = ['application/json']; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request( + 'put', + `${this.basePath}/reference/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, + { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + } + ); + } } diff --git a/src/app/api/reference-data/configuration.ts b/src/app/api/reference-data/configuration.ts index 82e8458f39..698dce114c 100644 --- a/src/app/api/reference-data/configuration.ts +++ b/src/app/api/reference-data/configuration.ts @@ -1,79 +1,82 @@ export interface ConfigurationParameters { - apiKeys?: {[ key: string ]: string}; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: { [key: string]: string }; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; } export class Configuration { - apiKeys?: {[ key: string ]: string}; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: { [key: string]: string }; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; - constructor(configurationParameters: ConfigurationParameters = {}) { - this.apiKeys = configurationParameters.apiKeys; - this.username = configurationParameters.username; - this.password = configurationParameters.password; - this.accessToken = configurationParameters.accessToken; - this.basePath = configurationParameters.basePath; - this.withCredentials = configurationParameters.withCredentials; - } + constructor(configurationParameters: ConfigurationParameters = {}) { + this.apiKeys = configurationParameters.apiKeys; + this.username = configurationParameters.username; + this.password = configurationParameters.password; + this.accessToken = configurationParameters.accessToken; + this.basePath = configurationParameters.basePath; + this.withCredentials = configurationParameters.withCredentials; + } - /** - * Select the correct content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param contentTypes - the array of content types that are available for selection - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderContentType (contentTypes: string[]): string | undefined { - if (contentTypes.length == 0) { - return undefined; - } + /** + * Select the correct content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param contentTypes - the array of content types that are available for selection + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderContentType(contentTypes: string[]): string | undefined { + if (contentTypes.length == 0) { + return undefined; + } - let type = contentTypes.find(x => this.isJsonMime(x)); - if (type === undefined) { - return contentTypes[0]; - } - return type; - } + const type = contentTypes.find((x) => this.isJsonMime(x)); + if (type === undefined) { + return contentTypes[0]; + } + return type; + } - /** - * Select the correct accept content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param accepts - the array of content types that are available for selection. - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderAccept(accepts: string[]): string | undefined { - if (accepts.length == 0) { - return undefined; - } + /** + * Select the correct accept content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param accepts - the array of content types that are available for selection. + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderAccept(accepts: string[]): string | undefined { + if (accepts.length == 0) { + return undefined; + } - let type = accepts.find(x => this.isJsonMime(x)); - if (type === undefined) { - return accepts[0]; - } - return type; - } + const type = accepts.find((x) => this.isJsonMime(x)); + if (type === undefined) { + return accepts[0]; + } + return type; + } - /** - * Check if the given MIME is a JSON MIME. - * JSON MIME examples: - * application/json - * application/json; charset=UTF8 - * APPLICATION/JSON - * application/vnd.company+json - * @param mime - MIME (Multipurpose Internet Mail Extensions) - * @return True if the given MIME is JSON, false otherwise. - */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); - return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = /^(application\\/jnos | [^;\/ \t]+\; + \/[^ + \/ \t]+[+]json)[ \t]*( + .*)?$/i + return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } } diff --git a/src/app/api/reference-data/encoder.ts b/src/app/api/reference-data/encoder.ts index f506bfbea0..233fb78e4a 100644 --- a/src/app/api/reference-data/encoder.ts +++ b/src/app/api/reference-data/encoder.ts @@ -1,18 +1,17 @@ - import { HttpUrlEncodingCodec } from '@angular/common/http'; +import { HttpUrlEncodingCodec } from '@angular/common/http'; /** -* CustomHttpUrlEncodingCodec -* Fix plus sign (+) not encoding, so sent as blank space -* See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 -*/ + * CustomHttpUrlEncodingCodec + * Fix plus sign (+) not encoding, so sent as blank space + * See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 + */ export class CustomHttpUrlEncodingCodec extends HttpUrlEncodingCodec { - override encodeKey(k: string): string { - k = super.encodeKey(k); - return k.replace(/\+/gi, '%2B'); - } - override encodeValue(v: string): string { - v = super.encodeValue(v); - return v.replace(/\+/gi, '%2B'); - } + override encodeKey(k: string): string { + k = super.encodeKey(k); + return k.replace(/\+/gi, '%2B'); + } + override encodeValue(v: string): string { + v = super.encodeValue(v); + return v.replace(/\+/gi, '%2B'); + } } - diff --git a/src/app/api/reference-data/index.ts b/src/app/api/reference-data/index.ts index c312b70fa3..410623f1c9 100644 --- a/src/app/api/reference-data/index.ts +++ b/src/app/api/reference-data/index.ts @@ -2,4 +2,4 @@ export * from './api/api'; export * from './model/models'; export * from './variables'; export * from './configuration'; -export * from './api.module'; \ No newline at end of file +export * from './api.module'; diff --git a/src/app/api/reference-data/model/deleteItem.ts b/src/app/api/reference-data/model/deleteItem.ts index 52156da807..1dfd362d83 100644 --- a/src/app/api/reference-data/model/deleteItem.ts +++ b/src/app/api/reference-data/model/deleteItem.ts @@ -10,6 +10,6 @@ * Do not edit the class manually. */ -export interface DeleteItem { - success?: boolean; -} \ No newline at end of file +export interface DeleteItem { + success?: boolean; +} diff --git a/src/app/api/reference-data/model/emptyObject.ts b/src/app/api/reference-data/model/emptyObject.ts index 124b603c70..a3c2dddc63 100644 --- a/src/app/api/reference-data/model/emptyObject.ts +++ b/src/app/api/reference-data/model/emptyObject.ts @@ -10,5 +10,4 @@ * Do not edit the class manually. */ -export interface EmptyObject { -} \ No newline at end of file +export type EmptyObject = {}; diff --git a/src/app/api/reference-data/model/referenceDataApiResponse.ts b/src/app/api/reference-data/model/referenceDataApiResponse.ts index 1d35b26c6f..5704314bf4 100644 --- a/src/app/api/reference-data/model/referenceDataApiResponse.ts +++ b/src/app/api/reference-data/model/referenceDataApiResponse.ts @@ -12,4 +12,6 @@ import { ReferenceDataApiResponseWithPagination } from './referenceDataApiResponseWithPagination'; import { ReferenceDataApiResponseWithoutPagination } from './referenceDataApiResponseWithoutPagination'; -export type ReferenceDataApiResponse = ReferenceDataApiResponseWithoutPagination | ReferenceDataApiResponseWithPagination; \ No newline at end of file +export type ReferenceDataApiResponse = + | ReferenceDataApiResponseWithoutPagination + | ReferenceDataApiResponseWithPagination; diff --git a/src/app/api/reference-data/model/referenceDataApiResponseWithPagination.ts b/src/app/api/reference-data/model/referenceDataApiResponseWithPagination.ts index 2465daa232..c435d2427f 100644 --- a/src/app/api/reference-data/model/referenceDataApiResponseWithPagination.ts +++ b/src/app/api/reference-data/model/referenceDataApiResponseWithPagination.ts @@ -10,8 +10,7 @@ * Do not edit the class manually. */ import { ReferenceDataApiResponseWithoutPagination } from './referenceDataApiResponseWithoutPagination'; -import { ReferenceDataItem } from './referenceDataItem'; -export interface ReferenceDataApiResponseWithPagination extends ReferenceDataApiResponseWithoutPagination { - paginationToken: string; -} \ No newline at end of file +export interface ReferenceDataApiResponseWithPagination extends ReferenceDataApiResponseWithoutPagination { + paginationToken: string; +} diff --git a/src/app/api/reference-data/model/referenceDataApiResponseWithoutPagination.ts b/src/app/api/reference-data/model/referenceDataApiResponseWithoutPagination.ts index c473133fd5..93d2489a3c 100644 --- a/src/app/api/reference-data/model/referenceDataApiResponseWithoutPagination.ts +++ b/src/app/api/reference-data/model/referenceDataApiResponseWithoutPagination.ts @@ -11,6 +11,6 @@ */ import { ReferenceDataItem } from './referenceDataItem'; -export interface ReferenceDataApiResponseWithoutPagination { - data: Array; -} \ No newline at end of file +export interface ReferenceDataApiResponseWithoutPagination { + data: Array; +} diff --git a/src/app/api/reference-data/model/referenceDataItem.ts b/src/app/api/reference-data/model/referenceDataItem.ts index 55566b6435..97ae42895c 100644 --- a/src/app/api/reference-data/model/referenceDataItem.ts +++ b/src/app/api/reference-data/model/referenceDataItem.ts @@ -11,8 +11,8 @@ */ import { ResourceKey } from './resourceKey'; -export interface ReferenceDataItem { - resourceType: string; - resourceKey: ResourceKey; - reason?: string; -} \ No newline at end of file +export interface ReferenceDataItem { + resourceType: string; + resourceKey: ResourceKey; + reason?: string; +} diff --git a/src/app/api/reference-data/model/referenceDataItemApiResponse.ts b/src/app/api/reference-data/model/referenceDataItemApiResponse.ts index 97b7df9d77..37c298fb77 100644 --- a/src/app/api/reference-data/model/referenceDataItemApiResponse.ts +++ b/src/app/api/reference-data/model/referenceDataItemApiResponse.ts @@ -12,4 +12,4 @@ import { EmptyObject } from './emptyObject'; import { ReferenceDataItem } from './referenceDataItem'; -export type ReferenceDataItemApiResponse = ReferenceDataItem | EmptyObject; \ No newline at end of file +export type ReferenceDataItemApiResponse = ReferenceDataItem | EmptyObject; diff --git a/src/app/api/reference-data/model/resourceKey.ts b/src/app/api/reference-data/model/resourceKey.ts index 3f52dec65c..7898a0344a 100644 --- a/src/app/api/reference-data/model/resourceKey.ts +++ b/src/app/api/reference-data/model/resourceKey.ts @@ -10,4 +10,4 @@ * Do not edit the class manually. */ -export type ResourceKey = string | number; \ No newline at end of file +export type ResourceKey = string | number; diff --git a/src/app/api/reference-data/variables.ts b/src/app/api/reference-data/variables.ts index 6fe58549f3..9bae45f800 100644 --- a/src/app/api/reference-data/variables.ts +++ b/src/app/api/reference-data/variables.ts @@ -2,8 +2,8 @@ import { InjectionToken } from '@angular/core'; export const BASE_PATH = new InjectionToken('basePath'); export const COLLECTION_FORMATS = { - 'csv': ',', - 'tsv': ' ', - 'ssv': ' ', - 'pipes': '|' -} + csv: ',', + tsv: ' ', + ssv: ' ', + pipes: '|', +}; diff --git a/src/app/api/test-results/api.module.ts b/src/app/api/test-results/api.module.ts index 0cfe105217..8624d75994 100644 --- a/src/app/api/test-results/api.module.ts +++ b/src/app/api/test-results/api.module.ts @@ -1,7 +1,6 @@ -import { NgModule, ModuleWithProviders, SkipSelf, Optional } from '@angular/core'; -import { Configuration } from './configuration'; import { HttpClient } from '@angular/common/http'; - +import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; +import { Configuration } from './configuration'; import { ArchiveTestResultsService } from './api/archiveTestResults.service'; import { DefaultService } from './api/default.service'; @@ -9,31 +8,28 @@ import { GetTestResultsService } from './api/getTestResults.service'; import { UpdateTestResultsService } from './api/updateTestResults.service'; @NgModule({ - imports: [], - declarations: [], - exports: [], - providers: [ - ArchiveTestResultsService, - DefaultService, - GetTestResultsService, - UpdateTestResultsService ] + imports: [], + declarations: [], + exports: [], + providers: [ArchiveTestResultsService, DefaultService, GetTestResultsService, UpdateTestResultsService], }) export class ApiModule { - public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { - return { - ngModule: ApiModule, - providers: [ { provide: Configuration, useFactory: configurationFactory } ] - }; - } + public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { + return { + ngModule: ApiModule, + providers: [{ provide: Configuration, useFactory: configurationFactory }], + }; + } - constructor( @Optional() @SkipSelf() parentModule: ApiModule, - @Optional() http: HttpClient) { - if (parentModule) { - throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); - } - if (!http) { - throw new Error('You need to import the HttpClientModule in your AppModule! \n' + - 'See also https://github.com/angular/angular/issues/20575'); - } - } + constructor(@Optional() @SkipSelf() parentModule: ApiModule, @Optional() http: HttpClient) { + if (parentModule) { + throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); + } + if (!http) { + throw new Error( + 'You need to import the HttpClientModule in your AppModule! \n' + + 'See also https://github.com/angular/angular/issues/20575' + ); + } + } } diff --git a/src/app/api/test-results/api/archiveTestResults.service.ts b/src/app/api/test-results/api/archiveTestResults.service.ts index bb2afbf814..747db0ca46 100644 --- a/src/app/api/test-results/api/archiveTestResults.service.ts +++ b/src/app/api/test-results/api/archiveTestResults.service.ts @@ -7,112 +7,130 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - *//* tslint:disable:no-unused-variable member-ordering */ + */ /* tslint:disable:no-unused-variable member-ordering */ -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpHeaders, HttpParams, - HttpResponse, HttpEvent } from '@angular/common/http'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http'; +import { Inject, Injectable, Optional } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { CompleteTestResults } from '../model/completeTestResults'; import { TestResults } from '../model/testResults'; -import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; -import { Configuration } from '../configuration'; - +import { Configuration } from '../configuration'; +import { BASE_PATH } from '../variables'; @Injectable() export class ArchiveTestResultsService { - - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - - /** - * Archive a specific test-type, for a particular testResultId - * - * @param body The test result containing the test-type to be archived (marked with statusUpdatedFlag set to true) - * @param testResultId - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public testResultsArchiveTestResultIdPut(body: CompleteTestResults, testResultId: string, observe?: 'body', reportProgress?: boolean): Observable; - public testResultsArchiveTestResultIdPut(body: CompleteTestResults, testResultId: string, observe?: 'response', reportProgress?: boolean): Observable>; - public testResultsArchiveTestResultIdPut(body: CompleteTestResults, testResultId: string, observe?: 'events', reportProgress?: boolean): Observable>; - public testResultsArchiveTestResultIdPut(body: CompleteTestResults, testResultId: string, observe: any = 'body', reportProgress: boolean = false ): Observable { - - if (body === null || body === undefined) { - throw new Error('Required parameter body was null or undefined when calling testResultsArchiveTestResultIdPut.'); - } - - if (testResultId === null || testResultId === undefined) { - throw new Error('Required parameter testResultId was null or undefined when calling testResultsArchiveTestResultIdPut.'); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); - } - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/json' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - 'application/json' - ]; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request('put',`${this.basePath}/test-results/archive/${encodeURIComponent(String(testResultId))}`, - { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor( + protected httpClient: HttpClient, + @Optional() @Inject(BASE_PATH) basePath: string, + @Optional() configuration: Configuration + ) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + /** + * Archive a specific test-type, for a particular testResultId + * + * @param body The test result containing the test-type to be archived (marked with statusUpdatedFlag set to true) + * @param testResultId + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public testResultsArchiveTestResultIdPut( + body: CompleteTestResults, + testResultId: string, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public testResultsArchiveTestResultIdPut( + body: CompleteTestResults, + testResultId: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public testResultsArchiveTestResultIdPut( + body: CompleteTestResults, + testResultId: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public testResultsArchiveTestResultIdPut( + body: CompleteTestResults, + testResultId: string, + observe: any = 'body', + reportProgress = false + ): Observable { + if (body === null || body === undefined) { + throw new Error('Required parameter body was null or undefined when calling testResultsArchiveTestResultIdPut.'); + } + + if (testResultId === null || testResultId === undefined) { + throw new Error( + 'Required parameter testResultId was null or undefined when calling testResultsArchiveTestResultIdPut.' + ); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = ['application/json']; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request( + 'put', + `${this.basePath}/test-results/archive/${encodeURIComponent(String(testResultId))}`, + { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + } + ); + } } diff --git a/src/app/api/test-results/api/default.service.ts b/src/app/api/test-results/api/default.service.ts index 51ab3c8930..57b689c012 100644 --- a/src/app/api/test-results/api/default.service.ts +++ b/src/app/api/test-results/api/default.service.ts @@ -7,105 +7,106 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - *//* tslint:disable:no-unused-variable member-ordering */ + */ /* tslint:disable:no-unused-variable member-ordering */ -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpHeaders, HttpParams, - HttpResponse, HttpEvent } from '@angular/common/http'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http'; +import { Inject, Injectable, Optional } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { CompleteTestResults } from '../model/completeTestResults'; -import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; -import { Configuration } from '../configuration'; - +import { Configuration } from '../configuration'; +import { BASE_PATH } from '../variables'; @Injectable() export class DefaultService { - - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - - /** - * Submitting a new test records - * - * @param body Post the test results - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public testResultsPost(body: CompleteTestResults, observe?: 'body', reportProgress?: boolean): Observable; - public testResultsPost(body: CompleteTestResults, observe?: 'response', reportProgress?: boolean): Observable>; - public testResultsPost(body: CompleteTestResults, observe?: 'events', reportProgress?: boolean): Observable>; - public testResultsPost(body: CompleteTestResults, observe: any = 'body', reportProgress: boolean = false ): Observable { - - if (body === null || body === undefined) { - throw new Error('Required parameter body was null or undefined when calling testResultsPost.'); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); - } - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - 'application/json' - ]; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request('post',`${this.basePath}/test-results`, - { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor( + protected httpClient: HttpClient, + @Optional() @Inject(BASE_PATH) basePath: string, + @Optional() configuration: Configuration + ) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + /** + * Submitting a new test records + * + * @param body Post the test results + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public testResultsPost(body: CompleteTestResults, observe?: 'body', reportProgress?: boolean): Observable; + public testResultsPost( + body: CompleteTestResults, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public testResultsPost( + body: CompleteTestResults, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public testResultsPost(body: CompleteTestResults, observe: any = 'body', reportProgress = false): Observable { + if (body === null || body === undefined) { + throw new Error('Required parameter body was null or undefined when calling testResultsPost.'); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = []; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = ['application/json']; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request('post', `${this.basePath}/test-results`, { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + }); + } } diff --git a/src/app/api/test-results/api/getTestResults.service.ts b/src/app/api/test-results/api/getTestResults.service.ts index 98e13ed5af..612651208d 100644 --- a/src/app/api/test-results/api/getTestResults.service.ts +++ b/src/app/api/test-results/api/getTestResults.service.ts @@ -7,128 +7,157 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - *//* tslint:disable:no-unused-variable member-ordering */ + */ /* tslint:disable:no-unused-variable member-ordering */ -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpHeaders, HttpParams, - HttpResponse, HttpEvent } from '@angular/common/http'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; +import { Inject, Injectable, Optional } from '@angular/core'; +import { CustomHttpUrlEncodingCodec } from '../encoder'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { TestResults } from '../model/testResults'; -import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; -import { Configuration } from '../configuration'; - +import { Configuration } from '../configuration'; +import { BASE_PATH } from '../variables'; @Injectable() export class GetTestResultsService { - - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - - /** - * Get a test results, for a particular Vin with status specified. - * - * @param systemNumber - * @param status The test result status - * @param fromDateTime The UTC ISO Date Time filter, if the fromDate and ToDate not specified by default to 2 years of data for now. - * @param toDateTime The UTC ISO DateTime filter. - * @param testResultId Query param to filter the test-results based on testResultId. - * @param version Query param to filter the test-results based on testVersion. If not present then GET will return the current test-result. Can be used only with testResultId query param, otherwise it is not taken into account. - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public testResultsSystemNumberGet(systemNumber: string, status?: string, fromDateTime?: Date, toDateTime?: Date, testResultId?: string, version?: string, observe?: 'body', reportProgress?: boolean): Observable; - public testResultsSystemNumberGet(systemNumber: string, status?: string, fromDateTime?: Date, toDateTime?: Date, testResultId?: string, version?: string, observe?: 'response', reportProgress?: boolean): Observable>; - public testResultsSystemNumberGet(systemNumber: string, status?: string, fromDateTime?: Date, toDateTime?: Date, testResultId?: string, version?: string, observe?: 'events', reportProgress?: boolean): Observable>; - public testResultsSystemNumberGet(systemNumber: string, status?: string, fromDateTime?: Date, toDateTime?: Date, testResultId?: string, version?: string, observe: any = 'body', reportProgress: boolean = false ): Observable { - - if (systemNumber === null || systemNumber === undefined) { - throw new Error('Required parameter systemNumber was null or undefined when calling testResultsSystemNumberGet.'); - } - - - - - - - let queryParameters = new HttpParams({encoder: new CustomHttpUrlEncodingCodec()}); - if (status !== undefined && status !== null) { - queryParameters = queryParameters.set('status', status); - } - if (fromDateTime !== undefined && fromDateTime !== null) { - queryParameters = queryParameters.set('fromDateTime', fromDateTime.toISOString()); - } - if (toDateTime !== undefined && toDateTime !== null) { - queryParameters = queryParameters.set('toDateTime', toDateTime.toISOString()); - } - if (testResultId !== undefined && testResultId !== null) { - queryParameters = queryParameters.set('testResultId', testResultId); - } - if (version !== undefined && version !== null) { - queryParameters = queryParameters.set('version', version); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); - } - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/json' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - ]; - - return this.httpClient.request('get',`${this.basePath}/test-results/${encodeURIComponent(String(systemNumber))}`, - { - params: queryParameters, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor( + protected httpClient: HttpClient, + @Optional() @Inject(BASE_PATH) basePath: string, + @Optional() configuration: Configuration + ) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + /** + * Get a test results, for a particular Vin with status specified. + * + * @param systemNumber + * @param status The test result status + * @param fromDateTime The UTC ISO Date Time filter, if the fromDate and ToDate not specified by default to 2 years of data for now. + * @param toDateTime The UTC ISO DateTime filter. + * @param testResultId Query param to filter the test-results based on testResultId. + * @param version Query param to filter the test-results based on testVersion. If not present then GET will return the current test-result. Can be used only with testResultId query param, otherwise it is not taken into account. + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public testResultsSystemNumberGet( + systemNumber: string, + status?: string, + fromDateTime?: Date, + toDateTime?: Date, + testResultId?: string, + version?: string, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public testResultsSystemNumberGet( + systemNumber: string, + status?: string, + fromDateTime?: Date, + toDateTime?: Date, + testResultId?: string, + version?: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public testResultsSystemNumberGet( + systemNumber: string, + status?: string, + fromDateTime?: Date, + toDateTime?: Date, + testResultId?: string, + version?: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public testResultsSystemNumberGet( + systemNumber: string, + status?: string, + fromDateTime?: Date, + toDateTime?: Date, + testResultId?: string, + version?: string, + observe: any = 'body', + reportProgress = false + ): Observable { + if (systemNumber === null || systemNumber === undefined) { + throw new Error('Required parameter systemNumber was null or undefined when calling testResultsSystemNumberGet.'); + } + + let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); + if (status !== undefined && status !== null) { + queryParameters = queryParameters.set('status', status); + } + if (fromDateTime !== undefined && fromDateTime !== null) { + queryParameters = queryParameters.set('fromDateTime', fromDateTime.toISOString()); + } + if (toDateTime !== undefined && toDateTime !== null) { + queryParameters = queryParameters.set('toDateTime', toDateTime.toISOString()); + } + if (testResultId !== undefined && testResultId !== null) { + queryParameters = queryParameters.set('testResultId', testResultId); + } + if (version !== undefined && version !== null) { + queryParameters = queryParameters.set('version', version); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = []; + + return this.httpClient.request( + 'get', + `${this.basePath}/test-results/${encodeURIComponent(String(systemNumber))}`, + { + params: queryParameters, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + } + ); + } } diff --git a/src/app/api/test-results/api/updateTestResults.service.ts b/src/app/api/test-results/api/updateTestResults.service.ts index a17a7e1bea..52e310e045 100644 --- a/src/app/api/test-results/api/updateTestResults.service.ts +++ b/src/app/api/test-results/api/updateTestResults.service.ts @@ -7,111 +7,127 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - *//* tslint:disable:no-unused-variable member-ordering */ + */ /* tslint:disable:no-unused-variable member-ordering */ -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpHeaders, HttpParams, - HttpResponse, HttpEvent } from '@angular/common/http'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http'; +import { Inject, Injectable, Optional } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { CompleteTestResults } from '../model/completeTestResults'; -import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; -import { Configuration } from '../configuration'; - +import { Configuration } from '../configuration'; +import { BASE_PATH } from '../variables'; @Injectable() export class UpdateTestResultsService { - - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - - /** - * Update a test result using the systemNumber and testResultId as unique identifiers. - * - * @param body The test result to be updated - * @param systemNumber - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public testResultsSystemNumberPut(body: CompleteTestResults, systemNumber: string, observe?: 'body', reportProgress?: boolean): Observable; - public testResultsSystemNumberPut(body: CompleteTestResults, systemNumber: string, observe?: 'response', reportProgress?: boolean): Observable>; - public testResultsSystemNumberPut(body: CompleteTestResults, systemNumber: string, observe?: 'events', reportProgress?: boolean): Observable>; - public testResultsSystemNumberPut(body: CompleteTestResults, systemNumber: string, observe: any = 'body', reportProgress: boolean = false ): Observable { - - if (body === null || body === undefined) { - throw new Error('Required parameter body was null or undefined when calling testResultsSystemNumberPut.'); - } - - if (systemNumber === null || systemNumber === undefined) { - throw new Error('Required parameter systemNumber was null or undefined when calling testResultsSystemNumberPut.'); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); - } - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/json' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - 'application/json' - ]; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request('put',`${this.basePath}/test-results/${encodeURIComponent(String(systemNumber))}`, - { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor( + protected httpClient: HttpClient, + @Optional() @Inject(BASE_PATH) basePath: string, + @Optional() configuration: Configuration + ) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + /** + * Update a test result using the systemNumber and testResultId as unique identifiers. + * + * @param body The test result to be updated + * @param systemNumber + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public testResultsSystemNumberPut( + body: CompleteTestResults, + systemNumber: string, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public testResultsSystemNumberPut( + body: CompleteTestResults, + systemNumber: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public testResultsSystemNumberPut( + body: CompleteTestResults, + systemNumber: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public testResultsSystemNumberPut( + body: CompleteTestResults, + systemNumber: string, + observe: any = 'body', + reportProgress = false + ): Observable { + if (body === null || body === undefined) { + throw new Error('Required parameter body was null or undefined when calling testResultsSystemNumberPut.'); + } + + if (systemNumber === null || systemNumber === undefined) { + throw new Error('Required parameter systemNumber was null or undefined when calling testResultsSystemNumberPut.'); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = ['application/json']; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request( + 'put', + `${this.basePath}/test-results/${encodeURIComponent(String(systemNumber))}`, + { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + } + ); + } } diff --git a/src/app/api/test-results/configuration.ts b/src/app/api/test-results/configuration.ts index 82e8458f39..698dce114c 100644 --- a/src/app/api/test-results/configuration.ts +++ b/src/app/api/test-results/configuration.ts @@ -1,79 +1,82 @@ export interface ConfigurationParameters { - apiKeys?: {[ key: string ]: string}; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: { [key: string]: string }; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; } export class Configuration { - apiKeys?: {[ key: string ]: string}; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: { [key: string]: string }; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; - constructor(configurationParameters: ConfigurationParameters = {}) { - this.apiKeys = configurationParameters.apiKeys; - this.username = configurationParameters.username; - this.password = configurationParameters.password; - this.accessToken = configurationParameters.accessToken; - this.basePath = configurationParameters.basePath; - this.withCredentials = configurationParameters.withCredentials; - } + constructor(configurationParameters: ConfigurationParameters = {}) { + this.apiKeys = configurationParameters.apiKeys; + this.username = configurationParameters.username; + this.password = configurationParameters.password; + this.accessToken = configurationParameters.accessToken; + this.basePath = configurationParameters.basePath; + this.withCredentials = configurationParameters.withCredentials; + } - /** - * Select the correct content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param contentTypes - the array of content types that are available for selection - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderContentType (contentTypes: string[]): string | undefined { - if (contentTypes.length == 0) { - return undefined; - } + /** + * Select the correct content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param contentTypes - the array of content types that are available for selection + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderContentType(contentTypes: string[]): string | undefined { + if (contentTypes.length == 0) { + return undefined; + } - let type = contentTypes.find(x => this.isJsonMime(x)); - if (type === undefined) { - return contentTypes[0]; - } - return type; - } + const type = contentTypes.find((x) => this.isJsonMime(x)); + if (type === undefined) { + return contentTypes[0]; + } + return type; + } - /** - * Select the correct accept content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param accepts - the array of content types that are available for selection. - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderAccept(accepts: string[]): string | undefined { - if (accepts.length == 0) { - return undefined; - } + /** + * Select the correct accept content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param accepts - the array of content types that are available for selection. + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderAccept(accepts: string[]): string | undefined { + if (accepts.length == 0) { + return undefined; + } - let type = accepts.find(x => this.isJsonMime(x)); - if (type === undefined) { - return accepts[0]; - } - return type; - } + const type = accepts.find((x) => this.isJsonMime(x)); + if (type === undefined) { + return accepts[0]; + } + return type; + } - /** - * Check if the given MIME is a JSON MIME. - * JSON MIME examples: - * application/json - * application/json; charset=UTF8 - * APPLICATION/JSON - * application/vnd.company+json - * @param mime - MIME (Multipurpose Internet Mail Extensions) - * @return True if the given MIME is JSON, false otherwise. - */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); - return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = /^(application\\/jnos | [^;\/ \t]+\; + \/[^ + \/ \t]+[+]json)[ \t]*( + .*)?$/i + return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } } diff --git a/src/app/api/test-results/encoder.ts b/src/app/api/test-results/encoder.ts index 5d0fb0e90c..233fb78e4a 100644 --- a/src/app/api/test-results/encoder.ts +++ b/src/app/api/test-results/encoder.ts @@ -6,12 +6,12 @@ import { HttpUrlEncodingCodec } from '@angular/common/http'; * See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 */ export class CustomHttpUrlEncodingCodec extends HttpUrlEncodingCodec { - override encodeKey(k: string): string { - k = super.encodeKey(k); - return k.replace(/\+/gi, '%2B'); - } - override encodeValue(v: string): string { - v = super.encodeValue(v); - return v.replace(/\+/gi, '%2B'); - } + override encodeKey(k: string): string { + k = super.encodeKey(k); + return k.replace(/\+/gi, '%2B'); + } + override encodeValue(v: string): string { + v = super.encodeValue(v); + return v.replace(/\+/gi, '%2B'); + } } diff --git a/src/app/api/test-results/index.ts b/src/app/api/test-results/index.ts index c312b70fa3..410623f1c9 100644 --- a/src/app/api/test-results/index.ts +++ b/src/app/api/test-results/index.ts @@ -2,4 +2,4 @@ export * from './api/api'; export * from './model/models'; export * from './variables'; export * from './configuration'; -export * from './api.module'; \ No newline at end of file +export * from './api.module'; diff --git a/src/app/api/test-results/model/completeTestResults.ts b/src/app/api/test-results/model/completeTestResults.ts index 903399b351..f788cb0513 100644 --- a/src/app/api/test-results/model/completeTestResults.ts +++ b/src/app/api/test-results/model/completeTestResults.ts @@ -11,196 +11,225 @@ import { CompleteTestResultsVehicleClass } from './completeTestResultsVehicleClass'; import { TestTypes } from './testTypes'; -export interface CompleteTestResults { - /** - * It defines the link between a test and the vehicle, by uniqeuly identifing the vehicle. - */ - systemNumber?: string; - /** - * Mandatory for PSV and HGV, not applicable to TRL - */ - vrm?: string; - /** - * Mandatory for TRL, not applicable to PSV and HGV - */ - trailerId?: string; - vin?: string; - /** - * Not sent from FE, calculated in the BE. When the test result is submitted, in BE, the VRM of the vehicle will be copied into vehicleId also. - */ - vehicleId?: string; - /** - * Not sent from FE, calculated in the BE. - */ - deletionFlag?: boolean; - /** - * Array of archived test-results. The test-results in this array won't have the testHistory attribute and testVersion will always be archived. Should not be sent when performing an update - */ - testHistory?: Array; - /** - * Tests submitted from the mobile app won't have this attribute. Tests updated/created by VTM will do. - */ - testVersion?: CompleteTestResults.TestVersionEnum; - /** - * Applicable only when updating/creating a test from VTM - */ - reasonForCreation?: string; - /** - * Not sent from FE, calculated in the BE. - */ - createdAt?: Date; - /** - * Applicable only when updating/creating a test from VTM - */ - createdByName?: string; - /** - * Applicable only when updating/creating a test from VTM - */ - createdById?: string; - /** - * Not sent from FE, calculated in the BE. - */ - lastUpdatedAt?: Date; - /** - * Applicable only when updating/creating a test from VTM - */ - lastUpdatedByName?: string; - /** - * Applicable only when updating/creating a test from VTM - */ - lastUpdatedById?: string; - /** - * Not sent from FE, calculated in BE. Applicable only when updating a test from VTM. Used to determine if a certificate should be emailed or not after an update. - */ - shouldEmailCertificate?: string; - testStationName?: string; - testStationPNumber?: string; - testStationType?: CompleteTestResults.TestStationTypeEnum; - testerName?: string; - testerStaffId?: string; - testResultId?: string; - testerEmailAddress?: string; - testStartTimestamp?: Date; - testEndTimestamp?: Date; - testStatus?: CompleteTestResults.TestStatusEnum; - /** - * Required for Cancelled tests. Nullable only for Submitted and Abandoned tests. - */ - reasonForCancellation?: string; - vehicleClass?: CompleteTestResultsVehicleClass; - /** - * Used for car and lgv. - */ - vehicleSubclass?: Array; - vehicleType?: CompleteTestResults.VehicleTypeEnum; - /** - * mandatory for PSV only, not applicable for HGV and TRL - */ - numberOfSeats?: number; - vehicleConfiguration?: CompleteTestResults.VehicleConfigurationEnum; - /** - * Nullable only for Cancelled tests & not applicable to TRL - */ - odometerReading?: number; - /** - * Nullable only for Cancelled tests & not applicable to TRL - */ - odometerReadingUnits?: CompleteTestResults.OdometerReadingUnitsEnum; - preparerId?: string; - preparerName?: string; - numberOfWheelsDriven?: number; - /** - * Nullable only for Cancelled tests. - */ - euVehicleCategory?: CompleteTestResults.EuVehicleCategoryEnum; - /** - * Nullable only for Cancelled tests. - */ - countryOfRegistration?: string; - /** - * Mandatory for PSV only & not applicable to HGV and TRL - */ - vehicleSize?: CompleteTestResults.VehicleSizeEnum; - noOfAxles?: number; - /** - * Used only for PSV and HGV - */ - regnDate?: string; - /** - * Used only for TRL - */ - firstUseDate?: string; - testTypes?: TestTypes; +export interface CompleteTestResults { + /** + * It defines the link between a test and the vehicle, by uniqeuly identifing the vehicle. + */ + systemNumber?: string; + /** + * Mandatory for PSV and HGV, not applicable to TRL + */ + vrm?: string; + /** + * Mandatory for TRL, not applicable to PSV and HGV + */ + trailerId?: string; + vin?: string; + /** + * Not sent from FE, calculated in the BE. When the test result is submitted, in BE, the VRM of the vehicle will be copied into vehicleId also. + */ + vehicleId?: string; + /** + * Not sent from FE, calculated in the BE. + */ + deletionFlag?: boolean; + /** + * Array of archived test-results. The test-results in this array won't have the testHistory attribute and testVersion will always be archived. Should not be sent when performing an update + */ + testHistory?: Array; + /** + * Tests submitted from the mobile app won't have this attribute. Tests updated/created by VTM will do. + */ + testVersion?: CompleteTestResults.TestVersionEnum; + /** + * Applicable only when updating/creating a test from VTM + */ + reasonForCreation?: string; + /** + * Not sent from FE, calculated in the BE. + */ + createdAt?: Date; + /** + * Applicable only when updating/creating a test from VTM + */ + createdByName?: string; + /** + * Applicable only when updating/creating a test from VTM + */ + createdById?: string; + /** + * Not sent from FE, calculated in the BE. + */ + lastUpdatedAt?: Date; + /** + * Applicable only when updating/creating a test from VTM + */ + lastUpdatedByName?: string; + /** + * Applicable only when updating/creating a test from VTM + */ + lastUpdatedById?: string; + /** + * Not sent from FE, calculated in BE. Applicable only when updating a test from VTM. Used to determine if a certificate should be emailed or not after an update. + */ + shouldEmailCertificate?: string; + testStationName?: string; + testStationPNumber?: string; + testStationType?: CompleteTestResults.TestStationTypeEnum; + testerName?: string; + testerStaffId?: string; + testResultId?: string; + testerEmailAddress?: string; + testStartTimestamp?: Date; + testEndTimestamp?: Date; + testStatus?: CompleteTestResults.TestStatusEnum; + /** + * Required for Cancelled tests. Nullable only for Submitted and Abandoned tests. + */ + reasonForCancellation?: string; + vehicleClass?: CompleteTestResultsVehicleClass; + /** + * Used for car and lgv. + */ + vehicleSubclass?: Array; + vehicleType?: CompleteTestResults.VehicleTypeEnum; + /** + * mandatory for PSV only, not applicable for HGV and TRL + */ + numberOfSeats?: number; + vehicleConfiguration?: CompleteTestResults.VehicleConfigurationEnum; + /** + * Nullable only for Cancelled tests & not applicable to TRL + */ + odometerReading?: number; + /** + * Nullable only for Cancelled tests & not applicable to TRL + */ + odometerReadingUnits?: CompleteTestResults.OdometerReadingUnitsEnum; + preparerId?: string; + preparerName?: string; + numberOfWheelsDriven?: number; + /** + * Nullable only for Cancelled tests. + */ + euVehicleCategory?: CompleteTestResults.EuVehicleCategoryEnum; + /** + * Nullable only for Cancelled tests. + */ + countryOfRegistration?: string; + /** + * Mandatory for PSV only & not applicable to HGV and TRL + */ + vehicleSize?: CompleteTestResults.VehicleSizeEnum; + noOfAxles?: number; + /** + * Used only for PSV and HGV + */ + regnDate?: string; + /** + * Used only for TRL + */ + firstUseDate?: string; + testTypes?: TestTypes; } export namespace CompleteTestResults { - export type TestVersionEnum = 'current' | 'archived'; - export const TestVersionEnum = { - Current: 'current' as TestVersionEnum, - Archived: 'archived' as TestVersionEnum - }; - export type TestStationTypeEnum = 'atf' | 'gvts' | 'hq'; - export const TestStationTypeEnum = { - Atf: 'atf' as TestStationTypeEnum, - Gvts: 'gvts' as TestStationTypeEnum, - Hq: 'hq' as TestStationTypeEnum - }; - export type TestStatusEnum = 'submitted' | 'cancelled'; - export const TestStatusEnum = { - Submitted: 'submitted' as TestStatusEnum, - Cancelled: 'cancelled' as TestStatusEnum - }; - export type VehicleTypeEnum = 'psv' | 'hgv' | 'trl' | 'car' | 'lgv' | 'motorcycle'; - export const VehicleTypeEnum = { - Psv: 'psv' as VehicleTypeEnum, - Hgv: 'hgv' as VehicleTypeEnum, - Trl: 'trl' as VehicleTypeEnum, - Car: 'car' as VehicleTypeEnum, - Lgv: 'lgv' as VehicleTypeEnum, - Motorcycle: 'motorcycle' as VehicleTypeEnum - }; - export type VehicleConfigurationEnum = 'rigid' | 'articulated' | 'centre axle drawbar' | 'semi-car transporter' | 'semi-trailer' | 'low loader' | 'other' | 'drawbar' | 'four-in-line' | 'dolly' | 'full drawbar'; - export const VehicleConfigurationEnum = { - Rigid: 'rigid' as VehicleConfigurationEnum, - Articulated: 'articulated' as VehicleConfigurationEnum, - CentreAxleDrawbar: 'centre axle drawbar' as VehicleConfigurationEnum, - SemiCarTransporter: 'semi-car transporter' as VehicleConfigurationEnum, - SemiTrailer: 'semi-trailer' as VehicleConfigurationEnum, - LowLoader: 'low loader' as VehicleConfigurationEnum, - Other: 'other' as VehicleConfigurationEnum, - Drawbar: 'drawbar' as VehicleConfigurationEnum, - FourInLine: 'four-in-line' as VehicleConfigurationEnum, - Dolly: 'dolly' as VehicleConfigurationEnum, - FullDrawbar: 'full drawbar' as VehicleConfigurationEnum - }; - export type OdometerReadingUnitsEnum = 'kilometres' | 'miles'; - export const OdometerReadingUnitsEnum = { - Kilometres: 'kilometres' as OdometerReadingUnitsEnum, - Miles: 'miles' as OdometerReadingUnitsEnum - }; - export type EuVehicleCategoryEnum = 'm1' | 'm2' | 'm3' | 'n1' | 'n2' | 'n3' | 'o1' | 'o2' | 'o3' | 'o4' | 'l1e-a' | 'l1e' | 'l2e' | 'l3e' | 'l4e' | 'l5e' | 'l6e' | 'l7e'; - export const EuVehicleCategoryEnum = { - M1: 'm1' as EuVehicleCategoryEnum, - M2: 'm2' as EuVehicleCategoryEnum, - M3: 'm3' as EuVehicleCategoryEnum, - N1: 'n1' as EuVehicleCategoryEnum, - N2: 'n2' as EuVehicleCategoryEnum, - N3: 'n3' as EuVehicleCategoryEnum, - O1: 'o1' as EuVehicleCategoryEnum, - O2: 'o2' as EuVehicleCategoryEnum, - O3: 'o3' as EuVehicleCategoryEnum, - O4: 'o4' as EuVehicleCategoryEnum, - L1eA: 'l1e-a' as EuVehicleCategoryEnum, - L1e: 'l1e' as EuVehicleCategoryEnum, - L2e: 'l2e' as EuVehicleCategoryEnum, - L3e: 'l3e' as EuVehicleCategoryEnum, - L4e: 'l4e' as EuVehicleCategoryEnum, - L5e: 'l5e' as EuVehicleCategoryEnum, - L6e: 'l6e' as EuVehicleCategoryEnum, - L7e: 'l7e' as EuVehicleCategoryEnum - }; - export type VehicleSizeEnum = 'large' | 'small'; - export const VehicleSizeEnum = { - Large: 'large' as VehicleSizeEnum, - Small: 'small' as VehicleSizeEnum - }; -} \ No newline at end of file + export type TestVersionEnum = 'current' | 'archived'; + export const TestVersionEnum = { + Current: 'current' as TestVersionEnum, + Archived: 'archived' as TestVersionEnum, + }; + export type TestStationTypeEnum = 'atf' | 'gvts' | 'hq'; + export const TestStationTypeEnum = { + Atf: 'atf' as TestStationTypeEnum, + Gvts: 'gvts' as TestStationTypeEnum, + Hq: 'hq' as TestStationTypeEnum, + }; + export type TestStatusEnum = 'submitted' | 'cancelled'; + export const TestStatusEnum = { + Submitted: 'submitted' as TestStatusEnum, + Cancelled: 'cancelled' as TestStatusEnum, + }; + export type VehicleTypeEnum = 'psv' | 'hgv' | 'trl' | 'car' | 'lgv' | 'motorcycle'; + export const VehicleTypeEnum = { + Psv: 'psv' as VehicleTypeEnum, + Hgv: 'hgv' as VehicleTypeEnum, + Trl: 'trl' as VehicleTypeEnum, + Car: 'car' as VehicleTypeEnum, + Lgv: 'lgv' as VehicleTypeEnum, + Motorcycle: 'motorcycle' as VehicleTypeEnum, + }; + export type VehicleConfigurationEnum = + | 'rigid' + | 'articulated' + | 'centre axle drawbar' + | 'semi-car transporter' + | 'semi-trailer' + | 'low loader' + | 'other' + | 'drawbar' + | 'four-in-line' + | 'dolly' + | 'full drawbar'; + export const VehicleConfigurationEnum = { + Rigid: 'rigid' as VehicleConfigurationEnum, + Articulated: 'articulated' as VehicleConfigurationEnum, + CentreAxleDrawbar: 'centre axle drawbar' as VehicleConfigurationEnum, + SemiCarTransporter: 'semi-car transporter' as VehicleConfigurationEnum, + SemiTrailer: 'semi-trailer' as VehicleConfigurationEnum, + LowLoader: 'low loader' as VehicleConfigurationEnum, + Other: 'other' as VehicleConfigurationEnum, + Drawbar: 'drawbar' as VehicleConfigurationEnum, + FourInLine: 'four-in-line' as VehicleConfigurationEnum, + Dolly: 'dolly' as VehicleConfigurationEnum, + FullDrawbar: 'full drawbar' as VehicleConfigurationEnum, + }; + export type OdometerReadingUnitsEnum = 'kilometres' | 'miles'; + export const OdometerReadingUnitsEnum = { + Kilometres: 'kilometres' as OdometerReadingUnitsEnum, + Miles: 'miles' as OdometerReadingUnitsEnum, + }; + export type EuVehicleCategoryEnum = + | 'm1' + | 'm2' + | 'm3' + | 'n1' + | 'n2' + | 'n3' + | 'o1' + | 'o2' + | 'o3' + | 'o4' + | 'l1e-a' + | 'l1e' + | 'l2e' + | 'l3e' + | 'l4e' + | 'l5e' + | 'l6e' + | 'l7e'; + export const EuVehicleCategoryEnum = { + M1: 'm1' as EuVehicleCategoryEnum, + M2: 'm2' as EuVehicleCategoryEnum, + M3: 'm3' as EuVehicleCategoryEnum, + N1: 'n1' as EuVehicleCategoryEnum, + N2: 'n2' as EuVehicleCategoryEnum, + N3: 'n3' as EuVehicleCategoryEnum, + O1: 'o1' as EuVehicleCategoryEnum, + O2: 'o2' as EuVehicleCategoryEnum, + O3: 'o3' as EuVehicleCategoryEnum, + O4: 'o4' as EuVehicleCategoryEnum, + L1eA: 'l1e-a' as EuVehicleCategoryEnum, + L1e: 'l1e' as EuVehicleCategoryEnum, + L2e: 'l2e' as EuVehicleCategoryEnum, + L3e: 'l3e' as EuVehicleCategoryEnum, + L4e: 'l4e' as EuVehicleCategoryEnum, + L5e: 'l5e' as EuVehicleCategoryEnum, + L6e: 'l6e' as EuVehicleCategoryEnum, + L7e: 'l7e' as EuVehicleCategoryEnum, + }; + export type VehicleSizeEnum = 'large' | 'small'; + export const VehicleSizeEnum = { + Large: 'large' as VehicleSizeEnum, + Small: 'small' as VehicleSizeEnum, + }; +} diff --git a/src/app/api/test-results/model/completeTestResultsVehicleClass.ts b/src/app/api/test-results/model/completeTestResultsVehicleClass.ts index fa049e3663..f9efbd425b 100644 --- a/src/app/api/test-results/model/completeTestResultsVehicleClass.ts +++ b/src/app/api/test-results/model/completeTestResultsVehicleClass.ts @@ -12,37 +12,48 @@ /** * Mandatory only for motorcycles. 2 = MotorBikes over 200cc or with a sidecar, N = Not Applicable, S = Small PSV i.e less than or equal to 22 seats, 1 = Motorbikes upto 200cc, T = Trailer, L = LARGE PSV (ie. greater than 23 seats), 3 = 3 wheelers, V = Heavy Goods Vehicle */ -export interface CompleteTestResultsVehicleClass { - code?: CompleteTestResultsVehicleClass.CodeEnum; - description?: CompleteTestResultsVehicleClass.DescriptionEnum; +export interface CompleteTestResultsVehicleClass { + code?: CompleteTestResultsVehicleClass.CodeEnum; + description?: CompleteTestResultsVehicleClass.DescriptionEnum; } export namespace CompleteTestResultsVehicleClass { - export type CodeEnum = '2' | 'n' | 's' | '1' | 't' | 'l' | '3' | 'v' | '4' | '7' | '5'; - export const CodeEnum = { - _2: '2' as CodeEnum, - N: 'n' as CodeEnum, - S: 's' as CodeEnum, - _1: '1' as CodeEnum, - T: 't' as CodeEnum, - L: 'l' as CodeEnum, - _3: '3' as CodeEnum, - V: 'v' as CodeEnum, - _4: '4' as CodeEnum, - _7: '7' as CodeEnum, - _5: '5' as CodeEnum, - }; - export type DescriptionEnum = 'motorbikes over 200cc or with a sidecar' | 'not applicable' | 'small psv (ie: less than or equal to 22 seats)' | 'motorbikes up to 200cc' | 'trailer' | 'large psv(ie: greater than 23 seats)' | '3 wheelers' | 'heavy goods vehicle' | 'MOT class 4' | 'MOT class 7' | 'MOT class 5'; - export const DescriptionEnum = { - MotorbikesOver200ccOrWithASidecar: 'motorbikes over 200cc or with a sidecar' as DescriptionEnum, - NotApplicable: 'not applicable' as DescriptionEnum, - SmallPsvIeLessThanOrEqualTo22Seats: 'small psv (ie: less than or equal to 22 seats)' as DescriptionEnum, - MotorbikesUpTo200cc: 'motorbikes up to 200cc' as DescriptionEnum, - Trailer: 'trailer' as DescriptionEnum, - LargePsvIeGreaterThan23Seats: 'large psv(ie: greater than 23 seats)' as DescriptionEnum, - _3Wheelers: '3 wheelers' as DescriptionEnum, - HeavyGoodsVehicle: 'heavy goods vehicle' as DescriptionEnum, - MOTClass4: 'MOT class 4' as DescriptionEnum, - MOTClass7: 'MOT class 7' as DescriptionEnum, - MOTClass5: 'MOT class 5' as DescriptionEnum, - }; -} \ No newline at end of file + export type CodeEnum = '2' | 'n' | 's' | '1' | 't' | 'l' | '3' | 'v' | '4' | '7' | '5'; + export const CodeEnum = { + _2: '2' as CodeEnum, + N: 'n' as CodeEnum, + S: 's' as CodeEnum, + _1: '1' as CodeEnum, + T: 't' as CodeEnum, + L: 'l' as CodeEnum, + _3: '3' as CodeEnum, + V: 'v' as CodeEnum, + _4: '4' as CodeEnum, + _7: '7' as CodeEnum, + _5: '5' as CodeEnum, + }; + export type DescriptionEnum = + | 'motorbikes over 200cc or with a sidecar' + | 'not applicable' + | 'small psv (ie: less than or equal to 22 seats)' + | 'motorbikes up to 200cc' + | 'trailer' + | 'large psv(ie: greater than 23 seats)' + | '3 wheelers' + | 'heavy goods vehicle' + | 'MOT class 4' + | 'MOT class 7' + | 'MOT class 5'; + export const DescriptionEnum = { + MotorbikesOver200ccOrWithASidecar: 'motorbikes over 200cc or with a sidecar' as DescriptionEnum, + NotApplicable: 'not applicable' as DescriptionEnum, + SmallPsvIeLessThanOrEqualTo22Seats: 'small psv (ie: less than or equal to 22 seats)' as DescriptionEnum, + MotorbikesUpTo200cc: 'motorbikes up to 200cc' as DescriptionEnum, + Trailer: 'trailer' as DescriptionEnum, + LargePsvIeGreaterThan23Seats: 'large psv(ie: greater than 23 seats)' as DescriptionEnum, + _3Wheelers: '3 wheelers' as DescriptionEnum, + HeavyGoodsVehicle: 'heavy goods vehicle' as DescriptionEnum, + MOTClass4: 'MOT class 4' as DescriptionEnum, + MOTClass7: 'MOT class 7' as DescriptionEnum, + MOTClass5: 'MOT class 5' as DescriptionEnum, + }; +} diff --git a/src/app/api/test-results/model/customDefect.ts b/src/app/api/test-results/model/customDefect.ts index aab28f500a..4e6823c024 100644 --- a/src/app/api/test-results/model/customDefect.ts +++ b/src/app/api/test-results/model/customDefect.ts @@ -9,8 +9,8 @@ * Do not edit the class manually. */ -export interface CustomDefect { - referenceNumber?: string; - defectName?: string; - defectNotes?: string; -} \ No newline at end of file +export interface CustomDefect { + referenceNumber?: string; + defectName?: string; + defectNotes?: string; +} diff --git a/src/app/api/test-results/model/customDefects.ts b/src/app/api/test-results/model/customDefects.ts index 65b545a8aa..a306d4e1a1 100644 --- a/src/app/api/test-results/model/customDefects.ts +++ b/src/app/api/test-results/model/customDefects.ts @@ -10,5 +10,4 @@ */ import { CustomDefect } from './customDefect'; -export interface CustomDefects extends Array { -} \ No newline at end of file +export interface CustomDefects extends Array {} diff --git a/src/app/api/test-results/model/defect.ts b/src/app/api/test-results/model/defect.ts index f7c2885e2a..78918ffdf0 100644 --- a/src/app/api/test-results/model/defect.ts +++ b/src/app/api/test-results/model/defect.ts @@ -10,30 +10,30 @@ */ import { DefectAdditionalInformation } from './defectAdditionalInformation'; -export interface Defect { - imNumber?: number; - imDescription?: string; - additionalInformation?: DefectAdditionalInformation; - itemNumber?: number; - itemDescription?: string; - deficiencyRef?: string; - deficiencyId?: string; - deficiencySubId?: string; - /** - * It is mandatory for both Submitted or Cancelled tests. It is only nullable in the DB for the migration purposes. - */ - deficiencyCategory?: Defect.DeficiencyCategoryEnum; - deficiencyText?: string; - stdForProhibition?: boolean; - prs?: boolean; - prohibitionIssued?: boolean; +export interface Defect { + imNumber?: number; + imDescription?: string; + additionalInformation?: DefectAdditionalInformation; + itemNumber?: number; + itemDescription?: string; + deficiencyRef?: string; + deficiencyId?: string; + deficiencySubId?: string; + /** + * It is mandatory for both Submitted or Cancelled tests. It is only nullable in the DB for the migration purposes. + */ + deficiencyCategory?: Defect.DeficiencyCategoryEnum; + deficiencyText?: string; + stdForProhibition?: boolean; + prs?: boolean; + prohibitionIssued?: boolean; } export namespace Defect { - export type DeficiencyCategoryEnum = 'advisory' | 'dangerous' | 'major' | 'minor'; - export const DeficiencyCategoryEnum = { - Advisory: 'advisory' as DeficiencyCategoryEnum, - Dangerous: 'dangerous' as DeficiencyCategoryEnum, - Major: 'major' as DeficiencyCategoryEnum, - Minor: 'minor' as DeficiencyCategoryEnum - }; -} \ No newline at end of file + export type DeficiencyCategoryEnum = 'advisory' | 'dangerous' | 'major' | 'minor'; + export const DeficiencyCategoryEnum = { + Advisory: 'advisory' as DeficiencyCategoryEnum, + Dangerous: 'dangerous' as DeficiencyCategoryEnum, + Major: 'major' as DeficiencyCategoryEnum, + Minor: 'minor' as DeficiencyCategoryEnum, + }; +} diff --git a/src/app/api/test-results/model/defectAdditionalInformation.ts b/src/app/api/test-results/model/defectAdditionalInformation.ts index 27ffd34e13..a94ee2b6b8 100644 --- a/src/app/api/test-results/model/defectAdditionalInformation.ts +++ b/src/app/api/test-results/model/defectAdditionalInformation.ts @@ -10,7 +10,7 @@ */ import { DefectAdditionalInformationLocation } from './defectAdditionalInformationLocation'; -export interface DefectAdditionalInformation { - location?: DefectAdditionalInformationLocation; - notes?: string; -} \ No newline at end of file +export interface DefectAdditionalInformation { + location?: DefectAdditionalInformationLocation; + notes?: string; +} diff --git a/src/app/api/test-results/model/defectAdditionalInformationLocation.ts b/src/app/api/test-results/model/defectAdditionalInformationLocation.ts index 1c4104f52d..6cb1472202 100644 --- a/src/app/api/test-results/model/defectAdditionalInformationLocation.ts +++ b/src/app/api/test-results/model/defectAdditionalInformationLocation.ts @@ -9,35 +9,35 @@ * Do not edit the class manually. */ -export interface DefectAdditionalInformationLocation { - vertical?: DefectAdditionalInformationLocation.VerticalEnum; - horizontal?: DefectAdditionalInformationLocation.HorizontalEnum; - lateral?: DefectAdditionalInformationLocation.LateralEnum; - longitudinal?: DefectAdditionalInformationLocation.LongitudinalEnum; - rowNumber?: number; - seatNumber?: number; - axleNumber?: number; +export interface DefectAdditionalInformationLocation { + vertical?: DefectAdditionalInformationLocation.VerticalEnum; + horizontal?: DefectAdditionalInformationLocation.HorizontalEnum; + lateral?: DefectAdditionalInformationLocation.LateralEnum; + longitudinal?: DefectAdditionalInformationLocation.LongitudinalEnum; + rowNumber?: number; + seatNumber?: number; + axleNumber?: number; } export namespace DefectAdditionalInformationLocation { - export type VerticalEnum = 'upper' | 'lower'; - export const VerticalEnum = { - Upper: 'upper' as VerticalEnum, - Lower: 'lower' as VerticalEnum - }; - export type HorizontalEnum = 'inner' | 'outer'; - export const HorizontalEnum = { - Inner: 'inner' as HorizontalEnum, - Outer: 'outer' as HorizontalEnum - }; - export type LateralEnum = 'nearside' | 'centre' | 'offside'; - export const LateralEnum = { - Nearside: 'nearside' as LateralEnum, - Centre: 'centre' as LateralEnum, - Offside: 'offside' as LateralEnum - }; - export type LongitudinalEnum = 'front' | 'rear'; - export const LongitudinalEnum = { - Front: 'front' as LongitudinalEnum, - Rear: 'rear' as LongitudinalEnum - }; -} \ No newline at end of file + export type VerticalEnum = 'upper' | 'lower'; + export const VerticalEnum = { + Upper: 'upper' as VerticalEnum, + Lower: 'lower' as VerticalEnum, + }; + export type HorizontalEnum = 'inner' | 'outer'; + export const HorizontalEnum = { + Inner: 'inner' as HorizontalEnum, + Outer: 'outer' as HorizontalEnum, + }; + export type LateralEnum = 'nearside' | 'centre' | 'offside'; + export const LateralEnum = { + Nearside: 'nearside' as LateralEnum, + Centre: 'centre' as LateralEnum, + Offside: 'offside' as LateralEnum, + }; + export type LongitudinalEnum = 'front' | 'rear'; + export const LongitudinalEnum = { + Front: 'front' as LongitudinalEnum, + Rear: 'rear' as LongitudinalEnum, + }; +} diff --git a/src/app/api/test-results/model/defects.ts b/src/app/api/test-results/model/defects.ts index bf6bfd9a68..f7423b4d7b 100644 --- a/src/app/api/test-results/model/defects.ts +++ b/src/app/api/test-results/model/defects.ts @@ -10,5 +10,4 @@ */ import { Defect } from './defect'; -export interface Defects extends Array { -} \ No newline at end of file +export interface Defects extends Array {} diff --git a/src/app/api/test-results/model/testResults.ts b/src/app/api/test-results/model/testResults.ts index 8d16693b18..30169ac46a 100644 --- a/src/app/api/test-results/model/testResults.ts +++ b/src/app/api/test-results/model/testResults.ts @@ -10,5 +10,4 @@ */ import { CompleteTestResults } from './completeTestResults'; -export interface TestResults extends Array { -} \ No newline at end of file +export interface TestResults extends Array {} diff --git a/src/app/api/test-results/model/testTypeRecords.ts b/src/app/api/test-results/model/testTypeRecords.ts index f9f6ae0670..dc1a3c4736 100644 --- a/src/app/api/test-results/model/testTypeRecords.ts +++ b/src/app/api/test-results/model/testTypeRecords.ts @@ -9,5 +9,4 @@ * Do not edit the class manually. */ -export interface TestTypeRecords { -} \ No newline at end of file +export type TestTypeRecords = {}; diff --git a/src/app/api/test-results/model/testTypeResults.ts b/src/app/api/test-results/model/testTypeResults.ts index bcd8933add..b5be1b5b43 100644 --- a/src/app/api/test-results/model/testTypeResults.ts +++ b/src/app/api/test-results/model/testTypeResults.ts @@ -12,130 +12,137 @@ import { CustomDefects } from './customDefects'; import { Defects } from './defects'; import { TestTypeResultsModType } from './testTypeResultsModType'; -export interface TestTypeResults { - /** - * Not sent from FE, calculated in the BE. - */ - createdAt?: Date; - /** - * Not sent from FE, calculated in the BE. - */ - lastUpdatedAt?: Date; - /** - * Not sent from FE, calculated in the BE. - */ - deletionFlag?: boolean; - /** - * Not sent from FE, calculated in the BE. - */ - testCode?: string; - testTypeName?: string; - name?: string; - testTypeId?: string; - /** - * Not sent from FE, calculated in the BE. - */ - testNumber?: string; - certificateNumber?: string; - secondaryCertificateNumber?: string; - /** - * Not sent from FE, calculated in the BE. - */ - certificateLink?: string; - /** - * Sent form FE only for LEC tests. For the rest of the test types it is not sent from FE, and calculated in the BE. - */ - testExpiryDate?: Date; - /** - * Not sent from FE, calculated in the BE. - */ - testAnniversaryDate?: Date; - testTypeStartTimestamp?: Date; - /** - * Nullable only for Cancelled tests. - */ - testTypeEndTimestamp?: Date; - /** - * Sent from FE. Used to determine which test-type was updated/archived - */ - statusUpdatedFlag?: boolean; - /** - * mandatory for PSV only, not applicable for HGV and TRL - */ - numberOfSeatbeltsFitted?: number; - /** - * mandatory for PSV only, not applicable for HGV and TRL - */ - lastSeatbeltInstallationCheckDate?: string; - /** - * mandatory for PSV only, not applicable for HGV and TRL - */ - seatbeltInstallationCheckDate?: boolean; - /** - * Nullable only for Cancelled tests. - */ - testResult?: TestTypeResults.TestResultEnum; - prohibitionIssued?: boolean; - /** - * Required for Abandoned tests. - */ - reasonForAbandoning?: string; - additionalNotesRecorded?: string; - additionalCommentsForAbandon?: string; - modType?: TestTypeResultsModType; - /** - * Used only for LEC tests. - */ - emissionStandard?: TestTypeResults.EmissionStandardEnum; - /** - * Used only for LEC tests. - */ - fuelType?: TestTypeResults.FuelTypeEnum; - /** - * Used only for LEC tests. - */ - particulateTrapFitted?: string; - /** - * Used only for LEC tests. - */ - particulateTrapSerialNumber?: string; - /** - * Used only for LEC tests. - */ - modificationTypeUsed?: string; - /** - * Used only for LEC tests. - */ - smokeTestKLimitApplied?: string; - defects?: Defects; - customDefects?: CustomDefects; +export interface TestTypeResults { + /** + * Not sent from FE, calculated in the BE. + */ + createdAt?: Date; + /** + * Not sent from FE, calculated in the BE. + */ + lastUpdatedAt?: Date; + /** + * Not sent from FE, calculated in the BE. + */ + deletionFlag?: boolean; + /** + * Not sent from FE, calculated in the BE. + */ + testCode?: string; + testTypeName?: string; + name?: string; + testTypeId?: string; + /** + * Not sent from FE, calculated in the BE. + */ + testNumber?: string; + certificateNumber?: string; + secondaryCertificateNumber?: string; + /** + * Not sent from FE, calculated in the BE. + */ + certificateLink?: string; + /** + * Sent form FE only for LEC tests. For the rest of the test types it is not sent from FE, and calculated in the BE. + */ + testExpiryDate?: Date; + /** + * Not sent from FE, calculated in the BE. + */ + testAnniversaryDate?: Date; + testTypeStartTimestamp?: Date; + /** + * Nullable only for Cancelled tests. + */ + testTypeEndTimestamp?: Date; + /** + * Sent from FE. Used to determine which test-type was updated/archived + */ + statusUpdatedFlag?: boolean; + /** + * mandatory for PSV only, not applicable for HGV and TRL + */ + numberOfSeatbeltsFitted?: number; + /** + * mandatory for PSV only, not applicable for HGV and TRL + */ + lastSeatbeltInstallationCheckDate?: string; + /** + * mandatory for PSV only, not applicable for HGV and TRL + */ + seatbeltInstallationCheckDate?: boolean; + /** + * Nullable only for Cancelled tests. + */ + testResult?: TestTypeResults.TestResultEnum; + prohibitionIssued?: boolean; + /** + * Required for Abandoned tests. + */ + reasonForAbandoning?: string; + additionalNotesRecorded?: string; + additionalCommentsForAbandon?: string; + modType?: TestTypeResultsModType; + /** + * Used only for LEC tests. + */ + emissionStandard?: TestTypeResults.EmissionStandardEnum; + /** + * Used only for LEC tests. + */ + fuelType?: TestTypeResults.FuelTypeEnum; + /** + * Used only for LEC tests. + */ + particulateTrapFitted?: string; + /** + * Used only for LEC tests. + */ + particulateTrapSerialNumber?: string; + /** + * Used only for LEC tests. + */ + modificationTypeUsed?: string; + /** + * Used only for LEC tests. + */ + smokeTestKLimitApplied?: string; + defects?: Defects; + customDefects?: CustomDefects; } export namespace TestTypeResults { - export type TestResultEnum = 'fail' | 'pass' | 'prs' | 'abandoned'; - export const TestResultEnum = { - Fail: 'fail' as TestResultEnum, - Pass: 'pass' as TestResultEnum, - Prs: 'prs' as TestResultEnum, - Abandoned: 'abandoned' as TestResultEnum - }; - export type EmissionStandardEnum = '0.10 g/kWh Euro 3 PM' | '0.03 g/kWh Euro IV PM' | 'Euro 3' | 'Euro 4' | 'Euro 6' | 'Euro VI' | 'Full Electric'; - export const EmissionStandardEnum = { - _010GkWhEuro3PM: '0.10 g/kWh Euro 3 PM' as EmissionStandardEnum, - _003GkWhEuroIVPM: '0.03 g/kWh Euro IV PM' as EmissionStandardEnum, - Euro3: 'Euro 3' as EmissionStandardEnum, - Euro4: 'Euro 4' as EmissionStandardEnum, - Euro6: 'Euro 6' as EmissionStandardEnum, - EuroVI: 'Euro VI' as EmissionStandardEnum, - FullElectric: 'Full Electric' as EmissionStandardEnum - }; - export type FuelTypeEnum = 'diesel' | 'gas-cng' | 'gas-lng' | 'gas-lpg' | 'fuel cell' | 'petrol' | 'full electric'; - export const FuelTypeEnum = { - Diesel: 'diesel' as FuelTypeEnum, - GasCng: 'gas-cng' as FuelTypeEnum, - GasLng: 'gas-lng' as FuelTypeEnum, - GasLpg: 'gas-lpg' as FuelTypeEnum, - FuelCell: 'fuel cell' as FuelTypeEnum, - Petrol: 'petrol' as FuelTypeEnum, - FullElectric: 'full electric' as FuelTypeEnum - }; -} \ No newline at end of file + export type TestResultEnum = 'fail' | 'pass' | 'prs' | 'abandoned'; + export const TestResultEnum = { + Fail: 'fail' as TestResultEnum, + Pass: 'pass' as TestResultEnum, + Prs: 'prs' as TestResultEnum, + Abandoned: 'abandoned' as TestResultEnum, + }; + export type EmissionStandardEnum = + | '0.10 g/kWh Euro 3 PM' + | '0.03 g/kWh Euro IV PM' + | 'Euro 3' + | 'Euro 4' + | 'Euro 6' + | 'Euro VI' + | 'Full Electric'; + export const EmissionStandardEnum = { + _010GkWhEuro3PM: '0.10 g/kWh Euro 3 PM' as EmissionStandardEnum, + _003GkWhEuroIVPM: '0.03 g/kWh Euro IV PM' as EmissionStandardEnum, + Euro3: 'Euro 3' as EmissionStandardEnum, + Euro4: 'Euro 4' as EmissionStandardEnum, + Euro6: 'Euro 6' as EmissionStandardEnum, + EuroVI: 'Euro VI' as EmissionStandardEnum, + FullElectric: 'Full Electric' as EmissionStandardEnum, + }; + export type FuelTypeEnum = 'diesel' | 'gas-cng' | 'gas-lng' | 'gas-lpg' | 'fuel cell' | 'petrol' | 'full electric'; + export const FuelTypeEnum = { + Diesel: 'diesel' as FuelTypeEnum, + GasCng: 'gas-cng' as FuelTypeEnum, + GasLng: 'gas-lng' as FuelTypeEnum, + GasLpg: 'gas-lpg' as FuelTypeEnum, + FuelCell: 'fuel cell' as FuelTypeEnum, + Petrol: 'petrol' as FuelTypeEnum, + FullElectric: 'full electric' as FuelTypeEnum, + }; +} diff --git a/src/app/api/test-results/model/testTypeResultsModType.ts b/src/app/api/test-results/model/testTypeResultsModType.ts index 9044919191..553a0bdcb0 100644 --- a/src/app/api/test-results/model/testTypeResultsModType.ts +++ b/src/app/api/test-results/model/testTypeResultsModType.ts @@ -12,21 +12,21 @@ /** * Used only for LEC tests. p = particulate trap, m = modification or change of engine, g = gas engine. */ -export interface TestTypeResultsModType { - code?: TestTypeResultsModType.CodeEnum; - description?: TestTypeResultsModType.DescriptionEnum; +export interface TestTypeResultsModType { + code?: TestTypeResultsModType.CodeEnum; + description?: TestTypeResultsModType.DescriptionEnum; } export namespace TestTypeResultsModType { - export type CodeEnum = 'p' | 'm' | 'g'; - export const CodeEnum = { - P: 'p' as CodeEnum, - M: 'm' as CodeEnum, - G: 'g' as CodeEnum - }; - export type DescriptionEnum = 'particulate trap' | 'modification or change of engine' | 'gas engine'; - export const DescriptionEnum = { - ParticulateTrap: 'particulate trap' as DescriptionEnum, - ModificationOrChangeOfEngine: 'modification or change of engine' as DescriptionEnum, - GasEngine: 'gas engine' as DescriptionEnum - }; -} \ No newline at end of file + export type CodeEnum = 'p' | 'm' | 'g'; + export const CodeEnum = { + P: 'p' as CodeEnum, + M: 'm' as CodeEnum, + G: 'g' as CodeEnum, + }; + export type DescriptionEnum = 'particulate trap' | 'modification or change of engine' | 'gas engine'; + export const DescriptionEnum = { + ParticulateTrap: 'particulate trap' as DescriptionEnum, + ModificationOrChangeOfEngine: 'modification or change of engine' as DescriptionEnum, + GasEngine: 'gas engine' as DescriptionEnum, + }; +} diff --git a/src/app/api/test-results/model/testTypes.ts b/src/app/api/test-results/model/testTypes.ts index a10aae64b9..75a4b202b7 100644 --- a/src/app/api/test-results/model/testTypes.ts +++ b/src/app/api/test-results/model/testTypes.ts @@ -13,5 +13,4 @@ import { TestTypeRecords } from './testTypeRecords'; /** * Nullable only for Cancelled tests. */ -export interface TestTypes extends Array { -} \ No newline at end of file +export interface TestTypes extends Array {} diff --git a/src/app/api/test-results/variables.ts b/src/app/api/test-results/variables.ts index 6fe58549f3..9bae45f800 100644 --- a/src/app/api/test-results/variables.ts +++ b/src/app/api/test-results/variables.ts @@ -2,8 +2,8 @@ import { InjectionToken } from '@angular/core'; export const BASE_PATH = new InjectionToken('basePath'); export const COLLECTION_FORMATS = { - 'csv': ',', - 'tsv': ' ', - 'ssv': ' ', - 'pipes': '|' -} + csv: ',', + tsv: ' ', + ssv: ' ', + pipes: '|', +}; diff --git a/src/app/api/test-types/api.module.ts b/src/app/api/test-types/api.module.ts index a93ef1975d..44bae5c609 100644 --- a/src/app/api/test-types/api.module.ts +++ b/src/app/api/test-types/api.module.ts @@ -1,33 +1,32 @@ -import { NgModule, ModuleWithProviders, SkipSelf, Optional } from '@angular/core'; -import { Configuration } from './configuration'; import { HttpClient } from '@angular/common/http'; - +import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; +import { Configuration } from './configuration'; import { TestTypesService } from './api/testTypes.service'; @NgModule({ - imports: [], - declarations: [], - exports: [], - providers: [ - TestTypesService ] + imports: [], + declarations: [], + exports: [], + providers: [TestTypesService], }) export class ApiModule { - public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { - return { - ngModule: ApiModule, - providers: [ { provide: Configuration, useFactory: configurationFactory } ] - }; - } + public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { + return { + ngModule: ApiModule, + providers: [{ provide: Configuration, useFactory: configurationFactory }], + }; + } - constructor( @Optional() @SkipSelf() parentModule: ApiModule, - @Optional() http: HttpClient) { - if (parentModule) { - throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); - } - if (!http) { - throw new Error('You need to import the HttpClientModule in your AppModule! \n' + - 'See also https://github.com/angular/angular/issues/20575'); - } - } + constructor(@Optional() @SkipSelf() parentModule: ApiModule, @Optional() http: HttpClient) { + if (parentModule) { + throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); + } + if (!http) { + throw new Error( + 'You need to import the HttpClientModule in your AppModule! \n' + + 'See also https://github.com/angular/angular/issues/20575' + ); + } + } } diff --git a/src/app/api/test-types/api/testTypes.service.ts b/src/app/api/test-types/api/testTypes.service.ts index 8e1b6eeb04..278ae06052 100644 --- a/src/app/api/test-types/api/testTypes.service.ts +++ b/src/app/api/test-types/api/testTypes.service.ts @@ -7,207 +7,252 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - *//* tslint:disable:no-unused-variable member-ordering */ + */ /* tslint:disable:no-unused-variable member-ordering */ -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpHeaders, HttpParams, - HttpResponse, HttpEvent } from '@angular/common/http'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; +import { Inject, Injectable, Optional } from '@angular/core'; +import { CustomHttpUrlEncodingCodec } from '../encoder'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { TestTypeInfo } from '../model/testTypeInfo'; import { TestTypesTaxonomy } from '../model/testTypesTaxonomy'; -import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; -import { Configuration } from '../configuration'; - +import { Configuration } from '../configuration'; +import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; @Injectable() export class TestTypesService { - - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - - /** - * Return test types - * This endpoint will return all the data for test types based on filters provided. By default it will return all testTypes which don't have a typeOfTest field. - * @param typeOfTest It is used to filter test types based on the given typeOfTest. Note that sending the query parameter will also return the test types without a tag. - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public getTestTypes(typeOfTest?: string, observe?: 'body', reportProgress?: boolean): Observable; - public getTestTypes(typeOfTest?: string, observe?: 'response', reportProgress?: boolean): Observable>; - public getTestTypes(typeOfTest?: string, observe?: 'events', reportProgress?: boolean): Observable>; - public getTestTypes(typeOfTest?: string, observe: any = 'body', reportProgress: boolean = false ): Observable { - - - let queryParameters = new HttpParams({encoder: new CustomHttpUrlEncodingCodec()}); - if (typeOfTest !== undefined && typeOfTest !== null) { - queryParameters = queryParameters.set('typeOfTest', typeOfTest); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); - } - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/json' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - ]; - - return this.httpClient.request('get',`${this.basePath}/test-types`, - { - params: queryParameters, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - - /** - * Return test type information by ID - * This endpoint will return data of the test types needed to be saved agains the test results. - * @param id - * @param fields - * @param vehicleType - * @param vehicleSize - * @param vehicleConfiguration - * @param vehicleAxles - * @param euVehicleCategory - * @param vehicleClass - * @param vehicleSubclass - * @param vehicleWheels - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public getTestTypesid(id: string, fields: Array, vehicleType: string, vehicleSize?: string, vehicleConfiguration?: string, vehicleAxles?: number, euVehicleCategory?: string, vehicleClass?: string, vehicleSubclass?: string, vehicleWheels?: number, observe?: 'body', reportProgress?: boolean): Observable; - public getTestTypesid(id: string, fields: Array, vehicleType: string, vehicleSize?: string, vehicleConfiguration?: string, vehicleAxles?: number, euVehicleCategory?: string, vehicleClass?: string, vehicleSubclass?: string, vehicleWheels?: number, observe?: 'response', reportProgress?: boolean): Observable>; - public getTestTypesid(id: string, fields: Array, vehicleType: string, vehicleSize?: string, vehicleConfiguration?: string, vehicleAxles?: number, euVehicleCategory?: string, vehicleClass?: string, vehicleSubclass?: string, vehicleWheels?: number, observe?: 'events', reportProgress?: boolean): Observable>; - public getTestTypesid(id: string, fields: Array, vehicleType: string, vehicleSize?: string, vehicleConfiguration?: string, vehicleAxles?: number, euVehicleCategory?: string, vehicleClass?: string, vehicleSubclass?: string, vehicleWheels?: number, observe: any = 'body', reportProgress: boolean = false ): Observable { - - if (id === null || id === undefined) { - throw new Error('Required parameter id was null or undefined when calling getTestTypesid.'); - } - - if (fields === null || fields === undefined) { - throw new Error('Required parameter fields was null or undefined when calling getTestTypesid.'); - } - - if (vehicleType === null || vehicleType === undefined) { - throw new Error('Required parameter vehicleType was null or undefined when calling getTestTypesid.'); - } - - - - - - - - - let queryParameters = new HttpParams({encoder: new CustomHttpUrlEncodingCodec()}); - if (fields) { - queryParameters = queryParameters.set('fields', fields.join(COLLECTION_FORMATS['csv'])); - } - if (vehicleType !== undefined && vehicleType !== null) { - queryParameters = queryParameters.set('vehicleType', vehicleType); - } - if (vehicleSize !== undefined && vehicleSize !== null) { - queryParameters = queryParameters.set('vehicleSize', vehicleSize); - } - if (vehicleConfiguration !== undefined && vehicleConfiguration !== null) { - queryParameters = queryParameters.set('vehicleConfiguration', vehicleConfiguration); - } - if (vehicleAxles !== undefined && vehicleAxles !== null) { - queryParameters = queryParameters.set('vehicleAxles', vehicleAxles); - } - if (euVehicleCategory !== undefined && euVehicleCategory !== null) { - queryParameters = queryParameters.set('euVehicleCategory', euVehicleCategory); - } - if (vehicleClass !== undefined && vehicleClass !== null) { - queryParameters = queryParameters.set('vehicleClass', vehicleClass); - } - if (vehicleSubclass !== undefined && vehicleSubclass !== null) { - queryParameters = queryParameters.set('vehicleSubclass', vehicleSubclass); - } - if (vehicleWheels !== undefined && vehicleWheels !== null) { - queryParameters = queryParameters.set('vehicleWheels', vehicleWheels); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); - } - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/json' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - ]; - - return this.httpClient.request('get',`${this.basePath}/test-types/${encodeURIComponent(String(id))}`, - { - params: queryParameters, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor( + protected httpClient: HttpClient, + @Optional() @Inject(BASE_PATH) basePath: string, + @Optional() configuration: Configuration + ) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + /** + * Return test types + * This endpoint will return all the data for test types based on filters provided. By default it will return all testTypes which don't have a typeOfTest field. + * @param typeOfTest It is used to filter test types based on the given typeOfTest. Note that sending the query parameter will also return the test types without a tag. + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public getTestTypes(typeOfTest?: string, observe?: 'body', reportProgress?: boolean): Observable; + public getTestTypes( + typeOfTest?: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public getTestTypes( + typeOfTest?: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public getTestTypes(typeOfTest?: string, observe: any = 'body', reportProgress = false): Observable { + let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); + if (typeOfTest !== undefined && typeOfTest !== null) { + queryParameters = queryParameters.set('typeOfTest', typeOfTest); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = []; + + return this.httpClient.request('get', `${this.basePath}/test-types`, { + params: queryParameters, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + }); + } + + /** + * Return test type information by ID + * This endpoint will return data of the test types needed to be saved agains the test results. + * @param id + * @param fields + * @param vehicleType + * @param vehicleSize + * @param vehicleConfiguration + * @param vehicleAxles + * @param euVehicleCategory + * @param vehicleClass + * @param vehicleSubclass + * @param vehicleWheels + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public getTestTypesid( + id: string, + fields: Array, + vehicleType: string, + vehicleSize?: string, + vehicleConfiguration?: string, + vehicleAxles?: number, + euVehicleCategory?: string, + vehicleClass?: string, + vehicleSubclass?: string, + vehicleWheels?: number, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public getTestTypesid( + id: string, + fields: Array, + vehicleType: string, + vehicleSize?: string, + vehicleConfiguration?: string, + vehicleAxles?: number, + euVehicleCategory?: string, + vehicleClass?: string, + vehicleSubclass?: string, + vehicleWheels?: number, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public getTestTypesid( + id: string, + fields: Array, + vehicleType: string, + vehicleSize?: string, + vehicleConfiguration?: string, + vehicleAxles?: number, + euVehicleCategory?: string, + vehicleClass?: string, + vehicleSubclass?: string, + vehicleWheels?: number, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public getTestTypesid( + id: string, + fields: Array, + vehicleType: string, + vehicleSize?: string, + vehicleConfiguration?: string, + vehicleAxles?: number, + euVehicleCategory?: string, + vehicleClass?: string, + vehicleSubclass?: string, + vehicleWheels?: number, + observe: any = 'body', + reportProgress = false + ): Observable { + if (id === null || id === undefined) { + throw new Error('Required parameter id was null or undefined when calling getTestTypesid.'); + } + + if (fields === null || fields === undefined) { + throw new Error('Required parameter fields was null or undefined when calling getTestTypesid.'); + } + + if (vehicleType === null || vehicleType === undefined) { + throw new Error('Required parameter vehicleType was null or undefined when calling getTestTypesid.'); + } + + let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); + if (fields) { + queryParameters = queryParameters.set('fields', fields.join(COLLECTION_FORMATS['csv'])); + } + if (vehicleType !== undefined && vehicleType !== null) { + queryParameters = queryParameters.set('vehicleType', vehicleType); + } + if (vehicleSize !== undefined && vehicleSize !== null) { + queryParameters = queryParameters.set('vehicleSize', vehicleSize); + } + if (vehicleConfiguration !== undefined && vehicleConfiguration !== null) { + queryParameters = queryParameters.set('vehicleConfiguration', vehicleConfiguration); + } + if (vehicleAxles !== undefined && vehicleAxles !== null) { + queryParameters = queryParameters.set('vehicleAxles', vehicleAxles); + } + if (euVehicleCategory !== undefined && euVehicleCategory !== null) { + queryParameters = queryParameters.set('euVehicleCategory', euVehicleCategory); + } + if (vehicleClass !== undefined && vehicleClass !== null) { + queryParameters = queryParameters.set('vehicleClass', vehicleClass); + } + if (vehicleSubclass !== undefined && vehicleSubclass !== null) { + queryParameters = queryParameters.set('vehicleSubclass', vehicleSubclass); + } + if (vehicleWheels !== undefined && vehicleWheels !== null) { + queryParameters = queryParameters.set('vehicleWheels', vehicleWheels); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = []; + + return this.httpClient.request( + 'get', + `${this.basePath}/test-types/${encodeURIComponent(String(id))}`, + { + params: queryParameters, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + } + ); + } } diff --git a/src/app/api/test-types/configuration.ts b/src/app/api/test-types/configuration.ts index 82e8458f39..698dce114c 100644 --- a/src/app/api/test-types/configuration.ts +++ b/src/app/api/test-types/configuration.ts @@ -1,79 +1,82 @@ export interface ConfigurationParameters { - apiKeys?: {[ key: string ]: string}; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: { [key: string]: string }; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; } export class Configuration { - apiKeys?: {[ key: string ]: string}; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: { [key: string]: string }; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; - constructor(configurationParameters: ConfigurationParameters = {}) { - this.apiKeys = configurationParameters.apiKeys; - this.username = configurationParameters.username; - this.password = configurationParameters.password; - this.accessToken = configurationParameters.accessToken; - this.basePath = configurationParameters.basePath; - this.withCredentials = configurationParameters.withCredentials; - } + constructor(configurationParameters: ConfigurationParameters = {}) { + this.apiKeys = configurationParameters.apiKeys; + this.username = configurationParameters.username; + this.password = configurationParameters.password; + this.accessToken = configurationParameters.accessToken; + this.basePath = configurationParameters.basePath; + this.withCredentials = configurationParameters.withCredentials; + } - /** - * Select the correct content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param contentTypes - the array of content types that are available for selection - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderContentType (contentTypes: string[]): string | undefined { - if (contentTypes.length == 0) { - return undefined; - } + /** + * Select the correct content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param contentTypes - the array of content types that are available for selection + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderContentType(contentTypes: string[]): string | undefined { + if (contentTypes.length == 0) { + return undefined; + } - let type = contentTypes.find(x => this.isJsonMime(x)); - if (type === undefined) { - return contentTypes[0]; - } - return type; - } + const type = contentTypes.find((x) => this.isJsonMime(x)); + if (type === undefined) { + return contentTypes[0]; + } + return type; + } - /** - * Select the correct accept content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param accepts - the array of content types that are available for selection. - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderAccept(accepts: string[]): string | undefined { - if (accepts.length == 0) { - return undefined; - } + /** + * Select the correct accept content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param accepts - the array of content types that are available for selection. + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderAccept(accepts: string[]): string | undefined { + if (accepts.length == 0) { + return undefined; + } - let type = accepts.find(x => this.isJsonMime(x)); - if (type === undefined) { - return accepts[0]; - } - return type; - } + const type = accepts.find((x) => this.isJsonMime(x)); + if (type === undefined) { + return accepts[0]; + } + return type; + } - /** - * Check if the given MIME is a JSON MIME. - * JSON MIME examples: - * application/json - * application/json; charset=UTF8 - * APPLICATION/JSON - * application/vnd.company+json - * @param mime - MIME (Multipurpose Internet Mail Extensions) - * @return True if the given MIME is JSON, false otherwise. - */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); - return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = /^(application\\/jnos | [^;\/ \t]+\; + \/[^ + \/ \t]+[+]json)[ \t]*( + .*)?$/i + return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } } diff --git a/src/app/api/test-types/encoder.ts b/src/app/api/test-types/encoder.ts index f506bfbea0..233fb78e4a 100644 --- a/src/app/api/test-types/encoder.ts +++ b/src/app/api/test-types/encoder.ts @@ -1,18 +1,17 @@ - import { HttpUrlEncodingCodec } from '@angular/common/http'; +import { HttpUrlEncodingCodec } from '@angular/common/http'; /** -* CustomHttpUrlEncodingCodec -* Fix plus sign (+) not encoding, so sent as blank space -* See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 -*/ + * CustomHttpUrlEncodingCodec + * Fix plus sign (+) not encoding, so sent as blank space + * See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 + */ export class CustomHttpUrlEncodingCodec extends HttpUrlEncodingCodec { - override encodeKey(k: string): string { - k = super.encodeKey(k); - return k.replace(/\+/gi, '%2B'); - } - override encodeValue(v: string): string { - v = super.encodeValue(v); - return v.replace(/\+/gi, '%2B'); - } + override encodeKey(k: string): string { + k = super.encodeKey(k); + return k.replace(/\+/gi, '%2B'); + } + override encodeValue(v: string): string { + v = super.encodeValue(v); + return v.replace(/\+/gi, '%2B'); + } } - diff --git a/src/app/api/test-types/index.ts b/src/app/api/test-types/index.ts index c312b70fa3..410623f1c9 100644 --- a/src/app/api/test-types/index.ts +++ b/src/app/api/test-types/index.ts @@ -2,4 +2,4 @@ export * from './api/api'; export * from './model/models'; export * from './variables'; export * from './configuration'; -export * from './api.module'; \ No newline at end of file +export * from './api.module'; diff --git a/src/app/api/test-types/model/testType.ts b/src/app/api/test-types/model/testType.ts index fb68cbc345..e29182543a 100644 --- a/src/app/api/test-types/model/testType.ts +++ b/src/app/api/test-types/model/testType.ts @@ -13,94 +13,94 @@ * Test type */ export interface TestType { - /** - * Unique identifier - */ - id: string; - /** - * The list of test type IDs or categories IDs, used to determine if two test types can be added as linked within the same test. - */ - linkedIds?: Array; - /** - * The list of suggested test types, used to determine suggested test types for psv, trl and hgv. - */ - suggestedTestTypeIds?: Array; - /** - * Name of the test type - */ - name: string; - /** - * Full name of the test type containing the entire path, having a business value - */ - testTypeName?: string; - /** - * Name to be displayed in the mobile app suggested next test type popup - */ - suggestedTestTypeDisplayName?: string; - /** - * Order in which this test type is displayed in the mobile app suggested next test type popup - */ - suggestedTestTypeDisplayOrder?: string; - /** - * Used to filter in test types with a specific typeOfTest, send as a query param in the request - */ - typeOfTest?: string; - /** - * This category is applying only to these vehicle types. The vehicle types should descend from its parent, but should not be necessarily the same - */ - forVehicleType: Array; - /** - * Used to filter test types that allow creating tests on Provisional Records - */ - forProvisionalStatus?: boolean; - /** - * Used to filter test types that allow creating tests on Provisional Records and not current - */ - forProvisionalStatusOnly?: boolean; - /** - * - * This category is applying only to these vehicle sizes. The vehicle sizes should descend from its parent, but should not be necessarily the same - */ - forVehicleSize?: Array; - /** - * This category is applying only to these vehicle configurations. The vehicle configurations should descend from its parent, but should not be necessarily the same - */ - forVehicleConfiguration?: Array; - /** - * This category is applying only to the vehicles with those number of axles. The vehicle number of axles should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any number of axles. - */ - forVehicleAxles?: Array; - /** - * This category is applying only to the vehicles with that eu category. The eu vehicle category should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any eu vehicle category. - */ - forEuVehicleCategory?: Array; - /** - * This category is applying only to the vehicles with that vehicle class. The vehicle class should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any vehicle class. - */ - forVehicleClass?: Array; - /** - * This category is applying only to the vehicles with that vehicle subclass. The vehicle subclass should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any vehicle subclass. - */ - forVehicleSubclass?: Array; - /** - * This category is applying only to the vehicles with those number of wheels. The vehicle number of wheels should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any number of wheels. - */ - forVehicleWheels?: Array; + /** + * Unique identifier + */ + id: string; + /** + * The list of test type IDs or categories IDs, used to determine if two test types can be added as linked within the same test. + */ + linkedIds?: Array; + /** + * The list of suggested test types, used to determine suggested test types for psv, trl and hgv. + */ + suggestedTestTypeIds?: Array; + /** + * Name of the test type + */ + name: string; + /** + * Full name of the test type containing the entire path, having a business value + */ + testTypeName?: string; + /** + * Name to be displayed in the mobile app suggested next test type popup + */ + suggestedTestTypeDisplayName?: string; + /** + * Order in which this test type is displayed in the mobile app suggested next test type popup + */ + suggestedTestTypeDisplayOrder?: string; + /** + * Used to filter in test types with a specific typeOfTest, send as a query param in the request + */ + typeOfTest?: string; + /** + * This category is applying only to these vehicle types. The vehicle types should descend from its parent, but should not be necessarily the same + */ + forVehicleType: Array; + /** + * Used to filter test types that allow creating tests on Provisional Records + */ + forProvisionalStatus?: boolean; + /** + * Used to filter test types that allow creating tests on Provisional Records and not current + */ + forProvisionalStatusOnly?: boolean; + /** + * + * This category is applying only to these vehicle sizes. The vehicle sizes should descend from its parent, but should not be necessarily the same + */ + forVehicleSize?: Array; + /** + * This category is applying only to these vehicle configurations. The vehicle configurations should descend from its parent, but should not be necessarily the same + */ + forVehicleConfiguration?: Array; + /** + * This category is applying only to the vehicles with those number of axles. The vehicle number of axles should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any number of axles. + */ + forVehicleAxles?: Array; + /** + * This category is applying only to the vehicles with that eu category. The eu vehicle category should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any eu vehicle category. + */ + forEuVehicleCategory?: Array; + /** + * This category is applying only to the vehicles with that vehicle class. The vehicle class should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any vehicle class. + */ + forVehicleClass?: Array; + /** + * This category is applying only to the vehicles with that vehicle subclass. The vehicle subclass should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any vehicle subclass. + */ + forVehicleSubclass?: Array; + /** + * This category is applying only to the vehicles with those number of wheels. The vehicle number of wheels should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any number of wheels. + */ + forVehicleWheels?: Array; } export namespace TestType { - export type ForVehicleTypeEnum = 'psv' | 'hgv' | 'trl' | 'lgv' | 'car' | 'small trl' | 'motorcycle'; - export const ForVehicleTypeEnum = { - Psv: 'psv' as ForVehicleTypeEnum, - Hgv: 'hgv' as ForVehicleTypeEnum, - Trl: 'trl' as ForVehicleTypeEnum, - Lgv: 'lgv' as ForVehicleTypeEnum, - Car: 'car' as ForVehicleTypeEnum, - SmallTrl: 'small trl' as ForVehicleTypeEnum, - Motorcycle: 'motorcycle' as ForVehicleTypeEnum, - }; - export type ForVehicleSizeEnum = 'small' | 'large'; - export const ForVehicleSizeEnum = { - Small: 'small' as ForVehicleSizeEnum, - Large: 'large' as ForVehicleSizeEnum - }; + export type ForVehicleTypeEnum = 'psv' | 'hgv' | 'trl' | 'lgv' | 'car' | 'small trl' | 'motorcycle'; + export const ForVehicleTypeEnum = { + Psv: 'psv' as ForVehicleTypeEnum, + Hgv: 'hgv' as ForVehicleTypeEnum, + Trl: 'trl' as ForVehicleTypeEnum, + Lgv: 'lgv' as ForVehicleTypeEnum, + Car: 'car' as ForVehicleTypeEnum, + SmallTrl: 'small trl' as ForVehicleTypeEnum, + Motorcycle: 'motorcycle' as ForVehicleTypeEnum, + }; + export type ForVehicleSizeEnum = 'small' | 'large'; + export const ForVehicleSizeEnum = { + Small: 'small' as ForVehicleSizeEnum, + Large: 'large' as ForVehicleSizeEnum, + }; } diff --git a/src/app/api/test-types/model/testTypeCategory.ts b/src/app/api/test-types/model/testTypeCategory.ts index 53475fd057..ed0a1c95c3 100644 --- a/src/app/api/test-types/model/testTypeCategory.ts +++ b/src/app/api/test-types/model/testTypeCategory.ts @@ -14,85 +14,85 @@ import { TestType } from './testType'; * A category that can be composed of zero/more categories + one/more test types */ export interface TestTypeCategory { - /** - * Unique identifier - */ - id: string; - /** - * used in helping to sort test types - */ - sortId?: string; - /** - * The lsit of test type IDs or categories IDs, used to determine if two test types can be added as linked within the same test. - */ - linkedIds?: Array; - /** - * Name of the category - */ - name: string; - /** - * This category is applying only to these vehicle types. - */ - forVehicleType: Array; - /** - * Used to filter test types that allow creating tests on Provisional Records - */ - forProvisionalStatus?: boolean; - /** - * Used to filter test types that allow creating tests on Provisional Records and not current - */ - forProvisionalStatusOnly?: boolean; - /** - * Used to filter in test types with a specific typeOfTest, send as a query param in the request - */ - typeOfTest?: string; - /** - * This category is applying only to these vehicle sizes. - */ - forVehicleSize?: Array; - /** - * This category is applying only to these vehicle configurations. - */ - forVehicleConfiguration?: Array; - /** - * This category is applying only to the vehicles with those number of axles. If the value is null then it means the category or test type is applicable to any number of axles. - */ - forVehicleAxles?: Array; - /** - * This category is applying only to the vehicles with that eu category. The eu vehicle category should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any eu vehicle category. - */ - forEuVehicleCategory?: Array; - /** - * This category is applying only to the vehicles with that vehicle class. The vehicle class should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any vehicle class. - */ - forVehicleClass?: Array; - /** - * This category is applying only to the vehicles with that vehicle subclass. The vehicle subclass should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any vehicle subclass. - */ - forVehicleSubclass?: Array; - /** - * This category is applying only to the vehicles with those number of wheels. The vehicle number of wheels should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any number of wheels. - */ - forVehicleWheels?: Array; - /** - * This is an array composed of TestTypeCategories and/or TestTypes - */ - nextTestTypesOrCategories?: Array; + /** + * Unique identifier + */ + id: string; + /** + * used in helping to sort test types + */ + sortId?: string; + /** + * The lsit of test type IDs or categories IDs, used to determine if two test types can be added as linked within the same test. + */ + linkedIds?: Array; + /** + * Name of the category + */ + name: string; + /** + * This category is applying only to these vehicle types. + */ + forVehicleType: Array; + /** + * Used to filter test types that allow creating tests on Provisional Records + */ + forProvisionalStatus?: boolean; + /** + * Used to filter test types that allow creating tests on Provisional Records and not current + */ + forProvisionalStatusOnly?: boolean; + /** + * Used to filter in test types with a specific typeOfTest, send as a query param in the request + */ + typeOfTest?: string; + /** + * This category is applying only to these vehicle sizes. + */ + forVehicleSize?: Array; + /** + * This category is applying only to these vehicle configurations. + */ + forVehicleConfiguration?: Array; + /** + * This category is applying only to the vehicles with those number of axles. If the value is null then it means the category or test type is applicable to any number of axles. + */ + forVehicleAxles?: Array; + /** + * This category is applying only to the vehicles with that eu category. The eu vehicle category should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any eu vehicle category. + */ + forEuVehicleCategory?: Array; + /** + * This category is applying only to the vehicles with that vehicle class. The vehicle class should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any vehicle class. + */ + forVehicleClass?: Array; + /** + * This category is applying only to the vehicles with that vehicle subclass. The vehicle subclass should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any vehicle subclass. + */ + forVehicleSubclass?: Array; + /** + * This category is applying only to the vehicles with those number of wheels. The vehicle number of wheels should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any number of wheels. + */ + forVehicleWheels?: Array; + /** + * This is an array composed of TestTypeCategories and/or TestTypes + */ + nextTestTypesOrCategories?: Array; } export namespace TestTypeCategory { - export type ForVehicleTypeEnum = 'psv' | 'hgv' | 'trl' | 'lgv' | 'car' | 'small trl' | 'motorcycle'; - export const ForVehicleTypeEnum = { - Psv: 'psv' as ForVehicleTypeEnum, - Hgv: 'hgv' as ForVehicleTypeEnum, - Trl: 'trl' as ForVehicleTypeEnum, - Car: 'car' as ForVehicleTypeEnum, - Lgv: 'lgv' as ForVehicleTypeEnum, - SmallTrl: 'small trl' as ForVehicleTypeEnum, - Motorcycle: 'motorcycle' as ForVehicleTypeEnum, - }; - export type ForVehicleSizeEnum = 'small' | 'large'; - export const ForVehicleSizeEnum = { - Small: 'small' as ForVehicleSizeEnum, - Large: 'large' as ForVehicleSizeEnum - }; + export type ForVehicleTypeEnum = 'psv' | 'hgv' | 'trl' | 'lgv' | 'car' | 'small trl' | 'motorcycle'; + export const ForVehicleTypeEnum = { + Psv: 'psv' as ForVehicleTypeEnum, + Hgv: 'hgv' as ForVehicleTypeEnum, + Trl: 'trl' as ForVehicleTypeEnum, + Car: 'car' as ForVehicleTypeEnum, + Lgv: 'lgv' as ForVehicleTypeEnum, + SmallTrl: 'small trl' as ForVehicleTypeEnum, + Motorcycle: 'motorcycle' as ForVehicleTypeEnum, + }; + export type ForVehicleSizeEnum = 'small' | 'large'; + export const ForVehicleSizeEnum = { + Small: 'small' as ForVehicleSizeEnum, + Large: 'large' as ForVehicleSizeEnum, + }; } diff --git a/src/app/api/test-types/model/testTypeInfo.ts b/src/app/api/test-types/model/testTypeInfo.ts index d8b2db15fd..699575003b 100644 --- a/src/app/api/test-types/model/testTypeInfo.ts +++ b/src/app/api/test-types/model/testTypeInfo.ts @@ -12,20 +12,20 @@ /** * Test type */ -export interface TestTypeInfo { - /** - * Unique identifier - */ - id?: string; - testTypeClassification?: TestTypeInfo.TestTypeClassificationEnum; - defaultTestCode?: string; - linkedTestCode?: string; +export interface TestTypeInfo { + /** + * Unique identifier + */ + id?: string; + testTypeClassification?: TestTypeInfo.TestTypeClassificationEnum; + defaultTestCode?: string; + linkedTestCode?: string; } export namespace TestTypeInfo { - export type TestTypeClassificationEnum = 'Annual With Certificate' | 'Annual No Certificate' | 'Non Annual'; - export const TestTypeClassificationEnum = { - AnnualWithCertificate: 'Annual With Certificate' as TestTypeClassificationEnum, - AnnualNoCertificate: 'Annual No Certificate' as TestTypeClassificationEnum, - NonAnnual: 'Non Annual' as TestTypeClassificationEnum - }; -} \ No newline at end of file + export type TestTypeClassificationEnum = 'Annual With Certificate' | 'Annual No Certificate' | 'Non Annual'; + export const TestTypeClassificationEnum = { + AnnualWithCertificate: 'Annual With Certificate' as TestTypeClassificationEnum, + AnnualNoCertificate: 'Annual No Certificate' as TestTypeClassificationEnum, + NonAnnual: 'Non Annual' as TestTypeClassificationEnum, + }; +} diff --git a/src/app/api/test-types/model/testTypesTaxonomy.ts b/src/app/api/test-types/model/testTypesTaxonomy.ts index 9a4e53702c..ad4389ee3c 100644 --- a/src/app/api/test-types/model/testTypesTaxonomy.ts +++ b/src/app/api/test-types/model/testTypesTaxonomy.ts @@ -11,5 +11,4 @@ import { TestType } from './testType'; import { TestTypeCategory } from './testTypeCategory'; -export interface TestTypesTaxonomy extends Array { -} \ No newline at end of file +export interface TestTypesTaxonomy extends Array {} diff --git a/src/app/api/test-types/variables.ts b/src/app/api/test-types/variables.ts index 6fe58549f3..9bae45f800 100644 --- a/src/app/api/test-types/variables.ts +++ b/src/app/api/test-types/variables.ts @@ -2,8 +2,8 @@ import { InjectionToken } from '@angular/core'; export const BASE_PATH = new InjectionToken('basePath'); export const COLLECTION_FORMATS = { - 'csv': ',', - 'tsv': ' ', - 'ssv': ' ', - 'pipes': '|' -} + csv: ',', + tsv: ' ', + ssv: ' ', + pipes: '|', +}; diff --git a/src/app/api/vehicle/api.module.ts b/src/app/api/vehicle/api.module.ts index 878117c339..526092d029 100644 --- a/src/app/api/vehicle/api.module.ts +++ b/src/app/api/vehicle/api.module.ts @@ -1,7 +1,6 @@ -import { NgModule, ModuleWithProviders, SkipSelf, Optional } from '@angular/core'; -import { Configuration } from './configuration'; import { HttpClient } from '@angular/common/http'; - +import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; +import { Configuration } from './configuration'; import { AddProvisionalTechRecordService } from './api/addProvisionalTechRecord.service'; import { ArchiveTechRecordStatusService } from './api/archiveTechRecordStatus.service'; @@ -10,32 +9,34 @@ import { PostTechRecordsService } from './api/postTechRecords.service'; import { UpdateTechRecordsService } from './api/updateTechRecords.service'; @NgModule({ - imports: [], - declarations: [], - exports: [], - providers: [ - AddProvisionalTechRecordService, - ArchiveTechRecordStatusService, - GetTechRecordsService, - PostTechRecordsService, - UpdateTechRecordsService ] + imports: [], + declarations: [], + exports: [], + providers: [ + AddProvisionalTechRecordService, + ArchiveTechRecordStatusService, + GetTechRecordsService, + PostTechRecordsService, + UpdateTechRecordsService, + ], }) export class ApiModule { - public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { - return { - ngModule: ApiModule, - providers: [ { provide: Configuration, useFactory: configurationFactory } ] - }; - } + public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { + return { + ngModule: ApiModule, + providers: [{ provide: Configuration, useFactory: configurationFactory }], + }; + } - constructor( @Optional() @SkipSelf() parentModule: ApiModule, - @Optional() http: HttpClient) { - if (parentModule) { - throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); - } - if (!http) { - throw new Error('You need to import the HttpClientModule in your AppModule! \n' + - 'See also https://github.com/angular/angular/issues/20575'); - } - } + constructor(@Optional() @SkipSelf() parentModule: ApiModule, @Optional() http: HttpClient) { + if (parentModule) { + throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); + } + if (!http) { + throw new Error( + 'You need to import the HttpClientModule in your AppModule! \n' + + 'See also https://github.com/angular/angular/issues/20575' + ); + } + } } diff --git a/src/app/api/vehicle/api/addProvisionalTechRecord.service.ts b/src/app/api/vehicle/api/addProvisionalTechRecord.service.ts index abd4fe2904..f56cb1b070 100644 --- a/src/app/api/vehicle/api/addProvisionalTechRecord.service.ts +++ b/src/app/api/vehicle/api/addProvisionalTechRecord.service.ts @@ -7,112 +7,128 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - *//* tslint:disable:no-unused-variable member-ordering */ + */ /* tslint:disable:no-unused-variable member-ordering */ -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpHeaders, HttpParams, - HttpResponse, HttpEvent } from '@angular/common/http'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http'; +import { Inject, Injectable, Optional } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { CompleteTechRecordPUT } from '../model/completeTechRecordPUT'; import { TechRecordArchiveAndProvisionalPayload } from '../model/techRecordArchiveAndProvisionalPayload'; -import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; -import { Configuration } from '../configuration'; - +import { Configuration } from '../configuration'; +import { BASE_PATH } from '../variables'; @Injectable() export class AddProvisionalTechRecordService { - - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - - /** - * Creates a new tech-record with status provisional for that vehicle and appends it to the techRecords array - * - * @param body The tech record to be created and added into the techRecords array - * @param systemNumber This represents the systemNumber of the vehicle - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public addProvisionalTechRecord(body: TechRecordArchiveAndProvisionalPayload, systemNumber: string, observe?: 'body', reportProgress?: boolean): Observable; - public addProvisionalTechRecord(body: TechRecordArchiveAndProvisionalPayload, systemNumber: string, observe?: 'response', reportProgress?: boolean): Observable>; - public addProvisionalTechRecord(body: TechRecordArchiveAndProvisionalPayload, systemNumber: string, observe?: 'events', reportProgress?: boolean): Observable>; - public addProvisionalTechRecord(body: TechRecordArchiveAndProvisionalPayload, systemNumber: string, observe: any = 'body', reportProgress: boolean = false ): Observable { - - if (body === null || body === undefined) { - throw new Error('Required parameter body was null or undefined when calling addProvisionalTechRecord.'); - } - - if (systemNumber === null || systemNumber === undefined) { - throw new Error('Required parameter systemNumber was null or undefined when calling addProvisionalTechRecord.'); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); - } - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/json' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - 'application/json' - ]; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request('post',`${this.basePath}/vehicles/add-provisional/${encodeURIComponent(String(systemNumber))}`, - { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor( + protected httpClient: HttpClient, + @Optional() @Inject(BASE_PATH) basePath: string, + @Optional() configuration: Configuration + ) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + /** + * Creates a new tech-record with status provisional for that vehicle and appends it to the techRecords array + * + * @param body The tech record to be created and added into the techRecords array + * @param systemNumber This represents the systemNumber of the vehicle + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public addProvisionalTechRecord( + body: TechRecordArchiveAndProvisionalPayload, + systemNumber: string, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public addProvisionalTechRecord( + body: TechRecordArchiveAndProvisionalPayload, + systemNumber: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public addProvisionalTechRecord( + body: TechRecordArchiveAndProvisionalPayload, + systemNumber: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public addProvisionalTechRecord( + body: TechRecordArchiveAndProvisionalPayload, + systemNumber: string, + observe: any = 'body', + reportProgress = false + ): Observable { + if (body === null || body === undefined) { + throw new Error('Required parameter body was null or undefined when calling addProvisionalTechRecord.'); + } + + if (systemNumber === null || systemNumber === undefined) { + throw new Error('Required parameter systemNumber was null or undefined when calling addProvisionalTechRecord.'); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = ['application/json']; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request( + 'post', + `${this.basePath}/vehicles/add-provisional/${encodeURIComponent(String(systemNumber))}`, + { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + } + ); + } } diff --git a/src/app/api/vehicle/api/api.ts b/src/app/api/vehicle/api/api.ts index c561b91cc7..241f54088f 100644 --- a/src/app/api/vehicle/api/api.ts +++ b/src/app/api/vehicle/api/api.ts @@ -8,4 +8,10 @@ export * from './postTechRecords.service'; import { PostTechRecordsService } from './postTechRecords.service'; export * from './updateTechRecords.service'; import { UpdateTechRecordsService } from './updateTechRecords.service'; -export const APIS = [AddProvisionalTechRecordService, ArchiveTechRecordStatusService, GetTechRecordsService, PostTechRecordsService, UpdateTechRecordsService]; +export const APIS = [ + AddProvisionalTechRecordService, + ArchiveTechRecordStatusService, + GetTechRecordsService, + PostTechRecordsService, + UpdateTechRecordsService, +]; diff --git a/src/app/api/vehicle/api/archiveTechRecordStatus.service.ts b/src/app/api/vehicle/api/archiveTechRecordStatus.service.ts index 61c1610de0..9878327475 100644 --- a/src/app/api/vehicle/api/archiveTechRecordStatus.service.ts +++ b/src/app/api/vehicle/api/archiveTechRecordStatus.service.ts @@ -7,112 +7,128 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - *//* tslint:disable:no-unused-variable member-ordering */ + */ /* tslint:disable:no-unused-variable member-ordering */ -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpHeaders, HttpParams, - HttpResponse, HttpEvent } from '@angular/common/http'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http'; +import { Inject, Injectable, Optional } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { CompleteTechRecordPUT } from '../model/completeTechRecordPUT'; import { TechRecordArchiveAndProvisionalPayload } from '../model/techRecordArchiveAndProvisionalPayload'; -import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; -import { Configuration } from '../configuration'; - +import { Configuration } from '../configuration'; +import { BASE_PATH } from '../variables'; @Injectable() export class ArchiveTechRecordStatusService { - - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - - /** - * Archive an existing current or provisional tech record - * - * @param body The tech record to be archived - * @param systemNumber This represents the systemNumber of the vehicle - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public archiveTechRecordStatus(body: TechRecordArchiveAndProvisionalPayload, systemNumber: string, observe?: 'body', reportProgress?: boolean): Observable; - public archiveTechRecordStatus(body: TechRecordArchiveAndProvisionalPayload, systemNumber: string, observe?: 'response', reportProgress?: boolean): Observable>; - public archiveTechRecordStatus(body: TechRecordArchiveAndProvisionalPayload, systemNumber: string, observe?: 'events', reportProgress?: boolean): Observable>; - public archiveTechRecordStatus(body: TechRecordArchiveAndProvisionalPayload, systemNumber: string, observe: any = 'body', reportProgress: boolean = false ): Observable { - - if (body === null || body === undefined) { - throw new Error('Required parameter body was null or undefined when calling archiveTechRecordStatus.'); - } - - if (systemNumber === null || systemNumber === undefined) { - throw new Error('Required parameter systemNumber was null or undefined when calling archiveTechRecordStatus.'); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); - } - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/json' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - 'application/json' - ]; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request('post',`${this.basePath}/vehicles/archive/${encodeURIComponent(String(systemNumber))}`, - { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor( + protected httpClient: HttpClient, + @Optional() @Inject(BASE_PATH) basePath: string, + @Optional() configuration: Configuration + ) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + /** + * Archive an existing current or provisional tech record + * + * @param body The tech record to be archived + * @param systemNumber This represents the systemNumber of the vehicle + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public archiveTechRecordStatus( + body: TechRecordArchiveAndProvisionalPayload, + systemNumber: string, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public archiveTechRecordStatus( + body: TechRecordArchiveAndProvisionalPayload, + systemNumber: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public archiveTechRecordStatus( + body: TechRecordArchiveAndProvisionalPayload, + systemNumber: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public archiveTechRecordStatus( + body: TechRecordArchiveAndProvisionalPayload, + systemNumber: string, + observe: any = 'body', + reportProgress = false + ): Observable { + if (body === null || body === undefined) { + throw new Error('Required parameter body was null or undefined when calling archiveTechRecordStatus.'); + } + + if (systemNumber === null || systemNumber === undefined) { + throw new Error('Required parameter systemNumber was null or undefined when calling archiveTechRecordStatus.'); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = ['application/json']; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request( + 'post', + `${this.basePath}/vehicles/archive/${encodeURIComponent(String(systemNumber))}`, + { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + } + ); + } } diff --git a/src/app/api/vehicle/api/getTechRecords.service.ts b/src/app/api/vehicle/api/getTechRecords.service.ts index 3d8e50a5eb..0037eec10b 100644 --- a/src/app/api/vehicle/api/getTechRecords.service.ts +++ b/src/app/api/vehicle/api/getTechRecords.service.ts @@ -7,118 +7,141 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - *//* tslint:disable:no-unused-variable member-ordering */ + */ /* tslint:disable:no-unused-variable member-ordering */ -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpHeaders, HttpParams, - HttpResponse, HttpEvent } from '@angular/common/http'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; +import { Inject, Injectable, Optional } from '@angular/core'; +import { CustomHttpUrlEncodingCodec } from '../encoder'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { CompleteTechRecords } from '../model/completeTechRecords'; -import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; -import { Configuration } from '../configuration'; - +import { Configuration } from '../configuration'; +import { BASE_PATH } from '../variables'; @Injectable() export class GetTechRecordsService { - - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - - /** - * Get a tech record, for a particular Vin with status specified. - * - * @param searchIdentifier If the searchCriteria query parameter is not used or it has the \"all\" value then the searchIdentifier can be VRM, VIN, last six digits of the VIN or trailerId. VRM = between 3 and 8 characters, VIN = >8 characters, partial VIN = exactly 6 digits and trailerId = exactly 8 digits / 1 letter followed by exactly 6 digits. - * @param metadata - * @param status The tech record's status, the default value is provisional_over_current. If \"status\" = \"provisional_over_current\" or not provided when the GET call is done, then the current tech record will be retrieved only if, for the \"searchIdentifier\" that was provided, there is no \"provisional\" tech record, in which case the provisional tech record will be retrieved instead. If \"status\" = \"all\", then the backend will translate this into returning ALL technical records for that particular VIN/VRM, not just specific statuses - * @param searchCriteria The parameter is used to specify which search criteria should be used. \"ALL\" = search identifier can be VRM, VIN, last six digits of the VIN or trailerId. VRM = between 3 and 8 characters, VIN = >8 characters, partial VIN = exactly 6 digits and trailerId = exactly 8 digits / 1 letter followed by exactly 6 digits. If any other value than \"ALL\" is used then the search will be done using the specified search criteria, without taking into account the format of the saerch identifier. - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public getTechRecords(searchIdentifier: string, metadata?: boolean, status?: string, searchCriteria?: string, observe?: 'body', reportProgress?: boolean): Observable; - public getTechRecords(searchIdentifier: string, metadata?: boolean, status?: string, searchCriteria?: string, observe?: 'response', reportProgress?: boolean): Observable>; - public getTechRecords(searchIdentifier: string, metadata?: boolean, status?: string, searchCriteria?: string, observe?: 'events', reportProgress?: boolean): Observable>; - public getTechRecords(searchIdentifier: string, metadata?: boolean, status?: string, searchCriteria?: string, observe: any = 'body', reportProgress: boolean = false ): Observable { - - if (searchIdentifier === null || searchIdentifier === undefined) { - throw new Error('Required parameter searchIdentifier was null or undefined when calling getTechRecords.'); - } - - - - - let queryParameters = new HttpParams({encoder: new CustomHttpUrlEncodingCodec()}); - if (metadata !== undefined && metadata !== null) { - queryParameters = queryParameters.set('metadata', metadata); - } - if (status !== undefined && status !== null) { - queryParameters = queryParameters.set('status', status); - } - if (searchCriteria !== undefined && searchCriteria !== null) { - queryParameters = queryParameters.set('searchCriteria', searchCriteria); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); - } - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/json' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - ]; - - return this.httpClient.request('get',`${this.basePath}/vehicles/${encodeURIComponent(String(searchIdentifier))}/tech-records`, - { - params: queryParameters, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor( + protected httpClient: HttpClient, + @Optional() @Inject(BASE_PATH) basePath: string, + @Optional() configuration: Configuration + ) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + /** + * Get a tech record, for a particular Vin with status specified. + * + * @param searchIdentifier If the searchCriteria query parameter is not used or it has the \"all\" value then the searchIdentifier can be VRM, VIN, last six digits of the VIN or trailerId. VRM = between 3 and 8 characters, VIN = >8 characters, partial VIN = exactly 6 digits and trailerId = exactly 8 digits / 1 letter followed by exactly 6 digits. + * @param metadata + * @param status The tech record's status, the default value is provisional_over_current. If \"status\" = \"provisional_over_current\" or not provided when the GET call is done, then the current tech record will be retrieved only if, for the \"searchIdentifier\" that was provided, there is no \"provisional\" tech record, in which case the provisional tech record will be retrieved instead. If \"status\" = \"all\", then the backend will translate this into returning ALL technical records for that particular VIN/VRM, not just specific statuses + * @param searchCriteria The parameter is used to specify which search criteria should be used. \"ALL\" = search identifier can be VRM, VIN, last six digits of the VIN or trailerId. VRM = between 3 and 8 characters, VIN = >8 characters, partial VIN = exactly 6 digits and trailerId = exactly 8 digits / 1 letter followed by exactly 6 digits. If any other value than \"ALL\" is used then the search will be done using the specified search criteria, without taking into account the format of the saerch identifier. + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public getTechRecords( + searchIdentifier: string, + metadata?: boolean, + status?: string, + searchCriteria?: string, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public getTechRecords( + searchIdentifier: string, + metadata?: boolean, + status?: string, + searchCriteria?: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public getTechRecords( + searchIdentifier: string, + metadata?: boolean, + status?: string, + searchCriteria?: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public getTechRecords( + searchIdentifier: string, + metadata?: boolean, + status?: string, + searchCriteria?: string, + observe: any = 'body', + reportProgress = false + ): Observable { + if (searchIdentifier === null || searchIdentifier === undefined) { + throw new Error('Required parameter searchIdentifier was null or undefined when calling getTechRecords.'); + } + + let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); + if (metadata !== undefined && metadata !== null) { + queryParameters = queryParameters.set('metadata', metadata); + } + if (status !== undefined && status !== null) { + queryParameters = queryParameters.set('status', status); + } + if (searchCriteria !== undefined && searchCriteria !== null) { + queryParameters = queryParameters.set('searchCriteria', searchCriteria); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = []; + + return this.httpClient.request( + 'get', + `${this.basePath}/vehicles/${encodeURIComponent(String(searchIdentifier))}/tech-records`, + { + params: queryParameters, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + } + ); + } } diff --git a/src/app/api/vehicle/api/postTechRecords.service.ts b/src/app/api/vehicle/api/postTechRecords.service.ts index 352391a9ea..d0017d5b2a 100644 --- a/src/app/api/vehicle/api/postTechRecords.service.ts +++ b/src/app/api/vehicle/api/postTechRecords.service.ts @@ -7,106 +7,106 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - *//* tslint:disable:no-unused-variable member-ordering */ + */ /* tslint:disable:no-unused-variable member-ordering */ -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpHeaders, HttpParams, - HttpResponse, HttpEvent } from '@angular/common/http'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http'; +import { Inject, Injectable, Optional } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { TechRecordPOST } from '../model/techRecordPOST'; -import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; -import { Configuration } from '../configuration'; - +import { Configuration } from '../configuration'; +import { BASE_PATH } from '../variables'; @Injectable() export class PostTechRecordsService { - - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - - /** - * Create a tech record - * - * @param body The tech record to create - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public postTechRecords(body: TechRecordPOST, observe?: 'body', reportProgress?: boolean): Observable; - public postTechRecords(body: TechRecordPOST, observe?: 'response', reportProgress?: boolean): Observable>; - public postTechRecords(body: TechRecordPOST, observe?: 'events', reportProgress?: boolean): Observable>; - public postTechRecords(body: TechRecordPOST, observe: any = 'body', reportProgress: boolean = false ): Observable { - - if (body === null || body === undefined) { - throw new Error('Required parameter body was null or undefined when calling postTechRecords.'); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); - } - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/text' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - 'application/json' - ]; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request('post',`${this.basePath}/vehicles`, - { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor( + protected httpClient: HttpClient, + @Optional() @Inject(BASE_PATH) basePath: string, + @Optional() configuration: Configuration + ) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + /** + * Create a tech record + * + * @param body The tech record to create + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public postTechRecords(body: TechRecordPOST, observe?: 'body', reportProgress?: boolean): Observable; + public postTechRecords( + body: TechRecordPOST, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public postTechRecords( + body: TechRecordPOST, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public postTechRecords(body: TechRecordPOST, observe: any = 'body', reportProgress = false): Observable { + if (body === null || body === undefined) { + throw new Error('Required parameter body was null or undefined when calling postTechRecords.'); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/text']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = ['application/json']; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request('post', `${this.basePath}/vehicles`, { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + }); + } } diff --git a/src/app/api/vehicle/api/updateTechRecords.service.ts b/src/app/api/vehicle/api/updateTechRecords.service.ts index b5d1e53c67..ca299c9b5a 100644 --- a/src/app/api/vehicle/api/updateTechRecords.service.ts +++ b/src/app/api/vehicle/api/updateTechRecords.service.ts @@ -7,120 +7,140 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - *//* tslint:disable:no-unused-variable member-ordering */ + */ /* tslint:disable:no-unused-variable member-ordering */ -import { Inject, Injectable, Optional } from '@angular/core'; -import { HttpClient, HttpHeaders, HttpParams, - HttpResponse, HttpEvent } from '@angular/common/http'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; +import { Inject, Injectable, Optional } from '@angular/core'; +import { CustomHttpUrlEncodingCodec } from '../encoder'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { CompleteTechRecordPUT } from '../model/completeTechRecordPUT'; import { TechRecordPUT } from '../model/techRecordPUT'; -import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; -import { Configuration } from '../configuration'; - +import { Configuration } from '../configuration'; +import { BASE_PATH } from '../variables'; @Injectable() export class UpdateTechRecordsService { - - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - - /** - * Update a tech record, for a particular systemNumber - * - * @param body The tech record to update - * @param systemNumber This represents the systemNumber of the vehicle - * @param oldStatusCode This represents the old statusCode of a techRecord. Should be passed only if the statusCode was changed. - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public updateTechRecords(body: TechRecordPUT, systemNumber: string, oldStatusCode?: string, observe?: 'body', reportProgress?: boolean): Observable; - public updateTechRecords(body: TechRecordPUT, systemNumber: string, oldStatusCode?: string, observe?: 'response', reportProgress?: boolean): Observable>; - public updateTechRecords(body: TechRecordPUT, systemNumber: string, oldStatusCode?: string, observe?: 'events', reportProgress?: boolean): Observable>; - public updateTechRecords(body: TechRecordPUT, systemNumber: string, oldStatusCode?: string, observe: any = 'body', reportProgress: boolean = false ): Observable { - - if (body === null || body === undefined) { - throw new Error('Required parameter body was null or undefined when calling updateTechRecords.'); - } - - if (systemNumber === null || systemNumber === undefined) { - throw new Error('Required parameter systemNumber was null or undefined when calling updateTechRecords.'); - } - - - let queryParameters = new HttpParams({encoder: new CustomHttpUrlEncodingCodec()}); - if (oldStatusCode !== undefined && oldStatusCode !== null) { - queryParameters = queryParameters.set('oldStatusCode', oldStatusCode); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); - } - - // to determine the Accept header - let httpHeaderAccepts: string[] = [ - 'application/json' - ]; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = [ - 'application/json' - ]; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request('put',`${this.basePath}/vehicles/${encodeURIComponent(String(systemNumber))}`, - { - body: body, - params: queryParameters, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor( + protected httpClient: HttpClient, + @Optional() @Inject(BASE_PATH) basePath: string, + @Optional() configuration: Configuration + ) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + /** + * Update a tech record, for a particular systemNumber + * + * @param body The tech record to update + * @param systemNumber This represents the systemNumber of the vehicle + * @param oldStatusCode This represents the old statusCode of a techRecord. Should be passed only if the statusCode was changed. + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public updateTechRecords( + body: TechRecordPUT, + systemNumber: string, + oldStatusCode?: string, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public updateTechRecords( + body: TechRecordPUT, + systemNumber: string, + oldStatusCode?: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public updateTechRecords( + body: TechRecordPUT, + systemNumber: string, + oldStatusCode?: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public updateTechRecords( + body: TechRecordPUT, + systemNumber: string, + oldStatusCode?: string, + observe: any = 'body', + reportProgress = false + ): Observable { + if (body === null || body === undefined) { + throw new Error('Required parameter body was null or undefined when calling updateTechRecords.'); + } + + if (systemNumber === null || systemNumber === undefined) { + throw new Error('Required parameter systemNumber was null or undefined when calling updateTechRecords.'); + } + + let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); + if (oldStatusCode !== undefined && oldStatusCode !== null) { + queryParameters = queryParameters.set('oldStatusCode', oldStatusCode); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = + typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + const httpHeaderAccepts: string[] = ['application/json']; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = ['application/json']; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request( + 'put', + `${this.basePath}/vehicles/${encodeURIComponent(String(systemNumber))}`, + { + body: body, + params: queryParameters, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress, + } + ); + } } diff --git a/src/app/api/vehicle/configuration.ts b/src/app/api/vehicle/configuration.ts index 82e8458f39..698dce114c 100644 --- a/src/app/api/vehicle/configuration.ts +++ b/src/app/api/vehicle/configuration.ts @@ -1,79 +1,82 @@ export interface ConfigurationParameters { - apiKeys?: {[ key: string ]: string}; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: { [key: string]: string }; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; } export class Configuration { - apiKeys?: {[ key: string ]: string}; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: { [key: string]: string }; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; - constructor(configurationParameters: ConfigurationParameters = {}) { - this.apiKeys = configurationParameters.apiKeys; - this.username = configurationParameters.username; - this.password = configurationParameters.password; - this.accessToken = configurationParameters.accessToken; - this.basePath = configurationParameters.basePath; - this.withCredentials = configurationParameters.withCredentials; - } + constructor(configurationParameters: ConfigurationParameters = {}) { + this.apiKeys = configurationParameters.apiKeys; + this.username = configurationParameters.username; + this.password = configurationParameters.password; + this.accessToken = configurationParameters.accessToken; + this.basePath = configurationParameters.basePath; + this.withCredentials = configurationParameters.withCredentials; + } - /** - * Select the correct content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param contentTypes - the array of content types that are available for selection - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderContentType (contentTypes: string[]): string | undefined { - if (contentTypes.length == 0) { - return undefined; - } + /** + * Select the correct content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param contentTypes - the array of content types that are available for selection + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderContentType(contentTypes: string[]): string | undefined { + if (contentTypes.length == 0) { + return undefined; + } - let type = contentTypes.find(x => this.isJsonMime(x)); - if (type === undefined) { - return contentTypes[0]; - } - return type; - } + const type = contentTypes.find((x) => this.isJsonMime(x)); + if (type === undefined) { + return contentTypes[0]; + } + return type; + } - /** - * Select the correct accept content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param accepts - the array of content types that are available for selection. - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderAccept(accepts: string[]): string | undefined { - if (accepts.length == 0) { - return undefined; - } + /** + * Select the correct accept content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param accepts - the array of content types that are available for selection. + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderAccept(accepts: string[]): string | undefined { + if (accepts.length == 0) { + return undefined; + } - let type = accepts.find(x => this.isJsonMime(x)); - if (type === undefined) { - return accepts[0]; - } - return type; - } + const type = accepts.find((x) => this.isJsonMime(x)); + if (type === undefined) { + return accepts[0]; + } + return type; + } - /** - * Check if the given MIME is a JSON MIME. - * JSON MIME examples: - * application/json - * application/json; charset=UTF8 - * APPLICATION/JSON - * application/vnd.company+json - * @param mime - MIME (Multipurpose Internet Mail Extensions) - * @return True if the given MIME is JSON, false otherwise. - */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); - return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = /^(application\\/jnos | [^;\/ \t]+\; + \/[^ + \/ \t]+[+]json)[ \t]*( + .*)?$/i + return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } } diff --git a/src/app/api/vehicle/encoder.ts b/src/app/api/vehicle/encoder.ts index 5d0fb0e90c..233fb78e4a 100644 --- a/src/app/api/vehicle/encoder.ts +++ b/src/app/api/vehicle/encoder.ts @@ -6,12 +6,12 @@ import { HttpUrlEncodingCodec } from '@angular/common/http'; * See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 */ export class CustomHttpUrlEncodingCodec extends HttpUrlEncodingCodec { - override encodeKey(k: string): string { - k = super.encodeKey(k); - return k.replace(/\+/gi, '%2B'); - } - override encodeValue(v: string): string { - v = super.encodeValue(v); - return v.replace(/\+/gi, '%2B'); - } + override encodeKey(k: string): string { + k = super.encodeKey(k); + return k.replace(/\+/gi, '%2B'); + } + override encodeValue(v: string): string { + v = super.encodeValue(v); + return v.replace(/\+/gi, '%2B'); + } } diff --git a/src/app/api/vehicle/index.ts b/src/app/api/vehicle/index.ts index c312b70fa3..410623f1c9 100644 --- a/src/app/api/vehicle/index.ts +++ b/src/app/api/vehicle/index.ts @@ -2,4 +2,4 @@ export * from './api/api'; export * from './model/models'; export * from './variables'; export * from './configuration'; -export * from './api.module'; \ No newline at end of file +export * from './api.module'; diff --git a/src/app/api/vehicle/model/adrDetails.ts b/src/app/api/vehicle/model/adrDetails.ts index 4a2192c11d..290aab8780 100644 --- a/src/app/api/vehicle/model/adrDetails.ts +++ b/src/app/api/vehicle/model/adrDetails.ts @@ -16,56 +16,56 @@ import { AdrDetailsVehicleDetails } from './adrDetailsVehicleDetails'; /** * Used only for HGV and TRL */ -export interface AdrDetails { - vehicleDetails?: AdrDetailsVehicleDetails; - /** - * Optional. Applicable only if vehicleDetails.type contains the word ‘battery’. - */ - listStatementApplicable?: boolean; - /** - * Mandatory if listStatementApplicable is true, therefore applicable only if vehicleDetails.type contains the word ‘battery’. Else N/A - */ - batteryListNumber?: string; - /** - * Optional for all vehicle types - */ - declarationsSeen?: boolean; - /** - * Optional for all vehicle types - */ - brakeDeclarationsSeen?: boolean; - /** - * Optional for all vehicle types - */ - brakeDeclarationIssuer?: string; - /** - * Optional for all vehicle types - */ - brakeEndurance?: boolean; - /** - * Mandatory if brakeEndurance = true, else N/A - */ - weight?: string; - /** - * Optional for all vehicle types - */ - compatibilityGroupJ?: boolean; - /** - * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - documents?: Array; - /** - * Mandatory. Users must select, AT LEAST ONE of these. However, users CAN select more than one - */ - permittedDangerousGoods?: Array; - /** - * Optional for all vehicle types - */ - additionalExaminerNotes?: string; - applicantDetails?: AdrDetailsApplicantDetails; - memosApply?: Array; - additionalNotes?: AdrDetailsAdditionalNotes; - adrTypeApprovalNo?: string; - adrCertificateNotes?: string; - tank?: AdrDetailsTank; -} \ No newline at end of file +export interface AdrDetails { + vehicleDetails?: AdrDetailsVehicleDetails; + /** + * Optional. Applicable only if vehicleDetails.type contains the word ‘battery’. + */ + listStatementApplicable?: boolean; + /** + * Mandatory if listStatementApplicable is true, therefore applicable only if vehicleDetails.type contains the word ‘battery’. Else N/A + */ + batteryListNumber?: string; + /** + * Optional for all vehicle types + */ + declarationsSeen?: boolean; + /** + * Optional for all vehicle types + */ + brakeDeclarationsSeen?: boolean; + /** + * Optional for all vehicle types + */ + brakeDeclarationIssuer?: string; + /** + * Optional for all vehicle types + */ + brakeEndurance?: boolean; + /** + * Mandatory if brakeEndurance = true, else N/A + */ + weight?: string; + /** + * Optional for all vehicle types + */ + compatibilityGroupJ?: boolean; + /** + * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + documents?: Array; + /** + * Mandatory. Users must select, AT LEAST ONE of these. However, users CAN select more than one + */ + permittedDangerousGoods?: Array; + /** + * Optional for all vehicle types + */ + additionalExaminerNotes?: string; + applicantDetails?: AdrDetailsApplicantDetails; + memosApply?: Array; + additionalNotes?: AdrDetailsAdditionalNotes; + adrTypeApprovalNo?: string; + adrCertificateNotes?: string; + tank?: AdrDetailsTank; +} diff --git a/src/app/api/vehicle/model/adrDetailsAdditionalNotes.ts b/src/app/api/vehicle/model/adrDetailsAdditionalNotes.ts index 36c3484486..83bfc89334 100644 --- a/src/app/api/vehicle/model/adrDetailsAdditionalNotes.ts +++ b/src/app/api/vehicle/model/adrDetailsAdditionalNotes.ts @@ -9,13 +9,13 @@ * Do not edit the class manually. */ -export interface AdrDetailsAdditionalNotes { - /** - * Optional for all vehicle types - */ - number?: Array; - /** - * Optional for all vehicle types - */ - guidanceNotes?: Array; -} \ No newline at end of file +export interface AdrDetailsAdditionalNotes { + /** + * Optional for all vehicle types + */ + number?: Array; + /** + * Optional for all vehicle types + */ + guidanceNotes?: Array; +} diff --git a/src/app/api/vehicle/model/adrDetailsApplicantDetails.ts b/src/app/api/vehicle/model/adrDetailsApplicantDetails.ts index 16277b4715..db19406345 100644 --- a/src/app/api/vehicle/model/adrDetailsApplicantDetails.ts +++ b/src/app/api/vehicle/model/adrDetailsApplicantDetails.ts @@ -9,10 +9,10 @@ * Do not edit the class manually. */ -export interface AdrDetailsApplicantDetails { - name?: string; - street?: string; - town?: string; - city?: string; - postcode?: string; -} \ No newline at end of file +export interface AdrDetailsApplicantDetails { + name?: string; + street?: string; + town?: string; + city?: string; + postcode?: string; +} diff --git a/src/app/api/vehicle/model/adrDetailsTank.ts b/src/app/api/vehicle/model/adrDetailsTank.ts index 49d6ec0050..1c283e18cf 100644 --- a/src/app/api/vehicle/model/adrDetailsTank.ts +++ b/src/app/api/vehicle/model/adrDetailsTank.ts @@ -11,7 +11,7 @@ import { AdrDetailsTankTankDetails } from './adrDetailsTankTankDetails'; import { AdrDetailsTankTankStatement } from './adrDetailsTankTankStatement'; -export interface AdrDetailsTank { - tankDetails?: AdrDetailsTankTankDetails; - tankStatement?: AdrDetailsTankTankStatement; -} \ No newline at end of file +export interface AdrDetailsTank { + tankDetails?: AdrDetailsTankTankDetails; + tankStatement?: AdrDetailsTankTankStatement; +} diff --git a/src/app/api/vehicle/model/adrDetailsTankTankDetails.ts b/src/app/api/vehicle/model/adrDetailsTankTankDetails.ts index 4e0dc8993f..b946f931ea 100644 --- a/src/app/api/vehicle/model/adrDetailsTankTankDetails.ts +++ b/src/app/api/vehicle/model/adrDetailsTankTankDetails.ts @@ -11,31 +11,31 @@ import { AdrDetailsTankTankDetailsTc2Details } from './adrDetailsTankTankDetailsTc2Details'; import { AdrDetailsTankTankDetailsTc3Details } from './adrDetailsTankTankDetailsTc3Details'; -export interface AdrDetailsTankTankDetails { - /** - * Mandatory. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tankManufacturer?: string; - /** - * Mandatory. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - yearOfManufacture?: number; - /** - * Mandatory. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tankCode?: string; - /** - * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - specialProvisions?: string; - /** - * Mandatory. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tankManufacturerSerialNo?: string; - /** - * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tankTypeAppNo?: string; - tc2Details?: AdrDetailsTankTankDetailsTc2Details; - tc3Details?: Array; -} \ No newline at end of file +export interface AdrDetailsTankTankDetails { + /** + * Mandatory. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tankManufacturer?: string; + /** + * Mandatory. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + yearOfManufacture?: number; + /** + * Mandatory. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tankCode?: string; + /** + * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + specialProvisions?: string; + /** + * Mandatory. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tankManufacturerSerialNo?: string; + /** + * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tankTypeAppNo?: string; + tc2Details?: AdrDetailsTankTankDetailsTc2Details; + tc3Details?: Array; +} diff --git a/src/app/api/vehicle/model/adrDetailsTankTankDetailsTc2Details.ts b/src/app/api/vehicle/model/adrDetailsTankTankDetailsTc2Details.ts index ee1d2d8090..acf7d9ad29 100644 --- a/src/app/api/vehicle/model/adrDetailsTankTankDetailsTc2Details.ts +++ b/src/app/api/vehicle/model/adrDetailsTankTankDetailsTc2Details.ts @@ -9,23 +9,23 @@ * Do not edit the class manually. */ -export interface AdrDetailsTankTankDetailsTc2Details { - /** - * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tc2Type?: AdrDetailsTankTankDetailsTc2Details.Tc2TypeEnum; - /** - * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tc2IntermediateApprovalNo?: string; - /** - * Optional. Date(YYYY-MM-DD). Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tc2IntermediateExpiryDate?: string; +export interface AdrDetailsTankTankDetailsTc2Details { + /** + * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tc2Type?: AdrDetailsTankTankDetailsTc2Details.Tc2TypeEnum; + /** + * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tc2IntermediateApprovalNo?: string; + /** + * Optional. Date(YYYY-MM-DD). Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tc2IntermediateExpiryDate?: string; } export namespace AdrDetailsTankTankDetailsTc2Details { - export type Tc2TypeEnum = 'initial'; - export const Tc2TypeEnum = { - Initial: 'initial' as Tc2TypeEnum - }; -} \ No newline at end of file + export type Tc2TypeEnum = 'initial'; + export const Tc2TypeEnum = { + Initial: 'initial' as Tc2TypeEnum, + }; +} diff --git a/src/app/api/vehicle/model/adrDetailsTankTankDetailsTc3Details.ts b/src/app/api/vehicle/model/adrDetailsTankTankDetailsTc3Details.ts index c36f8c1c0a..7d935c90b7 100644 --- a/src/app/api/vehicle/model/adrDetailsTankTankDetailsTc3Details.ts +++ b/src/app/api/vehicle/model/adrDetailsTankTankDetailsTc3Details.ts @@ -10,24 +10,24 @@ */ export interface AdrDetailsTankTankDetailsTc3Details { - /** - * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tc3Type?: AdrDetailsTankTankDetailsTc3Details.Tc3TypeEnum; - /** - * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tc3PeriodicNumber?: string; - /** - * Optional. Date(YYYY-MM-DD). Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tc3PeriodicExpiryDate?: string; + /** + * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tc3Type?: AdrDetailsTankTankDetailsTc3Details.Tc3TypeEnum; + /** + * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tc3PeriodicNumber?: string; + /** + * Optional. Date(YYYY-MM-DD). Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tc3PeriodicExpiryDate?: string; } export namespace AdrDetailsTankTankDetailsTc3Details { - export type Tc3TypeEnum = 'intermediate' | 'periodic' | 'exceptional'; - export const Tc3TypeEnum = { - Intermediate: 'intermediate' as Tc3TypeEnum, - Periodic: 'periodic' as Tc3TypeEnum, - Exceptional: 'exceptional' as Tc3TypeEnum - }; + export type Tc3TypeEnum = 'intermediate' | 'periodic' | 'exceptional'; + export const Tc3TypeEnum = { + Intermediate: 'intermediate' as Tc3TypeEnum, + Periodic: 'periodic' as Tc3TypeEnum, + Exceptional: 'exceptional' as Tc3TypeEnum, + }; } diff --git a/src/app/api/vehicle/model/adrDetailsTankTankStatement.ts b/src/app/api/vehicle/model/adrDetailsTankTankStatement.ts index 4ce7b52ddb..27d37327f9 100644 --- a/src/app/api/vehicle/model/adrDetailsTankTankStatement.ts +++ b/src/app/api/vehicle/model/adrDetailsTankTankStatement.ts @@ -9,25 +9,25 @@ * Do not edit the class manually. */ -export interface AdrDetailsTankTankStatement { - /** - * Mandatory IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ ELSE, optional. If mandatory, users must select ONE of these. Users cannot select less/more than one - */ - substancesPermitted?: string; - /** - * Optional. Applicable only IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ - */ - statement?: string; - /** - * Optional. Applicable only IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ - */ - productListRefNo?: string; - /** - * Optional. Applicable only IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ - */ - productListUnNo?: Array; - /** - * Optional. Applicable only IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ - */ - productList?: string; -} \ No newline at end of file +export interface AdrDetailsTankTankStatement { + /** + * Mandatory IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ ELSE, optional. If mandatory, users must select ONE of these. Users cannot select less/more than one + */ + substancesPermitted?: string; + /** + * Optional. Applicable only IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ + */ + statement?: string; + /** + * Optional. Applicable only IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ + */ + productListRefNo?: string; + /** + * Optional. Applicable only IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ + */ + productListUnNo?: Array; + /** + * Optional. Applicable only IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ + */ + productList?: string; +} diff --git a/src/app/api/vehicle/model/adrDetailsVehicleDetails.ts b/src/app/api/vehicle/model/adrDetailsVehicleDetails.ts index 426af68ac1..62346e9b3d 100644 --- a/src/app/api/vehicle/model/adrDetailsVehicleDetails.ts +++ b/src/app/api/vehicle/model/adrDetailsVehicleDetails.ts @@ -9,13 +9,13 @@ * Do not edit the class manually. */ -export interface AdrDetailsVehicleDetails { - /** - * Mandatory. Users must select ONE of these. Users cannot select less/more - */ - type?: string; - /** - * Date (YYYY-MM-DD) - */ - approvalDate?: string; -} \ No newline at end of file +export interface AdrDetailsVehicleDetails { + /** + * Mandatory. Users must select ONE of these. Users cannot select less/more + */ + type?: string; + /** + * Date (YYYY-MM-DD) + */ + approvalDate?: string; +} diff --git a/src/app/api/vehicle/model/applicantDetailsProperties.ts b/src/app/api/vehicle/model/applicantDetailsProperties.ts index a2c7b8922e..0f6443b1f7 100644 --- a/src/app/api/vehicle/model/applicantDetailsProperties.ts +++ b/src/app/api/vehicle/model/applicantDetailsProperties.ts @@ -12,13 +12,13 @@ /** * Used for all vehicle types */ -export interface ApplicantDetailsProperties { - name?: string; - address1?: string; - address2?: string; - postTown?: string; - address3?: string; - postCode?: string; - emailAddress?: string; - telephoneNumber?: string; -} \ No newline at end of file +export interface ApplicantDetailsProperties { + name?: string; + address1?: string; + address2?: string; + postTown?: string; + address3?: string; + postCode?: string; + emailAddress?: string; + telephoneNumber?: string; +} diff --git a/src/app/api/vehicle/model/authIntoService.ts b/src/app/api/vehicle/model/authIntoService.ts index 4aee7abb64..6aeaf4598d 100644 --- a/src/app/api/vehicle/model/authIntoService.ts +++ b/src/app/api/vehicle/model/authIntoService.ts @@ -12,25 +12,25 @@ /** * Authorization into service */ -export interface AuthIntoService { - /** - * Used only for TRL - */ - cocIssueDate?: string; - /** - * Used only for TRL - */ - dateReceived?: string; - /** - * Used only for TRL - */ - datePending?: string; - /** - * Used only for TRL - */ - dateAuthorised?: string; - /** - * Used only for TRL - */ - dateRejected?: string; -} \ No newline at end of file +export interface AuthIntoService { + /** + * Used only for TRL + */ + cocIssueDate?: string; + /** + * Used only for TRL + */ + dateReceived?: string; + /** + * Used only for TRL + */ + datePending?: string; + /** + * Used only for TRL + */ + dateAuthorised?: string; + /** + * Used only for TRL + */ + dateRejected?: string; +} diff --git a/src/app/api/vehicle/model/axleBrakeProperties.ts b/src/app/api/vehicle/model/axleBrakeProperties.ts index 98f174d6bd..c0b9c41db0 100644 --- a/src/app/api/vehicle/model/axleBrakeProperties.ts +++ b/src/app/api/vehicle/model/axleBrakeProperties.ts @@ -12,8 +12,8 @@ /** * Used only for TRL */ -export interface AxleBrakeProperties { - brakeActuator?: number; - leverLength?: number; - springBrakeParking?: boolean; -} \ No newline at end of file +export interface AxleBrakeProperties { + brakeActuator?: number; + leverLength?: number; + springBrakeParking?: boolean; +} diff --git a/src/app/api/vehicle/model/axleTyreProperties.ts b/src/app/api/vehicle/model/axleTyreProperties.ts index b710ca19ce..cf2ca08122 100644 --- a/src/app/api/vehicle/model/axleTyreProperties.ts +++ b/src/app/api/vehicle/model/axleTyreProperties.ts @@ -9,54 +9,69 @@ * Do not edit the class manually. */ -export interface AxleTyreProperties { - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - tyreSize?: string; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - plyRating?: string; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - fitmentCode?: AxleTyreProperties.FitmentCodeEnum; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - dataTrAxles?: number; - /** - * Used only for PSV - */ - speedCategorySymbol?: AxleTyreProperties.SpeedCategorySymbolEnum; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - tyreCode?: number; +export interface AxleTyreProperties { + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + tyreSize?: string; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + plyRating?: string; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + fitmentCode?: AxleTyreProperties.FitmentCodeEnum; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + dataTrAxles?: number; + /** + * Used only for PSV + */ + speedCategorySymbol?: AxleTyreProperties.SpeedCategorySymbolEnum; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + tyreCode?: number; } export namespace AxleTyreProperties { - export type FitmentCodeEnum = 'double' | 'single'; - export const FitmentCodeEnum = { - Double: 'double' as FitmentCodeEnum, - Single: 'single' as FitmentCodeEnum - }; - export type SpeedCategorySymbolEnum = 'a7' | 'a8' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'j' | 'k' | 'l' | 'm' | 'n' | 'p' | 'q'; - export const SpeedCategorySymbolEnum = { - A7: 'a7' as SpeedCategorySymbolEnum, - A8: 'a8' as SpeedCategorySymbolEnum, - B: 'b' as SpeedCategorySymbolEnum, - C: 'c' as SpeedCategorySymbolEnum, - D: 'd' as SpeedCategorySymbolEnum, - E: 'e' as SpeedCategorySymbolEnum, - F: 'f' as SpeedCategorySymbolEnum, - G: 'g' as SpeedCategorySymbolEnum, - J: 'j' as SpeedCategorySymbolEnum, - K: 'k' as SpeedCategorySymbolEnum, - L: 'l' as SpeedCategorySymbolEnum, - M: 'm' as SpeedCategorySymbolEnum, - N: 'n' as SpeedCategorySymbolEnum, - P: 'p' as SpeedCategorySymbolEnum, - Q: 'q' as SpeedCategorySymbolEnum - }; -} \ No newline at end of file + export type FitmentCodeEnum = 'double' | 'single'; + export const FitmentCodeEnum = { + Double: 'double' as FitmentCodeEnum, + Single: 'single' as FitmentCodeEnum, + }; + export type SpeedCategorySymbolEnum = + | 'a7' + | 'a8' + | 'b' + | 'c' + | 'd' + | 'e' + | 'f' + | 'g' + | 'j' + | 'k' + | 'l' + | 'm' + | 'n' + | 'p' + | 'q'; + export const SpeedCategorySymbolEnum = { + A7: 'a7' as SpeedCategorySymbolEnum, + A8: 'a8' as SpeedCategorySymbolEnum, + B: 'b' as SpeedCategorySymbolEnum, + C: 'c' as SpeedCategorySymbolEnum, + D: 'd' as SpeedCategorySymbolEnum, + E: 'e' as SpeedCategorySymbolEnum, + F: 'f' as SpeedCategorySymbolEnum, + G: 'g' as SpeedCategorySymbolEnum, + J: 'j' as SpeedCategorySymbolEnum, + K: 'k' as SpeedCategorySymbolEnum, + L: 'l' as SpeedCategorySymbolEnum, + M: 'm' as SpeedCategorySymbolEnum, + N: 'n' as SpeedCategorySymbolEnum, + P: 'p' as SpeedCategorySymbolEnum, + Q: 'q' as SpeedCategorySymbolEnum, + }; +} diff --git a/src/app/api/vehicle/model/axleWeightProperties.ts b/src/app/api/vehicle/model/axleWeightProperties.ts index 16f32cfe2d..ac8064379d 100644 --- a/src/app/api/vehicle/model/axleWeightProperties.ts +++ b/src/app/api/vehicle/model/axleWeightProperties.ts @@ -9,25 +9,25 @@ * Do not edit the class manually. */ -export interface AxleWeightProperties { - /** - * Used only for PSV - */ - kerbWeight?: number; - /** - * Used only for PSV - */ - ladenWeight?: number; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - gbWeight?: number; - /** - * Used only for HGV and TRL - */ - eecWeight?: number; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - designWeight?: number; -} \ No newline at end of file +export interface AxleWeightProperties { + /** + * Used only for PSV + */ + kerbWeight?: number; + /** + * Used only for PSV + */ + ladenWeight?: number; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + gbWeight?: number; + /** + * Used only for HGV and TRL + */ + eecWeight?: number; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + designWeight?: number; +} diff --git a/src/app/api/vehicle/model/axles.ts b/src/app/api/vehicle/model/axles.ts index fc4ba71a07..ad9f2b858d 100644 --- a/src/app/api/vehicle/model/axles.ts +++ b/src/app/api/vehicle/model/axles.ts @@ -10,5 +10,4 @@ */ import { Weights } from './weights'; -export interface Axles extends Array { -} \ No newline at end of file +export interface Axles extends Array {} diff --git a/src/app/api/vehicle/model/brakeForceWheelsNotLocked.ts b/src/app/api/vehicle/model/brakeForceWheelsNotLocked.ts index 9b9a7f2a80..dc798eae8b 100644 --- a/src/app/api/vehicle/model/brakeForceWheelsNotLocked.ts +++ b/src/app/api/vehicle/model/brakeForceWheelsNotLocked.ts @@ -9,17 +9,17 @@ * Do not edit the class manually. */ -export interface BrakeForceWheelsNotLocked { - /** - * Used only for PSV - */ - serviceBrakeForceA?: number; - /** - * Used only for PSV - */ - secondaryBrakeForceA?: number; - /** - * Used only for PSV - */ - parkingBrakeForceA?: number; -} \ No newline at end of file +export interface BrakeForceWheelsNotLocked { + /** + * Used only for PSV + */ + serviceBrakeForceA?: number; + /** + * Used only for PSV + */ + secondaryBrakeForceA?: number; + /** + * Used only for PSV + */ + parkingBrakeForceA?: number; +} diff --git a/src/app/api/vehicle/model/brakeForceWheelsUpToHalfLocked.ts b/src/app/api/vehicle/model/brakeForceWheelsUpToHalfLocked.ts index 03b7a04818..a5aa6b8ad7 100644 --- a/src/app/api/vehicle/model/brakeForceWheelsUpToHalfLocked.ts +++ b/src/app/api/vehicle/model/brakeForceWheelsUpToHalfLocked.ts @@ -9,17 +9,17 @@ * Do not edit the class manually. */ -export interface BrakeForceWheelsUpToHalfLocked { - /** - * Used only for PSV - */ - serviceBrakeForceB?: number; - /** - * Used only for PSV - */ - secondaryBrakeForceB?: number; - /** - * Used only for PSV - */ - parkingBrakeForceB?: number; -} \ No newline at end of file +export interface BrakeForceWheelsUpToHalfLocked { + /** + * Used only for PSV + */ + serviceBrakeForceB?: number; + /** + * Used only for PSV + */ + secondaryBrakeForceB?: number; + /** + * Used only for PSV + */ + parkingBrakeForceB?: number; +} diff --git a/src/app/api/vehicle/model/brakes.ts b/src/app/api/vehicle/model/brakes.ts index 59315a8f2e..4983aafa5e 100644 --- a/src/app/api/vehicle/model/brakes.ts +++ b/src/app/api/vehicle/model/brakes.ts @@ -11,67 +11,67 @@ import { BrakeForceWheelsNotLocked } from './brakeForceWheelsNotLocked'; import { BrakeForceWheelsUpToHalfLocked } from './brakeForceWheelsUpToHalfLocked'; -export interface Brakes { - /** - * Used only for PSV - */ - brakeCodeOriginal?: string; - /** - * Used only for PSV - */ - brakeCode?: string; - /** - * Used only for PSV - */ - dataTrBrakeOne?: string; - /** - * Used only for PSV - */ - dataTrBrakeTwo?: string; - /** - * Used only for PSV - */ - dataTrBrakeThree?: string; - /** - * Used only for PSV - */ - retarderBrakeOne?: Brakes.RetarderBrakeOneEnum; - /** - * Used only for PSV - */ - retarderBrakeTwo?: Brakes.RetarderBrakeTwoEnum; - /** - * Used for PSV, HGV and TRL - */ - dtpNumber?: string; - brakeForceWheelsNotLocked?: BrakeForceWheelsNotLocked; - brakeForceWheelsUpToHalfLocked?: BrakeForceWheelsUpToHalfLocked; - /** - * Used only for TRL - */ - loadSensingValve?: boolean; - /** - * Used only for TRL - */ - antilockBrakingSystem?: boolean; +export interface Brakes { + /** + * Used only for PSV + */ + brakeCodeOriginal?: string; + /** + * Used only for PSV + */ + brakeCode?: string; + /** + * Used only for PSV + */ + dataTrBrakeOne?: string; + /** + * Used only for PSV + */ + dataTrBrakeTwo?: string; + /** + * Used only for PSV + */ + dataTrBrakeThree?: string; + /** + * Used only for PSV + */ + retarderBrakeOne?: Brakes.RetarderBrakeOneEnum; + /** + * Used only for PSV + */ + retarderBrakeTwo?: Brakes.RetarderBrakeTwoEnum; + /** + * Used for PSV, HGV and TRL + */ + dtpNumber?: string; + brakeForceWheelsNotLocked?: BrakeForceWheelsNotLocked; + brakeForceWheelsUpToHalfLocked?: BrakeForceWheelsUpToHalfLocked; + /** + * Used only for TRL + */ + loadSensingValve?: boolean; + /** + * Used only for TRL + */ + antilockBrakingSystem?: boolean; } export namespace Brakes { - export type RetarderBrakeOneEnum = 'electric' | 'exhaust' | 'friction' | 'hydraulic' | 'other' | 'none'; - export const RetarderBrakeOneEnum = { - Electric: 'electric' as RetarderBrakeOneEnum, - Exhaust: 'exhaust' as RetarderBrakeOneEnum, - Friction: 'friction' as RetarderBrakeOneEnum, - Hydraulic: 'hydraulic' as RetarderBrakeOneEnum, - Other: 'other' as RetarderBrakeOneEnum, - None: 'none' as RetarderBrakeOneEnum - }; - export type RetarderBrakeTwoEnum = 'electric' | 'exhaust' | 'friction' | 'hydraulic' | 'other' | 'none'; - export const RetarderBrakeTwoEnum = { - Electric: 'electric' as RetarderBrakeTwoEnum, - Exhaust: 'exhaust' as RetarderBrakeTwoEnum, - Friction: 'friction' as RetarderBrakeTwoEnum, - Hydraulic: 'hydraulic' as RetarderBrakeTwoEnum, - Other: 'other' as RetarderBrakeTwoEnum, - None: 'none' as RetarderBrakeTwoEnum - }; -} \ No newline at end of file + export type RetarderBrakeOneEnum = 'electric' | 'exhaust' | 'friction' | 'hydraulic' | 'other' | 'none'; + export const RetarderBrakeOneEnum = { + Electric: 'electric' as RetarderBrakeOneEnum, + Exhaust: 'exhaust' as RetarderBrakeOneEnum, + Friction: 'friction' as RetarderBrakeOneEnum, + Hydraulic: 'hydraulic' as RetarderBrakeOneEnum, + Other: 'other' as RetarderBrakeOneEnum, + None: 'none' as RetarderBrakeOneEnum, + }; + export type RetarderBrakeTwoEnum = 'electric' | 'exhaust' | 'friction' | 'hydraulic' | 'other' | 'none'; + export const RetarderBrakeTwoEnum = { + Electric: 'electric' as RetarderBrakeTwoEnum, + Exhaust: 'exhaust' as RetarderBrakeTwoEnum, + Friction: 'friction' as RetarderBrakeTwoEnum, + Hydraulic: 'hydraulic' as RetarderBrakeTwoEnum, + Other: 'other' as RetarderBrakeTwoEnum, + None: 'none' as RetarderBrakeTwoEnum, + }; +} diff --git a/src/app/api/vehicle/model/completeTechRecord.ts b/src/app/api/vehicle/model/completeTechRecord.ts index fdf6a86f98..1c40d4e552 100644 --- a/src/app/api/vehicle/model/completeTechRecord.ts +++ b/src/app/api/vehicle/model/completeTechRecord.ts @@ -12,20 +12,20 @@ import { Metadata } from './metadata'; import { TechRecords } from './techRecords'; import { Vrms } from './vrms'; -export interface CompleteTechRecord { - /** - * It defines the composed primary key, in combination with \"vin\". - */ - systemNumber?: string; - vrms?: Vrms; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - vin?: string; - /** - * Used only for TRL - */ - trailerId?: string; - techRecord?: TechRecords; - metadata?: Metadata; -} \ No newline at end of file +export interface CompleteTechRecord { + /** + * It defines the composed primary key, in combination with \"vin\". + */ + systemNumber?: string; + vrms?: Vrms; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + vin?: string; + /** + * Used only for TRL + */ + trailerId?: string; + techRecord?: TechRecords; + metadata?: Metadata; +} diff --git a/src/app/api/vehicle/model/completeTechRecordDB.ts b/src/app/api/vehicle/model/completeTechRecordDB.ts index 4658f27478..870b4261b2 100644 --- a/src/app/api/vehicle/model/completeTechRecordDB.ts +++ b/src/app/api/vehicle/model/completeTechRecordDB.ts @@ -13,21 +13,21 @@ import { TechRecords } from './techRecords'; /** * the Tech objects as they */ -export interface CompleteTechRecordDB { - /** - * It defines the composed primary key, in combination with \"vin\". - */ - systemNumber?: string; - partialVin?: string; - primaryVrm?: string; - secondaryVrms?: Array; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - vin?: string; - /** - * Used only for TRL - */ - trailerId?: string; - techRecord?: TechRecords; -} \ No newline at end of file +export interface CompleteTechRecordDB { + /** + * It defines the composed primary key, in combination with \"vin\". + */ + systemNumber?: string; + partialVin?: string; + primaryVrm?: string; + secondaryVrms?: Array; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + vin?: string; + /** + * Used only for TRL + */ + trailerId?: string; + techRecord?: TechRecords; +} diff --git a/src/app/api/vehicle/model/completeTechRecordPUT.ts b/src/app/api/vehicle/model/completeTechRecordPUT.ts index 9252c923ba..78a5f022c6 100644 --- a/src/app/api/vehicle/model/completeTechRecordPUT.ts +++ b/src/app/api/vehicle/model/completeTechRecordPUT.ts @@ -11,19 +11,19 @@ import { TechRecords } from './techRecords'; import { Vrms } from './vrms'; -export interface CompleteTechRecordPUT { - /** - * It defines the composed primary key, in combination with \"vin\". - */ - systemNumber?: string; - vrms?: Vrms; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - vin?: string; - /** - * Used only for TRL - */ - trailerId?: string; - techRecord?: TechRecords; -} \ No newline at end of file +export interface CompleteTechRecordPUT { + /** + * It defines the composed primary key, in combination with \"vin\". + */ + systemNumber?: string; + vrms?: Vrms; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + vin?: string; + /** + * Used only for TRL + */ + trailerId?: string; + techRecord?: TechRecords; +} diff --git a/src/app/api/vehicle/model/completeTechRecords.ts b/src/app/api/vehicle/model/completeTechRecords.ts index 4f754e34c0..2cbc2c536c 100644 --- a/src/app/api/vehicle/model/completeTechRecords.ts +++ b/src/app/api/vehicle/model/completeTechRecords.ts @@ -10,5 +10,4 @@ */ import { CompleteTechRecord } from './completeTechRecord'; -export interface CompleteTechRecords extends Array { -} \ No newline at end of file +export interface CompleteTechRecords extends Array {} diff --git a/src/app/api/vehicle/model/dda.ts b/src/app/api/vehicle/model/dda.ts index df3e575f26..498d17b66a 100644 --- a/src/app/api/vehicle/model/dda.ts +++ b/src/app/api/vehicle/model/dda.ts @@ -12,53 +12,53 @@ /** * Disability Discrimination Act */ -export interface Dda { - /** - * Used only for PSV - */ - certificateIssued?: boolean; - /** - * Used only for PSV - */ - wheelchairCapacity?: number; - /** - * Used only for PSV - */ - wheelchairFittings?: string; - /** - * Used only for PSV - */ - wheelchairLiftPresent?: boolean; - /** - * Used only for PSV - */ - wheelchairLiftInformation?: string; - /** - * Used only for PSV - */ - wheelchairRampPresent?: boolean; - /** - * Used only for PSV - */ - wheelchairRampInformation?: string; - /** - * Used only for PSV - */ - minEmergencyExits?: number; - /** - * Used only for PSV - */ - outswing?: string; - /** - * Used only for PSV - */ - ddaSchedules?: string; - /** - * Used only for PSV - */ - seatbeltsFitted?: number; - /** - * Used only for PSV - */ - ddaNotes?: string; -} \ No newline at end of file +export interface Dda { + /** + * Used only for PSV + */ + certificateIssued?: boolean; + /** + * Used only for PSV + */ + wheelchairCapacity?: number; + /** + * Used only for PSV + */ + wheelchairFittings?: string; + /** + * Used only for PSV + */ + wheelchairLiftPresent?: boolean; + /** + * Used only for PSV + */ + wheelchairLiftInformation?: string; + /** + * Used only for PSV + */ + wheelchairRampPresent?: boolean; + /** + * Used only for PSV + */ + wheelchairRampInformation?: string; + /** + * Used only for PSV + */ + minEmergencyExits?: number; + /** + * Used only for PSV + */ + outswing?: string; + /** + * Used only for PSV + */ + ddaSchedules?: string; + /** + * Used only for PSV + */ + seatbeltsFitted?: number; + /** + * Used only for PSV + */ + ddaNotes?: string; +} diff --git a/src/app/api/vehicle/model/lettersOfAuth.ts b/src/app/api/vehicle/model/lettersOfAuth.ts index 52bb09af9e..5847c16708 100644 --- a/src/app/api/vehicle/model/lettersOfAuth.ts +++ b/src/app/api/vehicle/model/lettersOfAuth.ts @@ -12,24 +12,24 @@ /** * Letters of authorisation */ -export interface LettersOfAuth { - /** - * Used only for TRL - */ - letterType?: LettersOfAuth.LetterTypeEnum; - /** - * Used only for TRL - */ - letterDateRequested?: string; - /** - * Used only for TRL - */ - letterContents?: string; +export interface LettersOfAuth { + /** + * Used only for TRL + */ + letterType?: LettersOfAuth.LetterTypeEnum; + /** + * Used only for TRL + */ + letterDateRequested?: string; + /** + * Used only for TRL + */ + letterContents?: string; } export namespace LettersOfAuth { - export type LetterTypeEnum = 'Trailer authorization' | 'Trailer rejection'; - export const LetterTypeEnum = { - Authorization: 'Trailer authorization' as LetterTypeEnum, - Rejection: 'Trailer rejection' as LetterTypeEnum - }; -} \ No newline at end of file + export type LetterTypeEnum = 'Trailer authorization' | 'Trailer rejection'; + export const LetterTypeEnum = { + Authorization: 'Trailer authorization' as LetterTypeEnum, + Rejection: 'Trailer rejection' as LetterTypeEnum, + }; +} diff --git a/src/app/api/vehicle/model/manufacturerDetails.ts b/src/app/api/vehicle/model/manufacturerDetails.ts index 3e6f9e2050..401f693735 100644 --- a/src/app/api/vehicle/model/manufacturerDetails.ts +++ b/src/app/api/vehicle/model/manufacturerDetails.ts @@ -12,15 +12,15 @@ /** * Used for TRL only */ -export interface ManufacturerDetails { - name?: string; - address1?: string; - address2?: string; - postTown?: string; - address3?: string; - postCode?: string; - emailAddress?: string; - telephoneNumber?: string; - faxNumber?: string; - manufacturerNotes?: string; -} \ No newline at end of file +export interface ManufacturerDetails { + name?: string; + address1?: string; + address2?: string; + postTown?: string; + address3?: string; + postCode?: string; + emailAddress?: string; + telephoneNumber?: string; + faxNumber?: string; + manufacturerNotes?: string; +} diff --git a/src/app/api/vehicle/model/metadata.ts b/src/app/api/vehicle/model/metadata.ts index 4bfc91960f..9df852c501 100644 --- a/src/app/api/vehicle/model/metadata.ts +++ b/src/app/api/vehicle/model/metadata.ts @@ -13,11 +13,11 @@ import { MetadataAdrDetails } from './metadataAdrDetails'; /** * Applicable only to ADR details. Returned only if query param \"metadata\" = \"true\", otherwise not returned */ -export interface Metadata { - /** - * makeFe and chassisMakeFe fields have the same value. Combining them into a field for now so we don't send the same list twice. - */ - makeAndChassisMakeFe?: Array; - bodyMakeFe?: Array; - adrDetails?: MetadataAdrDetails; -} \ No newline at end of file +export interface Metadata { + /** + * makeFe and chassisMakeFe fields have the same value. Combining them into a field for now so we don't send the same list twice. + */ + makeAndChassisMakeFe?: Array; + bodyMakeFe?: Array; + adrDetails?: MetadataAdrDetails; +} diff --git a/src/app/api/vehicle/model/metadataAdrDetails.ts b/src/app/api/vehicle/model/metadataAdrDetails.ts index aac6b48499..c02f4b7655 100644 --- a/src/app/api/vehicle/model/metadataAdrDetails.ts +++ b/src/app/api/vehicle/model/metadataAdrDetails.ts @@ -12,27 +12,35 @@ import { MetadataAdrDetailsAdditionalNotes } from './metadataAdrDetailsAdditiona import { MetadataAdrDetailsTank } from './metadataAdrDetailsTank'; import { MetadataAdrDetailsVehicleDetails } from './metadataAdrDetailsVehicleDetails'; -export interface MetadataAdrDetails { - memosApplyFe?: Array; - tank?: MetadataAdrDetailsTank; - additionalNotes?: MetadataAdrDetailsAdditionalNotes; - permittedDangerousGoodsFe?: Array; - vehicleDetails?: MetadataAdrDetailsVehicleDetails; +export interface MetadataAdrDetails { + memosApplyFe?: Array; + tank?: MetadataAdrDetailsTank; + additionalNotes?: MetadataAdrDetailsAdditionalNotes; + permittedDangerousGoodsFe?: Array; + vehicleDetails?: MetadataAdrDetailsVehicleDetails; } export namespace MetadataAdrDetails { - export type MemosApplyFeEnum = '07/09 3mth leak ext'; - export const MemosApplyFeEnum = { - _07093mthLeakExt: '07/09 3mth leak ext' as MemosApplyFeEnum - }; - export type PermittedDangerousGoodsFeEnum = 'FP <61 (FL)' | 'AT' | 'Class 5.1 Hydrogen Peroxide (OX)' | 'MEMU' | 'Carbon Disulphide' | 'Hydrogen' | 'Explosives (type 2)' | 'Explosives (type 3)'; - export const PermittedDangerousGoodsFeEnum = { - FP61FL: 'FP <61 (FL)' as PermittedDangerousGoodsFeEnum, - AT: 'AT' as PermittedDangerousGoodsFeEnum, - Class51HydrogenPeroxideOX: 'Class 5.1 Hydrogen Peroxide (OX)' as PermittedDangerousGoodsFeEnum, - MEMU: 'MEMU' as PermittedDangerousGoodsFeEnum, - CarbonDisulphide: 'Carbon Disulphide' as PermittedDangerousGoodsFeEnum, - Hydrogen: 'Hydrogen' as PermittedDangerousGoodsFeEnum, - ExplosivesType2: 'Explosives (type 2)' as PermittedDangerousGoodsFeEnum, - ExplosivesType3: 'Explosives (type 3)' as PermittedDangerousGoodsFeEnum - }; -} \ No newline at end of file + export type MemosApplyFeEnum = '07/09 3mth leak ext'; + export const MemosApplyFeEnum = { + _07093mthLeakExt: '07/09 3mth leak ext' as MemosApplyFeEnum, + }; + export type PermittedDangerousGoodsFeEnum = + | 'FP <61 (FL)' + | 'AT' + | 'Class 5.1 Hydrogen Peroxide (OX)' + | 'MEMU' + | 'Carbon Disulphide' + | 'Hydrogen' + | 'Explosives (type 2)' + | 'Explosives (type 3)'; + export const PermittedDangerousGoodsFeEnum = { + FP61FL: 'FP <61 (FL)' as PermittedDangerousGoodsFeEnum, + AT: 'AT' as PermittedDangerousGoodsFeEnum, + Class51HydrogenPeroxideOX: 'Class 5.1 Hydrogen Peroxide (OX)' as PermittedDangerousGoodsFeEnum, + MEMU: 'MEMU' as PermittedDangerousGoodsFeEnum, + CarbonDisulphide: 'Carbon Disulphide' as PermittedDangerousGoodsFeEnum, + Hydrogen: 'Hydrogen' as PermittedDangerousGoodsFeEnum, + ExplosivesType2: 'Explosives (type 2)' as PermittedDangerousGoodsFeEnum, + ExplosivesType3: 'Explosives (type 3)' as PermittedDangerousGoodsFeEnum, + }; +} diff --git a/src/app/api/vehicle/model/metadataAdrDetailsAdditionalNotes.ts b/src/app/api/vehicle/model/metadataAdrDetailsAdditionalNotes.ts index 9011d60033..35eac3d117 100644 --- a/src/app/api/vehicle/model/metadataAdrDetailsAdditionalNotes.ts +++ b/src/app/api/vehicle/model/metadataAdrDetailsAdditionalNotes.ts @@ -9,22 +9,22 @@ * Do not edit the class manually. */ -export interface MetadataAdrDetailsAdditionalNotes { - guidanceNotesFe?: Array; - numberFe?: Array; +export interface MetadataAdrDetailsAdditionalNotes { + guidanceNotesFe?: Array; + numberFe?: Array; } export namespace MetadataAdrDetailsAdditionalNotes { - export type GuidanceNotesFeEnum = 'New certificate requested'; - export const GuidanceNotesFeEnum = { - NewCertificateRequested: 'New certificate requested' as GuidanceNotesFeEnum - }; - export type NumberFeEnum = '1' | '1A' | '2' | '3' | 'V1B' | 'T1B'; - export const NumberFeEnum = { - _1: '1' as NumberFeEnum, - _1A: '1A' as NumberFeEnum, - _2: '2' as NumberFeEnum, - _3: '3' as NumberFeEnum, - V1B: 'V1B' as NumberFeEnum, - T1B: 'T1B' as NumberFeEnum - }; -} \ No newline at end of file + export type GuidanceNotesFeEnum = 'New certificate requested'; + export const GuidanceNotesFeEnum = { + NewCertificateRequested: 'New certificate requested' as GuidanceNotesFeEnum, + }; + export type NumberFeEnum = '1' | '1A' | '2' | '3' | 'V1B' | 'T1B'; + export const NumberFeEnum = { + _1: '1' as NumberFeEnum, + _1A: '1A' as NumberFeEnum, + _2: '2' as NumberFeEnum, + _3: '3' as NumberFeEnum, + V1B: 'V1B' as NumberFeEnum, + T1B: 'T1B' as NumberFeEnum, + }; +} diff --git a/src/app/api/vehicle/model/metadataAdrDetailsTank.ts b/src/app/api/vehicle/model/metadataAdrDetailsTank.ts index 04da799d47..0154955b4e 100644 --- a/src/app/api/vehicle/model/metadataAdrDetailsTank.ts +++ b/src/app/api/vehicle/model/metadataAdrDetailsTank.ts @@ -10,6 +10,6 @@ */ import { MetadataAdrDetailsTankTankStatement } from './metadataAdrDetailsTankTankStatement'; -export interface MetadataAdrDetailsTank { - tankStatement?: MetadataAdrDetailsTankTankStatement; -} \ No newline at end of file +export interface MetadataAdrDetailsTank { + tankStatement?: MetadataAdrDetailsTankTankStatement; +} diff --git a/src/app/api/vehicle/model/metadataAdrDetailsTankTankStatement.ts b/src/app/api/vehicle/model/metadataAdrDetailsTankTankStatement.ts index 1942aace09..efdb7d4ceb 100644 --- a/src/app/api/vehicle/model/metadataAdrDetailsTankTankStatement.ts +++ b/src/app/api/vehicle/model/metadataAdrDetailsTankTankStatement.ts @@ -9,13 +9,17 @@ * Do not edit the class manually. */ -export interface MetadataAdrDetailsTankTankStatement { - substancesPermittedFe?: Array; +export interface MetadataAdrDetailsTankTankStatement { + substancesPermittedFe?: Array; } export namespace MetadataAdrDetailsTankTankStatement { - export type SubstancesPermittedFeEnum = 'Substances permitted under the tank code and any special provisions specified in 9 may be carried' | 'Substances (Class UN number and if necessary packing group and proper shipping name) may be carried'; - export const SubstancesPermittedFeEnum = { - PermittedUnderTheTankCodeAndAnySpecialProvisionsSpecifiedIn9MayBeCarried: 'Substances permitted under the tank code and any special provisions specified in 9 may be carried' as SubstancesPermittedFeEnum, - ClassUNNumberAndIfNecessaryPackingGroupAndProperShippingNameMayBeCarried: 'Substances (Class UN number and if necessary packing group and proper shipping name) may be carried' as SubstancesPermittedFeEnum - }; -} \ No newline at end of file + export type SubstancesPermittedFeEnum = + | 'Substances permitted under the tank code and any special provisions specified in 9 may be carried' + | 'Substances (Class UN number and if necessary packing group and proper shipping name) may be carried'; + export const SubstancesPermittedFeEnum = { + PermittedUnderTheTankCodeAndAnySpecialProvisionsSpecifiedIn9MayBeCarried: + 'Substances permitted under the tank code and any special provisions specified in 9 may be carried' as SubstancesPermittedFeEnum, + ClassUNNumberAndIfNecessaryPackingGroupAndProperShippingNameMayBeCarried: + 'Substances (Class UN number and if necessary packing group and proper shipping name) may be carried' as SubstancesPermittedFeEnum, + }; +} diff --git a/src/app/api/vehicle/model/metadataAdrDetailsVehicleDetails.ts b/src/app/api/vehicle/model/metadataAdrDetailsVehicleDetails.ts index f61106d130..a16b6532a0 100644 --- a/src/app/api/vehicle/model/metadataAdrDetailsVehicleDetails.ts +++ b/src/app/api/vehicle/model/metadataAdrDetailsVehicleDetails.ts @@ -9,32 +9,53 @@ * Do not edit the class manually. */ -export interface MetadataAdrDetailsVehicleDetails { - typeFe?: Array; +export interface MetadataAdrDetailsVehicleDetails { + typeFe?: Array; } export namespace MetadataAdrDetailsVehicleDetails { - export type TypeFeEnum = 'Artic tractor' | 'Rigid box body' | 'Rigid sheeted load' | 'Rigid tank' | 'Rigid skeletal' | 'Rigid battery' | 'Full drawbar box body' | 'Full drawbar sheeted load' | 'Full drawbar tank' | 'Full drawbar skeletal' | 'Full drawbar battery' | 'Centre axle box body' | 'Centre axle sheeted load' | 'Centre axle tank' | 'Centre axle skeletal' | 'Centre axle battery' | 'Semi trailer box body' | 'Semi trailer sheeted load' | 'Semi trailer tank' | 'Semi trailer skeletal' | 'Semi trailer battery'; - export const TypeFeEnum = { - ArticTractor: 'Artic tractor' as TypeFeEnum, - RigidBoxBody: 'Rigid box body' as TypeFeEnum, - RigidSheetedLoad: 'Rigid sheeted load' as TypeFeEnum, - RigidTank: 'Rigid tank' as TypeFeEnum, - RigidSkeletal: 'Rigid skeletal' as TypeFeEnum, - RigidBattery: 'Rigid battery' as TypeFeEnum, - FullDrawbarBoxBody: 'Full drawbar box body' as TypeFeEnum, - FullDrawbarSheetedLoad: 'Full drawbar sheeted load' as TypeFeEnum, - FullDrawbarTank: 'Full drawbar tank' as TypeFeEnum, - FullDrawbarSkeletal: 'Full drawbar skeletal' as TypeFeEnum, - FullDrawbarBattery: 'Full drawbar battery' as TypeFeEnum, - CentreAxleBoxBody: 'Centre axle box body' as TypeFeEnum, - CentreAxleSheetedLoad: 'Centre axle sheeted load' as TypeFeEnum, - CentreAxleTank: 'Centre axle tank' as TypeFeEnum, - CentreAxleSkeletal: 'Centre axle skeletal' as TypeFeEnum, - CentreAxleBattery: 'Centre axle battery' as TypeFeEnum, - SemiTrailerBoxBody: 'Semi trailer box body' as TypeFeEnum, - SemiTrailerSheetedLoad: 'Semi trailer sheeted load' as TypeFeEnum, - SemiTrailerTank: 'Semi trailer tank' as TypeFeEnum, - SemiTrailerSkeletal: 'Semi trailer skeletal' as TypeFeEnum, - SemiTrailerBattery: 'Semi trailer battery' as TypeFeEnum - }; -} \ No newline at end of file + export type TypeFeEnum = + | 'Artic tractor' + | 'Rigid box body' + | 'Rigid sheeted load' + | 'Rigid tank' + | 'Rigid skeletal' + | 'Rigid battery' + | 'Full drawbar box body' + | 'Full drawbar sheeted load' + | 'Full drawbar tank' + | 'Full drawbar skeletal' + | 'Full drawbar battery' + | 'Centre axle box body' + | 'Centre axle sheeted load' + | 'Centre axle tank' + | 'Centre axle skeletal' + | 'Centre axle battery' + | 'Semi trailer box body' + | 'Semi trailer sheeted load' + | 'Semi trailer tank' + | 'Semi trailer skeletal' + | 'Semi trailer battery'; + export const TypeFeEnum = { + ArticTractor: 'Artic tractor' as TypeFeEnum, + RigidBoxBody: 'Rigid box body' as TypeFeEnum, + RigidSheetedLoad: 'Rigid sheeted load' as TypeFeEnum, + RigidTank: 'Rigid tank' as TypeFeEnum, + RigidSkeletal: 'Rigid skeletal' as TypeFeEnum, + RigidBattery: 'Rigid battery' as TypeFeEnum, + FullDrawbarBoxBody: 'Full drawbar box body' as TypeFeEnum, + FullDrawbarSheetedLoad: 'Full drawbar sheeted load' as TypeFeEnum, + FullDrawbarTank: 'Full drawbar tank' as TypeFeEnum, + FullDrawbarSkeletal: 'Full drawbar skeletal' as TypeFeEnum, + FullDrawbarBattery: 'Full drawbar battery' as TypeFeEnum, + CentreAxleBoxBody: 'Centre axle box body' as TypeFeEnum, + CentreAxleSheetedLoad: 'Centre axle sheeted load' as TypeFeEnum, + CentreAxleTank: 'Centre axle tank' as TypeFeEnum, + CentreAxleSkeletal: 'Centre axle skeletal' as TypeFeEnum, + CentreAxleBattery: 'Centre axle battery' as TypeFeEnum, + SemiTrailerBoxBody: 'Semi trailer box body' as TypeFeEnum, + SemiTrailerSheetedLoad: 'Semi trailer sheeted load' as TypeFeEnum, + SemiTrailerTank: 'Semi trailer tank' as TypeFeEnum, + SemiTrailerSkeletal: 'Semi trailer skeletal' as TypeFeEnum, + SemiTrailerBattery: 'Semi trailer battery' as TypeFeEnum, + }; +} diff --git a/src/app/api/vehicle/model/microfilm.ts b/src/app/api/vehicle/model/microfilm.ts index 6dd73f446e..71b84a2b1b 100644 --- a/src/app/api/vehicle/model/microfilm.ts +++ b/src/app/api/vehicle/model/microfilm.ts @@ -9,77 +9,132 @@ * Do not edit the class manually. */ -export interface Microfilm { - /** - * Used for all vehicle types - */ - microfilmDocumentType?: Microfilm.MicrofilmDocumentTypeEnum; - /** - * Used for all vehicle types - */ - microfilmRollNumber?: string; - /** - * Used for all vehicle types - */ - microfilmSerialNumber?: string; +export interface Microfilm { + /** + * Used for all vehicle types + */ + microfilmDocumentType?: Microfilm.MicrofilmDocumentTypeEnum; + /** + * Used for all vehicle types + */ + microfilmRollNumber?: string; + /** + * Used for all vehicle types + */ + microfilmSerialNumber?: string; } export namespace Microfilm { - export type MicrofilmDocumentTypeEnum = 'PSV Miscellaneous' | 'AAT - Trailer Annual Test' | 'AIV - HGV International App' | 'COIF Modification' | 'Trailer COC + Int Plate' | 'RCT - Trailer Test Cert paid' | 'HGV COC + Int Plate' | 'PSV Carry/Auth' | 'OMO Report' | 'AIT - Trailer International App' | 'IPV - HGV EEC Plate/Cert' | 'XCV - HGV Test Cert free' | 'AAV - HGV Annual Test' | 'COIF Master' | 'Tempo 100 Sp Ord' | 'Deleted' | 'PSV N/ALT' | 'XPT - Tr Plating Cert paid' | 'FFV - HGV First Test' | 'Repl Vitesse 100' | 'TCV - HGV Test Cert' | 'ZZZ - Miscellaneous' | 'Test Certificate' | 'XCT - Trailer Test Cert free' | 'C52 - COC and VTG52A' | 'Tempo 100 Report' | 'Main File Amendment' | 'PSV Doc' | 'PSV COC' | 'PSV Repl COC' | 'TAV - COC' | 'NPT - Trailer Alteration' | 'OMO Certificate' | 'PSV Repl COIF' | 'PSV Repl COF' | 'COIF Application' | 'XPV - HGV Plating Cert Free' | 'TCT - Trailer Test Cert' | 'Tempo 100 App' | 'PSV Decision on N/ALT' | 'Special Order PSV' | 'NPV - HGV Alteration' | 'No Description Found' | 'Vitesse 100 Sp Ord' | 'Brake Test Details' | 'COIF Productional' | 'RDT - Test Disc Paid' | 'RCV - HGV Test Cert' | 'FFT - Trailer First Test' | 'IPT - Trailer EEC Plate/Cert' | 'XDT - Test Disc Free' | 'PRV - HGV Plating Cert paid' | 'COF Cert' | 'PRT - Tr Plating Cert paid' | 'Tempo 100 Permit'; - export const MicrofilmDocumentTypeEnum = { - PSVMiscellaneous: 'PSV Miscellaneous' as MicrofilmDocumentTypeEnum, - AATTrailerAnnualTest: 'AAT - Trailer Annual Test' as MicrofilmDocumentTypeEnum, - AIVHGVInternationalApp: 'AIV - HGV International App' as MicrofilmDocumentTypeEnum, - COIFModification: 'COIF Modification' as MicrofilmDocumentTypeEnum, - TrailerCOCIntPlate: 'Trailer COC + Int Plate' as MicrofilmDocumentTypeEnum, - RCTTrailerTestCertPaid: 'RCT - Trailer Test Cert paid' as MicrofilmDocumentTypeEnum, - HGVCOCIntPlate: 'HGV COC + Int Plate' as MicrofilmDocumentTypeEnum, - PSVCarryAuth: 'PSV Carry/Auth' as MicrofilmDocumentTypeEnum, - OMOReport: 'OMO Report' as MicrofilmDocumentTypeEnum, - AITTrailerInternationalApp: 'AIT - Trailer International App' as MicrofilmDocumentTypeEnum, - IPVHGVEECPlateCert: 'IPV - HGV EEC Plate/Cert' as MicrofilmDocumentTypeEnum, - XCVHGVTestCertFree: 'XCV - HGV Test Cert free' as MicrofilmDocumentTypeEnum, - AAVHGVAnnualTest: 'AAV - HGV Annual Test' as MicrofilmDocumentTypeEnum, - COIFMaster: 'COIF Master' as MicrofilmDocumentTypeEnum, - Tempo100SpOrd: 'Tempo 100 Sp Ord' as MicrofilmDocumentTypeEnum, - Deleted: 'Deleted' as MicrofilmDocumentTypeEnum, - PSVNALT: 'PSV N/ALT' as MicrofilmDocumentTypeEnum, - XPTTrPlatingCertPaid: 'XPT - Tr Plating Cert paid' as MicrofilmDocumentTypeEnum, - FFVHGVFirstTest: 'FFV - HGV First Test' as MicrofilmDocumentTypeEnum, - ReplVitesse100: 'Repl Vitesse 100' as MicrofilmDocumentTypeEnum, - TCVHGVTestCert: 'TCV - HGV Test Cert' as MicrofilmDocumentTypeEnum, - ZZZMiscellaneous: 'ZZZ - Miscellaneous' as MicrofilmDocumentTypeEnum, - TestCertificate: 'Test Certificate' as MicrofilmDocumentTypeEnum, - XCTTrailerTestCertFree: 'XCT - Trailer Test Cert free' as MicrofilmDocumentTypeEnum, - C52COCAndVTG52A: 'C52 - COC and VTG52A' as MicrofilmDocumentTypeEnum, - Tempo100Report: 'Tempo 100 Report' as MicrofilmDocumentTypeEnum, - MainFileAmendment: 'Main File Amendment' as MicrofilmDocumentTypeEnum, - PSVDoc: 'PSV Doc' as MicrofilmDocumentTypeEnum, - PSVCOC: 'PSV COC' as MicrofilmDocumentTypeEnum, - PSVReplCOC: 'PSV Repl COC' as MicrofilmDocumentTypeEnum, - TAVCOC: 'TAV - COC' as MicrofilmDocumentTypeEnum, - NPTTrailerAlteration: 'NPT - Trailer Alteration' as MicrofilmDocumentTypeEnum, - OMOCertificate: 'OMO Certificate' as MicrofilmDocumentTypeEnum, - PSVReplCOIF: 'PSV Repl COIF' as MicrofilmDocumentTypeEnum, - PSVReplCOF: 'PSV Repl COF' as MicrofilmDocumentTypeEnum, - COIFApplication: 'COIF Application' as MicrofilmDocumentTypeEnum, - XPVHGVPlatingCertFree: 'XPV - HGV Plating Cert Free' as MicrofilmDocumentTypeEnum, - TCTTrailerTestCert: 'TCT - Trailer Test Cert' as MicrofilmDocumentTypeEnum, - Tempo100App: 'Tempo 100 App' as MicrofilmDocumentTypeEnum, - PSVDecisionOnNALT: 'PSV Decision on N/ALT' as MicrofilmDocumentTypeEnum, - SpecialOrderPSV: 'Special Order PSV' as MicrofilmDocumentTypeEnum, - NPVHGVAlteration: 'NPV - HGV Alteration' as MicrofilmDocumentTypeEnum, - NoDescriptionFound: 'No Description Found' as MicrofilmDocumentTypeEnum, - Vitesse100SpOrd: 'Vitesse 100 Sp Ord' as MicrofilmDocumentTypeEnum, - BrakeTestDetails: 'Brake Test Details' as MicrofilmDocumentTypeEnum, - COIFProductional: 'COIF Productional' as MicrofilmDocumentTypeEnum, - RDTTestDiscPaid: 'RDT - Test Disc Paid' as MicrofilmDocumentTypeEnum, - RCVHGVTestCert: 'RCV - HGV Test Cert' as MicrofilmDocumentTypeEnum, - FFTTrailerFirstTest: 'FFT - Trailer First Test' as MicrofilmDocumentTypeEnum, - IPTTrailerEECPlateCert: 'IPT - Trailer EEC Plate/Cert' as MicrofilmDocumentTypeEnum, - XDTTestDiscFree: 'XDT - Test Disc Free' as MicrofilmDocumentTypeEnum, - PRVHGVPlatingCertPaid: 'PRV - HGV Plating Cert paid' as MicrofilmDocumentTypeEnum, - COFCert: 'COF Cert' as MicrofilmDocumentTypeEnum, - PRTTrPlatingCertPaid: 'PRT - Tr Plating Cert paid' as MicrofilmDocumentTypeEnum, - Tempo100Permit: 'Tempo 100 Permit' as MicrofilmDocumentTypeEnum - }; -} \ No newline at end of file + export type MicrofilmDocumentTypeEnum = + | 'PSV Miscellaneous' + | 'AAT - Trailer Annual Test' + | 'AIV - HGV International App' + | 'COIF Modification' + | 'Trailer COC + Int Plate' + | 'RCT - Trailer Test Cert paid' + | 'HGV COC + Int Plate' + | 'PSV Carry/Auth' + | 'OMO Report' + | 'AIT - Trailer International App' + | 'IPV - HGV EEC Plate/Cert' + | 'XCV - HGV Test Cert free' + | 'AAV - HGV Annual Test' + | 'COIF Master' + | 'Tempo 100 Sp Ord' + | 'Deleted' + | 'PSV N/ALT' + | 'XPT - Tr Plating Cert paid' + | 'FFV - HGV First Test' + | 'Repl Vitesse 100' + | 'TCV - HGV Test Cert' + | 'ZZZ - Miscellaneous' + | 'Test Certificate' + | 'XCT - Trailer Test Cert free' + | 'C52 - COC and VTG52A' + | 'Tempo 100 Report' + | 'Main File Amendment' + | 'PSV Doc' + | 'PSV COC' + | 'PSV Repl COC' + | 'TAV - COC' + | 'NPT - Trailer Alteration' + | 'OMO Certificate' + | 'PSV Repl COIF' + | 'PSV Repl COF' + | 'COIF Application' + | 'XPV - HGV Plating Cert Free' + | 'TCT - Trailer Test Cert' + | 'Tempo 100 App' + | 'PSV Decision on N/ALT' + | 'Special Order PSV' + | 'NPV - HGV Alteration' + | 'No Description Found' + | 'Vitesse 100 Sp Ord' + | 'Brake Test Details' + | 'COIF Productional' + | 'RDT - Test Disc Paid' + | 'RCV - HGV Test Cert' + | 'FFT - Trailer First Test' + | 'IPT - Trailer EEC Plate/Cert' + | 'XDT - Test Disc Free' + | 'PRV - HGV Plating Cert paid' + | 'COF Cert' + | 'PRT - Tr Plating Cert paid' + | 'Tempo 100 Permit'; + export const MicrofilmDocumentTypeEnum = { + PSVMiscellaneous: 'PSV Miscellaneous' as MicrofilmDocumentTypeEnum, + AATTrailerAnnualTest: 'AAT - Trailer Annual Test' as MicrofilmDocumentTypeEnum, + AIVHGVInternationalApp: 'AIV - HGV International App' as MicrofilmDocumentTypeEnum, + COIFModification: 'COIF Modification' as MicrofilmDocumentTypeEnum, + TrailerCOCIntPlate: 'Trailer COC + Int Plate' as MicrofilmDocumentTypeEnum, + RCTTrailerTestCertPaid: 'RCT - Trailer Test Cert paid' as MicrofilmDocumentTypeEnum, + HGVCOCIntPlate: 'HGV COC + Int Plate' as MicrofilmDocumentTypeEnum, + PSVCarryAuth: 'PSV Carry/Auth' as MicrofilmDocumentTypeEnum, + OMOReport: 'OMO Report' as MicrofilmDocumentTypeEnum, + AITTrailerInternationalApp: 'AIT - Trailer International App' as MicrofilmDocumentTypeEnum, + IPVHGVEECPlateCert: 'IPV - HGV EEC Plate/Cert' as MicrofilmDocumentTypeEnum, + XCVHGVTestCertFree: 'XCV - HGV Test Cert free' as MicrofilmDocumentTypeEnum, + AAVHGVAnnualTest: 'AAV - HGV Annual Test' as MicrofilmDocumentTypeEnum, + COIFMaster: 'COIF Master' as MicrofilmDocumentTypeEnum, + Tempo100SpOrd: 'Tempo 100 Sp Ord' as MicrofilmDocumentTypeEnum, + Deleted: 'Deleted' as MicrofilmDocumentTypeEnum, + PSVNALT: 'PSV N/ALT' as MicrofilmDocumentTypeEnum, + XPTTrPlatingCertPaid: 'XPT - Tr Plating Cert paid' as MicrofilmDocumentTypeEnum, + FFVHGVFirstTest: 'FFV - HGV First Test' as MicrofilmDocumentTypeEnum, + ReplVitesse100: 'Repl Vitesse 100' as MicrofilmDocumentTypeEnum, + TCVHGVTestCert: 'TCV - HGV Test Cert' as MicrofilmDocumentTypeEnum, + ZZZMiscellaneous: 'ZZZ - Miscellaneous' as MicrofilmDocumentTypeEnum, + TestCertificate: 'Test Certificate' as MicrofilmDocumentTypeEnum, + XCTTrailerTestCertFree: 'XCT - Trailer Test Cert free' as MicrofilmDocumentTypeEnum, + C52COCAndVTG52A: 'C52 - COC and VTG52A' as MicrofilmDocumentTypeEnum, + Tempo100Report: 'Tempo 100 Report' as MicrofilmDocumentTypeEnum, + MainFileAmendment: 'Main File Amendment' as MicrofilmDocumentTypeEnum, + PSVDoc: 'PSV Doc' as MicrofilmDocumentTypeEnum, + PSVCOC: 'PSV COC' as MicrofilmDocumentTypeEnum, + PSVReplCOC: 'PSV Repl COC' as MicrofilmDocumentTypeEnum, + TAVCOC: 'TAV - COC' as MicrofilmDocumentTypeEnum, + NPTTrailerAlteration: 'NPT - Trailer Alteration' as MicrofilmDocumentTypeEnum, + OMOCertificate: 'OMO Certificate' as MicrofilmDocumentTypeEnum, + PSVReplCOIF: 'PSV Repl COIF' as MicrofilmDocumentTypeEnum, + PSVReplCOF: 'PSV Repl COF' as MicrofilmDocumentTypeEnum, + COIFApplication: 'COIF Application' as MicrofilmDocumentTypeEnum, + XPVHGVPlatingCertFree: 'XPV - HGV Plating Cert Free' as MicrofilmDocumentTypeEnum, + TCTTrailerTestCert: 'TCT - Trailer Test Cert' as MicrofilmDocumentTypeEnum, + Tempo100App: 'Tempo 100 App' as MicrofilmDocumentTypeEnum, + PSVDecisionOnNALT: 'PSV Decision on N/ALT' as MicrofilmDocumentTypeEnum, + SpecialOrderPSV: 'Special Order PSV' as MicrofilmDocumentTypeEnum, + NPVHGVAlteration: 'NPV - HGV Alteration' as MicrofilmDocumentTypeEnum, + NoDescriptionFound: 'No Description Found' as MicrofilmDocumentTypeEnum, + Vitesse100SpOrd: 'Vitesse 100 Sp Ord' as MicrofilmDocumentTypeEnum, + BrakeTestDetails: 'Brake Test Details' as MicrofilmDocumentTypeEnum, + COIFProductional: 'COIF Productional' as MicrofilmDocumentTypeEnum, + RDTTestDiscPaid: 'RDT - Test Disc Paid' as MicrofilmDocumentTypeEnum, + RCVHGVTestCert: 'RCV - HGV Test Cert' as MicrofilmDocumentTypeEnum, + FFTTrailerFirstTest: 'FFT - Trailer First Test' as MicrofilmDocumentTypeEnum, + IPTTrailerEECPlateCert: 'IPT - Trailer EEC Plate/Cert' as MicrofilmDocumentTypeEnum, + XDTTestDiscFree: 'XDT - Test Disc Free' as MicrofilmDocumentTypeEnum, + PRVHGVPlatingCertPaid: 'PRV - HGV Plating Cert paid' as MicrofilmDocumentTypeEnum, + COFCert: 'COF Cert' as MicrofilmDocumentTypeEnum, + PRTTrPlatingCertPaid: 'PRT - Tr Plating Cert paid' as MicrofilmDocumentTypeEnum, + Tempo100Permit: 'Tempo 100 Permit' as MicrofilmDocumentTypeEnum, + }; +} diff --git a/src/app/api/vehicle/model/plates.ts b/src/app/api/vehicle/model/plates.ts index 6fbbd8d1d0..5ead075aec 100644 --- a/src/app/api/vehicle/model/plates.ts +++ b/src/app/api/vehicle/model/plates.ts @@ -10,5 +10,4 @@ */ import { PlatesInner } from './platesInner'; -export interface Plates extends Array { -} \ No newline at end of file +export interface Plates extends Array {} diff --git a/src/app/api/vehicle/model/platesInner.ts b/src/app/api/vehicle/model/platesInner.ts index 4f4c7f4ffc..3a0ba29d66 100644 --- a/src/app/api/vehicle/model/platesInner.ts +++ b/src/app/api/vehicle/model/platesInner.ts @@ -9,36 +9,42 @@ * Do not edit the class manually. */ -export interface PlatesInner { - /** - * Used for all vehicle types - */ - plateSerialNumber?: string; - /** - * Used for all vehicle types - */ - plateIssueDate?: string; - /** - * Used for all vehicle types - */ - plateReasonForIssue?: PlatesInner.PlateReasonForIssueEnum; - /** - * Used for all vehicle types - */ - plateIssuer?: string; - /** - * Used for all vehicle types - */ - toEmailAddress?: string; +export interface PlatesInner { + /** + * Used for all vehicle types + */ + plateSerialNumber?: string; + /** + * Used for all vehicle types + */ + plateIssueDate?: string; + /** + * Used for all vehicle types + */ + plateReasonForIssue?: PlatesInner.PlateReasonForIssueEnum; + /** + * Used for all vehicle types + */ + plateIssuer?: string; + /** + * Used for all vehicle types + */ + toEmailAddress?: string; } export namespace PlatesInner { - export type PlateReasonForIssueEnum = 'Free replacement' | 'Replacement' | 'Destroyed' | 'Provisional' | 'Original' | 'Manual'; - export const PlateReasonForIssueEnum = { - FreeReplacement: 'Free replacement' as PlateReasonForIssueEnum, - Replacement: 'Replacement' as PlateReasonForIssueEnum, - Destroyed: 'Destroyed' as PlateReasonForIssueEnum, - Provisional: 'Provisional' as PlateReasonForIssueEnum, - Original: 'Original' as PlateReasonForIssueEnum, - Manual: 'Manual' as PlateReasonForIssueEnum - }; -} \ No newline at end of file + export type PlateReasonForIssueEnum = + | 'Free replacement' + | 'Replacement' + | 'Destroyed' + | 'Provisional' + | 'Original' + | 'Manual'; + export const PlateReasonForIssueEnum = { + FreeReplacement: 'Free replacement' as PlateReasonForIssueEnum, + Replacement: 'Replacement' as PlateReasonForIssueEnum, + Destroyed: 'Destroyed' as PlateReasonForIssueEnum, + Provisional: 'Provisional' as PlateReasonForIssueEnum, + Original: 'Original' as PlateReasonForIssueEnum, + Manual: 'Manual' as PlateReasonForIssueEnum, + }; +} diff --git a/src/app/api/vehicle/model/purchaserDetails.ts b/src/app/api/vehicle/model/purchaserDetails.ts index 89b0d419e5..107fc4238d 100644 --- a/src/app/api/vehicle/model/purchaserDetails.ts +++ b/src/app/api/vehicle/model/purchaserDetails.ts @@ -12,15 +12,15 @@ /** * Used for TRL only */ -export interface PurchaserDetails { - name?: string; - address1?: string; - address2?: string; - postTown?: string; - address3?: string; - postCode?: string; - emailAddress?: string; - telephoneNumber?: string; - faxNumber?: string; - purchaserNotes?: string; -} \ No newline at end of file +export interface PurchaserDetails { + name?: string; + address1?: string; + address2?: string; + postTown?: string; + address3?: string; + postCode?: string; + emailAddress?: string; + telephoneNumber?: string; + faxNumber?: string; + purchaserNotes?: string; +} diff --git a/src/app/api/vehicle/model/techRecord.ts b/src/app/api/vehicle/model/techRecord.ts index 2d2fc48f52..9e7f2d032d 100644 --- a/src/app/api/vehicle/model/techRecord.ts +++ b/src/app/api/vehicle/model/techRecord.ts @@ -24,449 +24,496 @@ import { TechRecordDimensions } from './techRecordDimensions'; import { TechRecordVehicleClass } from './techRecordVehicleClass'; export interface TechRecord { - /** - * Defines the level of completeness for a tech record. If it is set to \"skeleton\" then it means the vehicle does not meet the minimum requirements to be tested. If it is \"testable\" it means the vehicle meets the minimum requirements to be tested but is not complete from a business perspective. If \"complete\" then the vehicle it is complete form a business perspective also. - */ - recordCompleteness?: string; - /** - * Used for all vehicle types - */ - createdAt?: Date; - /** - * Used for all vehicle types - */ - lastUpdatedAt?: Date; - /** - * Used only for HGV and TRL - */ - make?: string; - /** - * Used only for HGV and TRL - */ - model?: string; - /** - * Used for all vehicle types - */ - functionCode?: string; - /** - * Used for HGV and PSV - */ - fuelPropulsionSystem?: TechRecord.FuelPropulsionSystemEnum; - /** - * Used only for HGV - */ - offRoad?: boolean; - /** - * Used for motorcycles to derive the test codes for specialist tests. Used for HGV and PSV. - */ - numberOfWheelsDriven?: number; - /** - * Used for all vehicle types. Optional for car, lgv and motorcycle. - */ - euVehicleCategory?: TechRecord.EuVehicleCategoryEnum; - /** - * Used only for HGV and PSV - */ - emissionsLimit?: number; - /** - * Used for all vehicle types - */ - departmentalVehicleMarker?: boolean; - authIntoService?: AuthIntoService; - lettersOfAuth?: LettersOfAuth; - /** - * Used for all vehicle types - */ - alterationMarker?: boolean; - /** - * Used for all vehicle types - */ - approvalType?: TechRecord.ApprovalTypeEnum; - /** - * Used for all vehicle types - */ - approvalTypeNumber?: string; - /** - * Used for all vehicle types - */ - variantNumber?: string; - /** - * Used for all vehicle types - */ - variantVersionNumber?: string; - /** - * Used only for HGV and TRL - */ - grossEecWeight?: number; - /** - * Used only for HGV - */ - trainEecWeight?: number; - /** - * Used only for HGV - */ - maxTrainEecWeight?: number; - applicantDetails?: ApplicantDetailsProperties; - purchaserDetails?: PurchaserDetails; - manufacturerDetails?: ManufacturerDetails; - microfilm?: Microfilm; - plates?: Plates; - /** - * Used only for PSV - */ - chassisMake?: string; - /** - * Used only for PSV - */ - chassisModel?: string; - /** - * Used only for PSV - */ - bodyMake?: string; - /** - * Used only for PSV - */ - bodyModel?: string; - /** - * Used only for PSV - */ - modelLiteral?: string; - bodyType?: TechRecordBodyType; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - manufactureYear?: number; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - regnDate?: string; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - firstUseDate?: string; - /** - * Used only for PSV - */ - coifDate?: string; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - ntaNumber?: string; - /** - * Used only for PSV - */ - coifSerialNumber?: string; - /** - * Used only for PSV - */ - coifCertifierName?: string; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - conversionRefNo?: string; - /** - * Used only for PSV - */ - seatsLowerDeck?: number; - /** - * Used only for PSV - */ - seatsUpperDeck?: number; - /** - * Used only for PSV - */ - standingCapacity?: number; - /** - * Used only for PSV - */ - speedRestriction?: number; - /** - * Used only for PSV and HGV - */ - speedLimiterMrk?: boolean; - /** - * Used only for PSV and HGV - */ - tachoExemptMrk?: boolean; - /** - * Used only for PSV - */ - dispensations?: string; - /** - * Used for PSV, car, lgv and motorcycle - */ - remarks?: string; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv and motorcycle - */ - reasonForCreation?: string; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - statusCode?: TechRecord.StatusCodeEnum; - /** - * Used only for PSV - */ - unladenWeight?: number; - /** - * Used only for PSV - */ - grossKerbWeight?: number; - /** - * Used only for PSV - */ - grossLadenWeight?: number; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - grossGbWeight?: number; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - grossDesignWeight?: number; - /** - * Used only for HGV - */ - trainGbWeight?: number; - /** - * Used only for HGV and PSV - */ - trainDesignWeight?: number; - /** - * Used only for HGV and PSV. Optional for PSV - */ - maxTrainGbWeight?: number; - /** - * Used only for HGV - */ - maxTrainDesignWeight?: number; - /** - * Used only for TRL - */ - maxLoadOnCoupling?: number; - frameDescription?: TechRecord.FrameDescriptionEnum; - /** - * Used only for HGV and TRL - */ - tyreUseCode?: string; - /** - * Used only for HGV and TRL - */ - roadFriendly?: boolean; - /** - * Used only for HGV - */ - drawbarCouplingFitted?: boolean; - /** - * Used for HGV and PSV - */ - euroStandard?: string; - /** - * Used only for TRL - */ - suspensionType?: string; - /** - * Used only for TRL - */ - couplingType?: string; - dimensions?: TechRecordDimensions; - /** - * Used only for HGV - */ - frontAxleTo5thWheelMin?: number; - /** - * Used only for HGV - */ - frontAxleTo5thWheelMax?: number; - /** - * Used only for HGV. Optional for HGV - */ - frontVehicleTo5thWheelCouplingMin?: number; - /** - * Used only for HGV. Optional for HGV - */ - frontVehicleTo5thWheelCouplingMax?: number; - /** - * Used for all vehicle types. Optional for PSV - */ - frontAxleToRearAxle?: number; - /** - * Used only for TRL - */ - rearAxleToRearTrl?: number; - /** - * Used only for TRL - */ - couplingCenterToRearAxleMin?: number; - /** - * Used only for TRL - */ - couplingCenterToRearAxleMax?: number; - /** - * Used only for TRL - */ - couplingCenterToRearTrlMin?: number; - /** - * Used only for TRL - */ - couplingCenterToRearTrlMax?: number; - /** - * Used only for TRL - */ - centreOfRearmostAxleToRearOfTrl?: number; - /** - * Used only for HGV and TRL - */ - notes?: string; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - noOfAxles?: number; - /** - * Used only for PSV - */ - brakeCode?: string; - adrDetails?: AdrDetails; - /** - * This field gets populated with the Microsoft AD 'name', when a tech record gets created - */ - createdByName?: string; - /** - * This attribute gets populated with the Microsoft AD 'oid', when a tech record gets created - */ - createdById?: string; - /** - * This field gets populated with the Microsoft AD 'name', when a tech record gets updated - */ - lastUpdatedByName?: string; - /** - * This attribute gets populated with the Microsoft AD 'oid', when a tech record gets updated - */ - lastUpdatedById?: string; - /** - * set updateType to adrUpdate on the archived tech record, when a tech record is archived - */ - updateType?: TechRecord.UpdateTypeEnum; - vehicleClass?: TechRecordVehicleClass; - /** - * Used for car and lgv. - */ - vehicleSubclass?: Array; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - vehicleType?: TechRecord.VehicleTypeEnum; - /** - * Used only for PSV - */ - vehicleSize?: TechRecord.VehicleSizeEnum; - /** - * Used only for PSV - */ - numberOfSeatbelts?: string; - /** - * Used only for PSV - */ - seatbeltInstallationApprovalDate?: string; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - vehicleConfiguration?: TechRecord.VehicleConfigurationEnum; - brakes?: Brakes; - axles?: Axles; - dda?: Dda; + /** + * Defines the level of completeness for a tech record. If it is set to \"skeleton\" then it means the vehicle does not meet the minimum requirements to be tested. If it is \"testable\" it means the vehicle meets the minimum requirements to be tested but is not complete from a business perspective. If \"complete\" then the vehicle it is complete form a business perspective also. + */ + recordCompleteness?: string; + /** + * Used for all vehicle types + */ + createdAt?: Date; + /** + * Used for all vehicle types + */ + lastUpdatedAt?: Date; + /** + * Used only for HGV and TRL + */ + make?: string; + /** + * Used only for HGV and TRL + */ + model?: string; + /** + * Used for all vehicle types + */ + functionCode?: string; + /** + * Used for HGV and PSV + */ + fuelPropulsionSystem?: TechRecord.FuelPropulsionSystemEnum; + /** + * Used only for HGV + */ + offRoad?: boolean; + /** + * Used for motorcycles to derive the test codes for specialist tests. Used for HGV and PSV. + */ + numberOfWheelsDriven?: number; + /** + * Used for all vehicle types. Optional for car, lgv and motorcycle. + */ + euVehicleCategory?: TechRecord.EuVehicleCategoryEnum; + /** + * Used only for HGV and PSV + */ + emissionsLimit?: number; + /** + * Used for all vehicle types + */ + departmentalVehicleMarker?: boolean; + authIntoService?: AuthIntoService; + lettersOfAuth?: LettersOfAuth; + /** + * Used for all vehicle types + */ + alterationMarker?: boolean; + /** + * Used for all vehicle types + */ + approvalType?: TechRecord.ApprovalTypeEnum; + /** + * Used for all vehicle types + */ + approvalTypeNumber?: string; + /** + * Used for all vehicle types + */ + variantNumber?: string; + /** + * Used for all vehicle types + */ + variantVersionNumber?: string; + /** + * Used only for HGV and TRL + */ + grossEecWeight?: number; + /** + * Used only for HGV + */ + trainEecWeight?: number; + /** + * Used only for HGV + */ + maxTrainEecWeight?: number; + applicantDetails?: ApplicantDetailsProperties; + purchaserDetails?: PurchaserDetails; + manufacturerDetails?: ManufacturerDetails; + microfilm?: Microfilm; + plates?: Plates; + /** + * Used only for PSV + */ + chassisMake?: string; + /** + * Used only for PSV + */ + chassisModel?: string; + /** + * Used only for PSV + */ + bodyMake?: string; + /** + * Used only for PSV + */ + bodyModel?: string; + /** + * Used only for PSV + */ + modelLiteral?: string; + bodyType?: TechRecordBodyType; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + manufactureYear?: number; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + regnDate?: string; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + firstUseDate?: string; + /** + * Used only for PSV + */ + coifDate?: string; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + ntaNumber?: string; + /** + * Used only for PSV + */ + coifSerialNumber?: string; + /** + * Used only for PSV + */ + coifCertifierName?: string; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + conversionRefNo?: string; + /** + * Used only for PSV + */ + seatsLowerDeck?: number; + /** + * Used only for PSV + */ + seatsUpperDeck?: number; + /** + * Used only for PSV + */ + standingCapacity?: number; + /** + * Used only for PSV + */ + speedRestriction?: number; + /** + * Used only for PSV and HGV + */ + speedLimiterMrk?: boolean; + /** + * Used only for PSV and HGV + */ + tachoExemptMrk?: boolean; + /** + * Used only for PSV + */ + dispensations?: string; + /** + * Used for PSV, car, lgv and motorcycle + */ + remarks?: string; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv and motorcycle + */ + reasonForCreation?: string; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + statusCode?: TechRecord.StatusCodeEnum; + /** + * Used only for PSV + */ + unladenWeight?: number; + /** + * Used only for PSV + */ + grossKerbWeight?: number; + /** + * Used only for PSV + */ + grossLadenWeight?: number; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + grossGbWeight?: number; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + grossDesignWeight?: number; + /** + * Used only for HGV + */ + trainGbWeight?: number; + /** + * Used only for HGV and PSV + */ + trainDesignWeight?: number; + /** + * Used only for HGV and PSV. Optional for PSV + */ + maxTrainGbWeight?: number; + /** + * Used only for HGV + */ + maxTrainDesignWeight?: number; + /** + * Used only for TRL + */ + maxLoadOnCoupling?: number; + frameDescription?: TechRecord.FrameDescriptionEnum; + /** + * Used only for HGV and TRL + */ + tyreUseCode?: string; + /** + * Used only for HGV and TRL + */ + roadFriendly?: boolean; + /** + * Used only for HGV + */ + drawbarCouplingFitted?: boolean; + /** + * Used for HGV and PSV + */ + euroStandard?: string; + /** + * Used only for TRL + */ + suspensionType?: string; + /** + * Used only for TRL + */ + couplingType?: string; + dimensions?: TechRecordDimensions; + /** + * Used only for HGV + */ + frontAxleTo5thWheelMin?: number; + /** + * Used only for HGV + */ + frontAxleTo5thWheelMax?: number; + /** + * Used only for HGV. Optional for HGV + */ + frontVehicleTo5thWheelCouplingMin?: number; + /** + * Used only for HGV. Optional for HGV + */ + frontVehicleTo5thWheelCouplingMax?: number; + /** + * Used for all vehicle types. Optional for PSV + */ + frontAxleToRearAxle?: number; + /** + * Used only for TRL + */ + rearAxleToRearTrl?: number; + /** + * Used only for TRL + */ + couplingCenterToRearAxleMin?: number; + /** + * Used only for TRL + */ + couplingCenterToRearAxleMax?: number; + /** + * Used only for TRL + */ + couplingCenterToRearTrlMin?: number; + /** + * Used only for TRL + */ + couplingCenterToRearTrlMax?: number; + /** + * Used only for TRL + */ + centreOfRearmostAxleToRearOfTrl?: number; + /** + * Used only for HGV and TRL + */ + notes?: string; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + noOfAxles?: number; + /** + * Used only for PSV + */ + brakeCode?: string; + adrDetails?: AdrDetails; + /** + * This field gets populated with the Microsoft AD 'name', when a tech record gets created + */ + createdByName?: string; + /** + * This attribute gets populated with the Microsoft AD 'oid', when a tech record gets created + */ + createdById?: string; + /** + * This field gets populated with the Microsoft AD 'name', when a tech record gets updated + */ + lastUpdatedByName?: string; + /** + * This attribute gets populated with the Microsoft AD 'oid', when a tech record gets updated + */ + lastUpdatedById?: string; + /** + * set updateType to adrUpdate on the archived tech record, when a tech record is archived + */ + updateType?: TechRecord.UpdateTypeEnum; + vehicleClass?: TechRecordVehicleClass; + /** + * Used for car and lgv. + */ + vehicleSubclass?: Array; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + vehicleType?: TechRecord.VehicleTypeEnum; + /** + * Used only for PSV + */ + vehicleSize?: TechRecord.VehicleSizeEnum; + /** + * Used only for PSV + */ + numberOfSeatbelts?: string; + /** + * Used only for PSV + */ + seatbeltInstallationApprovalDate?: string; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + vehicleConfiguration?: TechRecord.VehicleConfigurationEnum; + brakes?: Brakes; + axles?: Axles; + dda?: Dda; } export namespace TechRecord { - export type FuelPropulsionSystemEnum = 'DieselPetrol' | 'Diesel' | 'Petrol' | 'Hybrid' | 'Electric' | 'CNG' | 'Fuel cell' | 'LNG' | 'Other'; - export const FuelPropulsionSystemEnum = { - DieselPetrol: "DieselPetrol" as FuelPropulsionSystemEnum, - Diesel: 'Diesel' as FuelPropulsionSystemEnum, - Petrol: 'Petrol' as FuelPropulsionSystemEnum, - Hybrid: 'Hybrid' as FuelPropulsionSystemEnum, - Electric: 'Electric' as FuelPropulsionSystemEnum, - CNG: 'CNG' as FuelPropulsionSystemEnum, - FuelCell: 'Fuel cell' as FuelPropulsionSystemEnum, - LNG: 'LNG' as FuelPropulsionSystemEnum, - Other: 'Other' as FuelPropulsionSystemEnum - }; - export type EuVehicleCategoryEnum = 'm1' | 'm2' | 'm3' | 'n1' | 'n2' | 'n3' | 'o1' | 'o2' | 'o3' | 'o4' | 'l1e-a' | 'l1e' | 'l2e' | 'l3e' | 'l4e' | 'l5e' | 'l6e' | 'l7e'; - export const EuVehicleCategoryEnum = { - M1: 'm1' as EuVehicleCategoryEnum, - M2: 'm2' as EuVehicleCategoryEnum, - M3: 'm3' as EuVehicleCategoryEnum, - N1: 'n1' as EuVehicleCategoryEnum, - N2: 'n2' as EuVehicleCategoryEnum, - N3: 'n3' as EuVehicleCategoryEnum, - O1: 'o1' as EuVehicleCategoryEnum, - O2: 'o2' as EuVehicleCategoryEnum, - O3: 'o3' as EuVehicleCategoryEnum, - O4: 'o4' as EuVehicleCategoryEnum, - L1eA: 'l1e-a' as EuVehicleCategoryEnum, - L1e: 'l1e' as EuVehicleCategoryEnum, - L2e: 'l2e' as EuVehicleCategoryEnum, - L3e: 'l3e' as EuVehicleCategoryEnum, - L4e: 'l4e' as EuVehicleCategoryEnum, - L5e: 'l5e' as EuVehicleCategoryEnum, - L6e: 'l6e' as EuVehicleCategoryEnum, - L7e: 'l7e' as EuVehicleCategoryEnum - }; - export type ApprovalTypeEnum = 'NTA' | 'ECTA' | 'IVA' | 'NSSTA' | 'ECSSTA'; - export const ApprovalTypeEnum = { - NTA: 'NTA' as ApprovalTypeEnum, - ECTA: 'ECTA' as ApprovalTypeEnum, - IVA: 'IVA' as ApprovalTypeEnum, - NSSTA: 'NSSTA' as ApprovalTypeEnum, - ECSSTA: 'ECSSTA' as ApprovalTypeEnum - }; - export type StatusCodeEnum = 'archived' | 'current' | 'provisional'; - export const StatusCodeEnum = { - Archived: 'archived' as StatusCodeEnum, - Current: 'current' as StatusCodeEnum, - Provisional: 'provisional' as StatusCodeEnum - }; - export type FrameDescriptionEnum = 'Channel section' | 'Space frame' | 'I section' | 'Tubular' | 'Frame section' | 'Other' | 'integral' | 'Box section' | 'U section'; - export const FrameDescriptionEnum = { - ChannelSection: 'Channel section' as FrameDescriptionEnum, - SpaceFrame: 'Space frame' as FrameDescriptionEnum, - ISection: 'I section' as FrameDescriptionEnum, - Tubular: 'Tubular' as FrameDescriptionEnum, - FrameSection: 'Frame section' as FrameDescriptionEnum, - Other: 'Other' as FrameDescriptionEnum, - Integral: 'integral' as FrameDescriptionEnum, - BoxSection: 'Box section' as FrameDescriptionEnum, - USection: 'U section' as FrameDescriptionEnum - }; - export type UpdateTypeEnum = 'adrUpdate' | 'techRecordUpdate'; - export const UpdateTypeEnum = { - AdrUpdate: 'adrUpdate' as UpdateTypeEnum, - TechRecordUpdate: 'techRecordUpdate' as UpdateTypeEnum - }; - export type VehicleTypeEnum = 'psv' | 'hgv' | 'trl' | 'car' | 'lgv' | 'motorcycle'; - export const VehicleTypeEnum = { - Psv: 'psv' as VehicleTypeEnum, - Hgv: 'hgv' as VehicleTypeEnum, - Trl: 'trl' as VehicleTypeEnum, - Car: 'car' as VehicleTypeEnum, - Lgv: 'lgv' as VehicleTypeEnum, - Motorcycle: 'motorcycle' as VehicleTypeEnum - }; - export type VehicleSizeEnum = 'small' | 'large'; - export const VehicleSizeEnum = { - Small: 'small' as VehicleSizeEnum, - Large: 'large' as VehicleSizeEnum - }; - export type VehicleConfigurationEnum = 'rigid' | 'articulated' | 'centre axle drawbar' | 'semi-car transporter' | 'semi-trailer' | 'low loader' | 'other' | 'drawbar' | 'four-in-line' | 'dolly' | 'full drawbar'; - export const VehicleConfigurationEnum = { - Rigid: 'rigid' as VehicleConfigurationEnum, - Articulated: 'articulated' as VehicleConfigurationEnum, - CentreAxleDrawbar: 'centre axle drawbar' as VehicleConfigurationEnum, - SemiCarTransporter: 'semi-car transporter' as VehicleConfigurationEnum, - SemiTrailer: 'semi-trailer' as VehicleConfigurationEnum, - LowLoader: 'low loader' as VehicleConfigurationEnum, - Other: 'other' as VehicleConfigurationEnum, - Drawbar: 'drawbar' as VehicleConfigurationEnum, - FourInLine: 'four-in-line' as VehicleConfigurationEnum, - Dolly: 'dolly' as VehicleConfigurationEnum, - FullDrawbar: 'full drawbar' as VehicleConfigurationEnum - }; + export type FuelPropulsionSystemEnum = + | 'DieselPetrol' + | 'Diesel' + | 'Petrol' + | 'Hybrid' + | 'Electric' + | 'CNG' + | 'Fuel cell' + | 'LNG' + | 'Other'; + export const FuelPropulsionSystemEnum = { + DieselPetrol: 'DieselPetrol' as FuelPropulsionSystemEnum, + Diesel: 'Diesel' as FuelPropulsionSystemEnum, + Petrol: 'Petrol' as FuelPropulsionSystemEnum, + Hybrid: 'Hybrid' as FuelPropulsionSystemEnum, + Electric: 'Electric' as FuelPropulsionSystemEnum, + CNG: 'CNG' as FuelPropulsionSystemEnum, + FuelCell: 'Fuel cell' as FuelPropulsionSystemEnum, + LNG: 'LNG' as FuelPropulsionSystemEnum, + Other: 'Other' as FuelPropulsionSystemEnum, + }; + export type EuVehicleCategoryEnum = + | 'm1' + | 'm2' + | 'm3' + | 'n1' + | 'n2' + | 'n3' + | 'o1' + | 'o2' + | 'o3' + | 'o4' + | 'l1e-a' + | 'l1e' + | 'l2e' + | 'l3e' + | 'l4e' + | 'l5e' + | 'l6e' + | 'l7e'; + export const EuVehicleCategoryEnum = { + M1: 'm1' as EuVehicleCategoryEnum, + M2: 'm2' as EuVehicleCategoryEnum, + M3: 'm3' as EuVehicleCategoryEnum, + N1: 'n1' as EuVehicleCategoryEnum, + N2: 'n2' as EuVehicleCategoryEnum, + N3: 'n3' as EuVehicleCategoryEnum, + O1: 'o1' as EuVehicleCategoryEnum, + O2: 'o2' as EuVehicleCategoryEnum, + O3: 'o3' as EuVehicleCategoryEnum, + O4: 'o4' as EuVehicleCategoryEnum, + L1eA: 'l1e-a' as EuVehicleCategoryEnum, + L1e: 'l1e' as EuVehicleCategoryEnum, + L2e: 'l2e' as EuVehicleCategoryEnum, + L3e: 'l3e' as EuVehicleCategoryEnum, + L4e: 'l4e' as EuVehicleCategoryEnum, + L5e: 'l5e' as EuVehicleCategoryEnum, + L6e: 'l6e' as EuVehicleCategoryEnum, + L7e: 'l7e' as EuVehicleCategoryEnum, + }; + export type ApprovalTypeEnum = 'NTA' | 'ECTA' | 'IVA' | 'NSSTA' | 'ECSSTA'; + export const ApprovalTypeEnum = { + NTA: 'NTA' as ApprovalTypeEnum, + ECTA: 'ECTA' as ApprovalTypeEnum, + IVA: 'IVA' as ApprovalTypeEnum, + NSSTA: 'NSSTA' as ApprovalTypeEnum, + ECSSTA: 'ECSSTA' as ApprovalTypeEnum, + }; + export type StatusCodeEnum = 'archived' | 'current' | 'provisional'; + export const StatusCodeEnum = { + Archived: 'archived' as StatusCodeEnum, + Current: 'current' as StatusCodeEnum, + Provisional: 'provisional' as StatusCodeEnum, + }; + export type FrameDescriptionEnum = + | 'Channel section' + | 'Space frame' + | 'I section' + | 'Tubular' + | 'Frame section' + | 'Other' + | 'integral' + | 'Box section' + | 'U section'; + export const FrameDescriptionEnum = { + ChannelSection: 'Channel section' as FrameDescriptionEnum, + SpaceFrame: 'Space frame' as FrameDescriptionEnum, + ISection: 'I section' as FrameDescriptionEnum, + Tubular: 'Tubular' as FrameDescriptionEnum, + FrameSection: 'Frame section' as FrameDescriptionEnum, + Other: 'Other' as FrameDescriptionEnum, + Integral: 'integral' as FrameDescriptionEnum, + BoxSection: 'Box section' as FrameDescriptionEnum, + USection: 'U section' as FrameDescriptionEnum, + }; + export type UpdateTypeEnum = 'adrUpdate' | 'techRecordUpdate'; + export const UpdateTypeEnum = { + AdrUpdate: 'adrUpdate' as UpdateTypeEnum, + TechRecordUpdate: 'techRecordUpdate' as UpdateTypeEnum, + }; + export type VehicleTypeEnum = 'psv' | 'hgv' | 'trl' | 'car' | 'lgv' | 'motorcycle'; + export const VehicleTypeEnum = { + Psv: 'psv' as VehicleTypeEnum, + Hgv: 'hgv' as VehicleTypeEnum, + Trl: 'trl' as VehicleTypeEnum, + Car: 'car' as VehicleTypeEnum, + Lgv: 'lgv' as VehicleTypeEnum, + Motorcycle: 'motorcycle' as VehicleTypeEnum, + }; + export type VehicleSizeEnum = 'small' | 'large'; + export const VehicleSizeEnum = { + Small: 'small' as VehicleSizeEnum, + Large: 'large' as VehicleSizeEnum, + }; + export type VehicleConfigurationEnum = + | 'rigid' + | 'articulated' + | 'centre axle drawbar' + | 'semi-car transporter' + | 'semi-trailer' + | 'low loader' + | 'other' + | 'drawbar' + | 'four-in-line' + | 'dolly' + | 'full drawbar'; + export const VehicleConfigurationEnum = { + Rigid: 'rigid' as VehicleConfigurationEnum, + Articulated: 'articulated' as VehicleConfigurationEnum, + CentreAxleDrawbar: 'centre axle drawbar' as VehicleConfigurationEnum, + SemiCarTransporter: 'semi-car transporter' as VehicleConfigurationEnum, + SemiTrailer: 'semi-trailer' as VehicleConfigurationEnum, + LowLoader: 'low loader' as VehicleConfigurationEnum, + Other: 'other' as VehicleConfigurationEnum, + Drawbar: 'drawbar' as VehicleConfigurationEnum, + FourInLine: 'four-in-line' as VehicleConfigurationEnum, + Dolly: 'dolly' as VehicleConfigurationEnum, + FullDrawbar: 'full drawbar' as VehicleConfigurationEnum, + }; } diff --git a/src/app/api/vehicle/model/techRecordArchiveAndProvisionalPayload.ts b/src/app/api/vehicle/model/techRecordArchiveAndProvisionalPayload.ts index 9e4492a955..9a73fbe0f5 100644 --- a/src/app/api/vehicle/model/techRecordArchiveAndProvisionalPayload.ts +++ b/src/app/api/vehicle/model/techRecordArchiveAndProvisionalPayload.ts @@ -11,7 +11,7 @@ import { TechRecord } from './techRecord'; import { TechRecordArchiveAndProvisionalPayloadMsUserDetails } from './techRecordArchiveAndProvisionalPayloadMsUserDetails'; -export interface TechRecordArchiveAndProvisionalPayload { - msUserDetails?: TechRecordArchiveAndProvisionalPayloadMsUserDetails; - techRecord?: TechRecord; -} \ No newline at end of file +export interface TechRecordArchiveAndProvisionalPayload { + msUserDetails?: TechRecordArchiveAndProvisionalPayloadMsUserDetails; + techRecord?: TechRecord; +} diff --git a/src/app/api/vehicle/model/techRecordArchiveAndProvisionalPayloadMsUserDetails.ts b/src/app/api/vehicle/model/techRecordArchiveAndProvisionalPayloadMsUserDetails.ts index f176a9f39c..0d9a727802 100644 --- a/src/app/api/vehicle/model/techRecordArchiveAndProvisionalPayloadMsUserDetails.ts +++ b/src/app/api/vehicle/model/techRecordArchiveAndProvisionalPayloadMsUserDetails.ts @@ -9,7 +9,7 @@ * Do not edit the class manually. */ -export interface TechRecordArchiveAndProvisionalPayloadMsUserDetails { - msUser?: string; - msOid?: string; -} \ No newline at end of file +export interface TechRecordArchiveAndProvisionalPayloadMsUserDetails { + msUser?: string; + msOid?: string; +} diff --git a/src/app/api/vehicle/model/techRecordBodyType.ts b/src/app/api/vehicle/model/techRecordBodyType.ts index 54b7f2fb14..38976eaf9e 100644 --- a/src/app/api/vehicle/model/techRecordBodyType.ts +++ b/src/app/api/vehicle/model/techRecordBodyType.ts @@ -12,56 +12,95 @@ /** * Used for all vehicles types - PSV, HGV and TRL. x = other, d = double decker. Used only for HGV and TRL. p = petrol/oil tanker, o = other tanker, s = skip loader, f = flat, c = refrigerated, b = box, e = curtainsider, k = skeletal, t = tipper, y = car transporter, i = livestock carrier. Used only for HGV. r = refuse, m = concrete mixer, a = fast trac tractor, u = artic unit. Used only for PSV. s = single decker, a = articulated, m = mini bus. Used only for TRL. l = low loader. */ -export interface TechRecordBodyType { - code?: TechRecordBodyType.CodeEnum; - description?: TechRecordBodyType.DescriptionEnum; +export interface TechRecordBodyType { + code?: TechRecordBodyType.CodeEnum; + description?: TechRecordBodyType.DescriptionEnum; } export namespace TechRecordBodyType { - export type CodeEnum = 'a' | 's' | 'd' | 'o' | 'x' | 'p' | 'k' | 't' | 'b' | 'f' | 'r' | 'c' | 'e' | 'y' | 'm' | 'i' | 'u' | 'l'; - export const CodeEnum = { - A: 'a' as CodeEnum, - S: 's' as CodeEnum, - D: 'd' as CodeEnum, - O: 'o' as CodeEnum, - M: 'm' as CodeEnum, - X: 'x' as CodeEnum, - P: 'p' as CodeEnum, - K: 'k' as CodeEnum, - T: 't' as CodeEnum, - B: 'b' as CodeEnum, - F: 'f' as CodeEnum, - R: 'r' as CodeEnum, - C: 'c' as CodeEnum, - E: 'e' as CodeEnum, - Y: 'y' as CodeEnum, - M_15: 'm' as CodeEnum, - I: 'i' as CodeEnum, - A_17: 'a' as CodeEnum, - U: 'u' as CodeEnum, - L: 'l' as CodeEnum - }; - export type DescriptionEnum = 'articulated' | 'single decker' | 'double decker' | 'other' | 'other tanker' | 'petrol/oil tanker' | 'skeletal' | 'tipper' | 'box' | 'flat' | 'refuse' | 'skip loader' | 'refrigerated' | 'curtainsider' | 'car transporter' | 'concrete mixer' | 'mini bus' | 'livestock carrier' | 'fast trac tractor' | 'artic unit' | 'low loader'; - export const DescriptionEnum = { - Articulated: 'articulated' as DescriptionEnum, - SingleDecker: 'single decker' as DescriptionEnum, - DoubleDecker: 'double decker' as DescriptionEnum, - Other: 'other' as DescriptionEnum, - OtherTanker: 'other tanker' as DescriptionEnum, - PetroloilTanker: 'petrol/oil tanker' as DescriptionEnum, - Skeletal: 'skeletal' as DescriptionEnum, - Tipper: 'tipper' as DescriptionEnum, - Box: 'box' as DescriptionEnum, - Flat: 'flat' as DescriptionEnum, - Refuse: 'refuse' as DescriptionEnum, - SkipLoader: 'skip loader' as DescriptionEnum, - Refrigerated: 'refrigerated' as DescriptionEnum, - Curtainsider: 'curtainsider' as DescriptionEnum, - CarTransporter: 'car transporter' as DescriptionEnum, - ConcreteMixer: 'concrete mixer' as DescriptionEnum, - MiniBus: 'mini bus' as DescriptionEnum, - LivestockCarrier: 'livestock carrier' as DescriptionEnum, - FastTracTractor: 'fast trac tractor' as DescriptionEnum, - ArticUnit: 'artic unit' as DescriptionEnum, - LowLoader: 'low loader' as DescriptionEnum - }; -} \ No newline at end of file + export type CodeEnum = + | 'a' + | 's' + | 'd' + | 'o' + | 'x' + | 'p' + | 'k' + | 't' + | 'b' + | 'f' + | 'r' + | 'c' + | 'e' + | 'y' + | 'm' + | 'i' + | 'u' + | 'l'; + export const CodeEnum = { + A: 'a' as CodeEnum, + S: 's' as CodeEnum, + D: 'd' as CodeEnum, + O: 'o' as CodeEnum, + M: 'm' as CodeEnum, + X: 'x' as CodeEnum, + P: 'p' as CodeEnum, + K: 'k' as CodeEnum, + T: 't' as CodeEnum, + B: 'b' as CodeEnum, + F: 'f' as CodeEnum, + R: 'r' as CodeEnum, + C: 'c' as CodeEnum, + E: 'e' as CodeEnum, + Y: 'y' as CodeEnum, + M_15: 'm' as CodeEnum, + I: 'i' as CodeEnum, + A_17: 'a' as CodeEnum, + U: 'u' as CodeEnum, + L: 'l' as CodeEnum, + }; + export type DescriptionEnum = + | 'articulated' + | 'single decker' + | 'double decker' + | 'other' + | 'other tanker' + | 'petrol/oil tanker' + | 'skeletal' + | 'tipper' + | 'box' + | 'flat' + | 'refuse' + | 'skip loader' + | 'refrigerated' + | 'curtainsider' + | 'car transporter' + | 'concrete mixer' + | 'mini bus' + | 'livestock carrier' + | 'fast trac tractor' + | 'artic unit' + | 'low loader'; + export const DescriptionEnum = { + Articulated: 'articulated' as DescriptionEnum, + SingleDecker: 'single decker' as DescriptionEnum, + DoubleDecker: 'double decker' as DescriptionEnum, + Other: 'other' as DescriptionEnum, + OtherTanker: 'other tanker' as DescriptionEnum, + PetroloilTanker: 'petrol/oil tanker' as DescriptionEnum, + Skeletal: 'skeletal' as DescriptionEnum, + Tipper: 'tipper' as DescriptionEnum, + Box: 'box' as DescriptionEnum, + Flat: 'flat' as DescriptionEnum, + Refuse: 'refuse' as DescriptionEnum, + SkipLoader: 'skip loader' as DescriptionEnum, + Refrigerated: 'refrigerated' as DescriptionEnum, + Curtainsider: 'curtainsider' as DescriptionEnum, + CarTransporter: 'car transporter' as DescriptionEnum, + ConcreteMixer: 'concrete mixer' as DescriptionEnum, + MiniBus: 'mini bus' as DescriptionEnum, + LivestockCarrier: 'livestock carrier' as DescriptionEnum, + FastTracTractor: 'fast trac tractor' as DescriptionEnum, + ArticUnit: 'artic unit' as DescriptionEnum, + LowLoader: 'low loader' as DescriptionEnum, + }; +} diff --git a/src/app/api/vehicle/model/techRecordDimensions.ts b/src/app/api/vehicle/model/techRecordDimensions.ts index ee3ee86de0..a45a94e78e 100644 --- a/src/app/api/vehicle/model/techRecordDimensions.ts +++ b/src/app/api/vehicle/model/techRecordDimensions.ts @@ -10,21 +10,21 @@ */ import { TechRecordDimensionsAxleSpacing } from './techRecordDimensionsAxleSpacing'; -export interface TechRecordDimensions { - /** - * Used for all vehicle types. Optional for PSV - */ - length?: number; - /** - * Used only for PSV - */ - height?: number; - /** - * Used for all vehicle types. Optional for PSV - */ - width?: number; - /** - * Used only for HGV and TRL - */ - axleSpacing?: Array; -} \ No newline at end of file +export interface TechRecordDimensions { + /** + * Used for all vehicle types. Optional for PSV + */ + length?: number; + /** + * Used only for PSV + */ + height?: number; + /** + * Used for all vehicle types. Optional for PSV + */ + width?: number; + /** + * Used only for HGV and TRL + */ + axleSpacing?: Array; +} diff --git a/src/app/api/vehicle/model/techRecordDimensionsAxleSpacing.ts b/src/app/api/vehicle/model/techRecordDimensionsAxleSpacing.ts index 7e2e900aee..c1872a51f6 100644 --- a/src/app/api/vehicle/model/techRecordDimensionsAxleSpacing.ts +++ b/src/app/api/vehicle/model/techRecordDimensionsAxleSpacing.ts @@ -9,10 +9,10 @@ * Do not edit the class manually. */ -export interface TechRecordDimensionsAxleSpacing { - axles?: string; - /** - * Optional for HGV - */ - value?: number; -} \ No newline at end of file +export interface TechRecordDimensionsAxleSpacing { + axles?: string; + /** + * Optional for HGV + */ + value?: number; +} diff --git a/src/app/api/vehicle/model/techRecordPOST.ts b/src/app/api/vehicle/model/techRecordPOST.ts index 554c971b4a..ea06a4e05e 100644 --- a/src/app/api/vehicle/model/techRecordPOST.ts +++ b/src/app/api/vehicle/model/techRecordPOST.ts @@ -11,23 +11,23 @@ import { TechRecordArchiveAndProvisionalPayloadMsUserDetails } from './techRecordArchiveAndProvisionalPayloadMsUserDetails'; import { TechRecords } from './techRecords'; -export interface TechRecordPOST { - msUserDetails?: TechRecordArchiveAndProvisionalPayloadMsUserDetails; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - vin?: string; - /** - * Mandatory for PSV, HGV, car, lgv, motorcycle. Optional for TRL - */ - primaryVrm?: string; - /** - * Mandatory for PSV and HGV. Optional for TRL - */ - secondaryVrms?: Array; - /** - * Used only for TRL. Optional for HGV and PSV - */ - trailerId?: string; - techRecord?: TechRecords; -} \ No newline at end of file +export interface TechRecordPOST { + msUserDetails?: TechRecordArchiveAndProvisionalPayloadMsUserDetails; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + vin?: string; + /** + * Mandatory for PSV, HGV, car, lgv, motorcycle. Optional for TRL + */ + primaryVrm?: string; + /** + * Mandatory for PSV and HGV. Optional for TRL + */ + secondaryVrms?: Array; + /** + * Used only for TRL. Optional for HGV and PSV + */ + trailerId?: string; + techRecord?: TechRecords; +} diff --git a/src/app/api/vehicle/model/techRecordPUT.ts b/src/app/api/vehicle/model/techRecordPUT.ts index 0e070ef150..d4300dc4f2 100644 --- a/src/app/api/vehicle/model/techRecordPUT.ts +++ b/src/app/api/vehicle/model/techRecordPUT.ts @@ -11,19 +11,19 @@ import { TechRecordArchiveAndProvisionalPayloadMsUserDetails } from './techRecordArchiveAndProvisionalPayloadMsUserDetails'; import { TechRecords } from './techRecords'; -export interface TechRecordPUT { - msUserDetails?: TechRecordArchiveAndProvisionalPayloadMsUserDetails; - /** - * Mandatory for PSV, HGV, car, lgv, motorcycle. Optional for TRL - */ - primaryVrm?: string; - /** - * Mandatory for PSV and HGV. Optional for TRL - */ - secondaryVrms?: Array; - /** - * Used only for TRL. Optional for HGV and PSV - */ - trailerId?: string; - techRecord?: TechRecords; -} \ No newline at end of file +export interface TechRecordPUT { + msUserDetails?: TechRecordArchiveAndProvisionalPayloadMsUserDetails; + /** + * Mandatory for PSV, HGV, car, lgv, motorcycle. Optional for TRL + */ + primaryVrm?: string; + /** + * Mandatory for PSV and HGV. Optional for TRL + */ + secondaryVrms?: Array; + /** + * Used only for TRL. Optional for HGV and PSV + */ + trailerId?: string; + techRecord?: TechRecords; +} diff --git a/src/app/api/vehicle/model/techRecordVehicleClass.ts b/src/app/api/vehicle/model/techRecordVehicleClass.ts index 222584bb61..52a0c14f85 100644 --- a/src/app/api/vehicle/model/techRecordVehicleClass.ts +++ b/src/app/api/vehicle/model/techRecordVehicleClass.ts @@ -12,37 +12,48 @@ /** * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle. Optional for CAR and LGV */ -export interface TechRecordVehicleClass { - code?: TechRecordVehicleClass.CodeEnum; - description?: TechRecordVehicleClass.DescriptionEnum; +export interface TechRecordVehicleClass { + code?: TechRecordVehicleClass.CodeEnum; + description?: TechRecordVehicleClass.DescriptionEnum; } export namespace TechRecordVehicleClass { - export type CodeEnum = '2' | 'n' | 's' | '1' | 't' | 'l' | '3' | 'v' | '4' | '7' | '5'; - export const CodeEnum = { - _2: '2' as CodeEnum, - N: 'n' as CodeEnum, - S: 's' as CodeEnum, - _1: '1' as CodeEnum, - T: 't' as CodeEnum, - L: 'l' as CodeEnum, - _3: '3' as CodeEnum, - V: 'v' as CodeEnum, - _4: '4' as CodeEnum, - _7: '7' as CodeEnum, - _5: '5' as CodeEnum - }; - export type DescriptionEnum = 'motorbikes over 200cc or with a sidecar' | 'not applicable' | 'small psv (ie: less than or equal to 22 seats)' | 'motorbikes up to 200cc' | 'trailer' | 'large psv(ie: greater than 23 seats)' | '3 wheelers' | 'heavy goods vehicle' | 'MOT class 4' | 'MOT class 7' | 'MOT class 5'; - export const DescriptionEnum = { - MotorbikesOver200ccOrWithASidecar: 'motorbikes over 200cc or with a sidecar' as DescriptionEnum, - NotApplicable: 'not applicable' as DescriptionEnum, - SmallPsvIeLessThanOrEqualTo22Seats: 'small psv (ie: less than or equal to 22 seats)' as DescriptionEnum, - MotorbikesUpTo200cc: 'motorbikes up to 200cc' as DescriptionEnum, - Trailer: 'trailer' as DescriptionEnum, - LargePsvIeGreaterThan23Seats: 'large psv(ie: greater than 23 seats)' as DescriptionEnum, - _3Wheelers: '3 wheelers' as DescriptionEnum, - HeavyGoodsVehicle: 'heavy goods vehicle' as DescriptionEnum, - MOTClass4: 'MOT class 4' as DescriptionEnum, - MOTClass7: 'MOT class 7' as DescriptionEnum, - MOTClass5: 'MOT class 5' as DescriptionEnum, - }; -} \ No newline at end of file + export type CodeEnum = '2' | 'n' | 's' | '1' | 't' | 'l' | '3' | 'v' | '4' | '7' | '5'; + export const CodeEnum = { + _2: '2' as CodeEnum, + N: 'n' as CodeEnum, + S: 's' as CodeEnum, + _1: '1' as CodeEnum, + T: 't' as CodeEnum, + L: 'l' as CodeEnum, + _3: '3' as CodeEnum, + V: 'v' as CodeEnum, + _4: '4' as CodeEnum, + _7: '7' as CodeEnum, + _5: '5' as CodeEnum, + }; + export type DescriptionEnum = + | 'motorbikes over 200cc or with a sidecar' + | 'not applicable' + | 'small psv (ie: less than or equal to 22 seats)' + | 'motorbikes up to 200cc' + | 'trailer' + | 'large psv(ie: greater than 23 seats)' + | '3 wheelers' + | 'heavy goods vehicle' + | 'MOT class 4' + | 'MOT class 7' + | 'MOT class 5'; + export const DescriptionEnum = { + MotorbikesOver200ccOrWithASidecar: 'motorbikes over 200cc or with a sidecar' as DescriptionEnum, + NotApplicable: 'not applicable' as DescriptionEnum, + SmallPsvIeLessThanOrEqualTo22Seats: 'small psv (ie: less than or equal to 22 seats)' as DescriptionEnum, + MotorbikesUpTo200cc: 'motorbikes up to 200cc' as DescriptionEnum, + Trailer: 'trailer' as DescriptionEnum, + LargePsvIeGreaterThan23Seats: 'large psv(ie: greater than 23 seats)' as DescriptionEnum, + _3Wheelers: '3 wheelers' as DescriptionEnum, + HeavyGoodsVehicle: 'heavy goods vehicle' as DescriptionEnum, + MOTClass4: 'MOT class 4' as DescriptionEnum, + MOTClass7: 'MOT class 7' as DescriptionEnum, + MOTClass5: 'MOT class 5' as DescriptionEnum, + }; +} diff --git a/src/app/api/vehicle/model/techRecords.ts b/src/app/api/vehicle/model/techRecords.ts index 08d9cebcdb..8e5898fe8b 100644 --- a/src/app/api/vehicle/model/techRecords.ts +++ b/src/app/api/vehicle/model/techRecords.ts @@ -10,5 +10,4 @@ */ import { TechRecord } from './techRecord'; -export interface TechRecords extends Array { -} \ No newline at end of file +export interface TechRecords extends Array {} diff --git a/src/app/api/vehicle/model/vrm.ts b/src/app/api/vehicle/model/vrm.ts index e3c79d95ba..69bb5cce13 100644 --- a/src/app/api/vehicle/model/vrm.ts +++ b/src/app/api/vehicle/model/vrm.ts @@ -12,7 +12,7 @@ /** * Used only for PSV and HGV */ -export interface Vrm { - vrm?: string; - isPrimary?: boolean; -} \ No newline at end of file +export interface Vrm { + vrm?: string; + isPrimary?: boolean; +} diff --git a/src/app/api/vehicle/model/vrms.ts b/src/app/api/vehicle/model/vrms.ts index d614ec759f..80800601b0 100644 --- a/src/app/api/vehicle/model/vrms.ts +++ b/src/app/api/vehicle/model/vrms.ts @@ -10,5 +10,4 @@ */ import { Vrm } from './vrm'; -export interface Vrms extends Array { -} \ No newline at end of file +export interface Vrms extends Array {} diff --git a/src/app/api/vehicle/model/weights.ts b/src/app/api/vehicle/model/weights.ts index 75fb0334f5..0b72e5a0f1 100644 --- a/src/app/api/vehicle/model/weights.ts +++ b/src/app/api/vehicle/model/weights.ts @@ -12,16 +12,16 @@ import { AxleBrakeProperties } from './axleBrakeProperties'; import { AxleTyreProperties } from './axleTyreProperties'; import { AxleWeightProperties } from './axleWeightProperties'; -export interface Weights { - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - axleNumber?: number; - /** - * Used for all vehicle types - PSV, HGV and TRL. Optional for HGV - */ - parkingBrakeMrk?: boolean; - weights?: AxleWeightProperties; - tyres?: AxleTyreProperties; - brakes?: AxleBrakeProperties; -} \ No newline at end of file +export interface Weights { + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + axleNumber?: number; + /** + * Used for all vehicle types - PSV, HGV and TRL. Optional for HGV + */ + parkingBrakeMrk?: boolean; + weights?: AxleWeightProperties; + tyres?: AxleTyreProperties; + brakes?: AxleBrakeProperties; +} diff --git a/src/app/api/vehicle/variables.ts b/src/app/api/vehicle/variables.ts index 6fe58549f3..9bae45f800 100644 --- a/src/app/api/vehicle/variables.ts +++ b/src/app/api/vehicle/variables.ts @@ -2,8 +2,8 @@ import { InjectionToken } from '@angular/core'; export const BASE_PATH = new InjectionToken('basePath'); export const COLLECTION_FORMATS = { - 'csv': ',', - 'tsv': ' ', - 'ssv': ' ', - 'pipes': '|' -} + csv: ',', + tsv: ' ', + ssv: ' ', + pipes: '|', +}; diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 3f609e8a19..cd088077ed 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -12,76 +12,81 @@ import { techRecordViewResolver } from './resolvers/tech-record-view/tech-record import { titleResolver } from './resolvers/title/title.resolver'; const routes: Routes = [ - { - path: RootRoutes.ROOT, - resolve: { title: titleResolver }, - children: [ - { - path: RootRoutes.ROOT, - data: { title: 'Home', roles: Roles.TechRecordView }, - canActivate: [MsalGuard, RoleGuard], - canDeactivate: [CancelEditTechGuard], - loadChildren: () => import('./features/home/home.module').then((m) => m.HomeModule), - }, - { - path: RootRoutes.SEARCH_TECHNICAL_RECORD, - data: { title: 'Technical record search', roles: Roles.TechRecordView }, - canActivate: [MsalGuard, RoleGuard], - canDeactivate: [CancelEditTechGuard], - loadChildren: () => import('./features/search/search.module').then((m) => m.SearchModule), - }, - { - path: RootRoutes.CREATE_TECHNICAL_RECORD, - data: { title: 'Create new technical record', roles: Roles.TechRecordCreate }, - canActivate: [MsalGuard, RoleGuard], - loadChildren: () => import('./features/tech-record/create/create-tech-records.module').then((m) => m.CreateTechRecordsModule), - }, - { - path: RootRoutes.BATCH_CREATE_TECHNICAL_RECORD, - data: { title: 'Select Vehicle Type', roles: Roles.TechRecordCreate }, - canActivate: [MsalGuard, RoleGuard], - loadChildren: () => import('./features/tech-record/create-batch/create-batch.module').then((m) => m.CreateBatchModule), - }, - { - path: RootRoutes.CURRENT_TEST_RESULT, - data: { title: 'Test Result', roles: Roles.TestResultView }, - canActivate: [MsalGuard, RoleGuard], - resolve: { techRecord: techRecordViewResolver }, - loadChildren: () => import('./features/test-records/amend/amend-test-records.module').then((m) => m.AmendTestRecordsModule), - }, - { - path: RootRoutes.CURRENT_TECH_RECORD, - data: { title: 'Tech Record', roles: Roles.TechRecordView }, - canActivate: [MsalGuard, RoleGuard], - loadChildren: () => import('./features/tech-record/tech-record.module').then((m) => m.TechRecordsModule), - }, - { - path: RootRoutes.REFERENCE_DATA, - data: { title: 'Select Reference Data Type', roles: Roles.ReferenceDataView }, - canActivate: [MsalGuard, RoleGuard], - loadChildren: () => import('./features/reference-data/reference-data.module').then((m) => m.ReferenceDataModule), - }, - { - path: RootRoutes.FEATURE_TOGGLE, - data: { title: 'Feature Toggle', featureToggleName: 'testToggle' }, - canActivate: [MsalGuard, FeatureToggleGuard], - loadChildren: () => import('./features/feature-toggle/feature-toggle.module').then((m) => m.FeatureToggleModule), - }, - { - path: RootRoutes.ERROR, - pathMatch: 'full', - component: ServerErrorComponent, - }, - ], - }, - { - path: RootRoutes.WILDCARD, - pathMatch: 'full', - component: PageNotFoundComponent, - }, + { + path: RootRoutes.ROOT, + resolve: { title: titleResolver }, + children: [ + { + path: RootRoutes.ROOT, + data: { title: 'Home', roles: Roles.TechRecordView }, + canActivate: [MsalGuard, RoleGuard], + canDeactivate: [CancelEditTechGuard], + loadChildren: () => import('./features/home/home.module').then((m) => m.HomeModule), + }, + { + path: RootRoutes.SEARCH_TECHNICAL_RECORD, + data: { title: 'Technical record search', roles: Roles.TechRecordView }, + canActivate: [MsalGuard, RoleGuard], + canDeactivate: [CancelEditTechGuard], + loadChildren: () => import('./features/search/search.module').then((m) => m.SearchModule), + }, + { + path: RootRoutes.CREATE_TECHNICAL_RECORD, + data: { title: 'Create new technical record', roles: Roles.TechRecordCreate }, + canActivate: [MsalGuard, RoleGuard], + loadChildren: () => + import('./features/tech-record/create/create-tech-records.module').then((m) => m.CreateTechRecordsModule), + }, + { + path: RootRoutes.BATCH_CREATE_TECHNICAL_RECORD, + data: { title: 'Select Vehicle Type', roles: Roles.TechRecordCreate }, + canActivate: [MsalGuard, RoleGuard], + loadChildren: () => + import('./features/tech-record/create-batch/create-batch.module').then((m) => m.CreateBatchModule), + }, + { + path: RootRoutes.CURRENT_TEST_RESULT, + data: { title: 'Test Result', roles: Roles.TestResultView }, + canActivate: [MsalGuard, RoleGuard], + resolve: { techRecord: techRecordViewResolver }, + loadChildren: () => + import('./features/test-records/amend/amend-test-records.module').then((m) => m.AmendTestRecordsModule), + }, + { + path: RootRoutes.CURRENT_TECH_RECORD, + data: { title: 'Tech Record', roles: Roles.TechRecordView }, + canActivate: [MsalGuard, RoleGuard], + loadChildren: () => import('./features/tech-record/tech-record.module').then((m) => m.TechRecordsModule), + }, + { + path: RootRoutes.REFERENCE_DATA, + data: { title: 'Select Reference Data Type', roles: Roles.ReferenceDataView }, + canActivate: [MsalGuard, RoleGuard], + loadChildren: () => + import('./features/reference-data/reference-data.module').then((m) => m.ReferenceDataModule), + }, + { + path: RootRoutes.FEATURE_TOGGLE, + data: { title: 'Feature Toggle', featureToggleName: 'testToggle' }, + canActivate: [MsalGuard, FeatureToggleGuard], + loadChildren: () => + import('./features/feature-toggle/feature-toggle.module').then((m) => m.FeatureToggleModule), + }, + { + path: RootRoutes.ERROR, + pathMatch: 'full', + component: ServerErrorComponent, + }, + ], + }, + { + path: RootRoutes.WILDCARD, + pathMatch: 'full', + component: PageNotFoundComponent, + }, ]; @NgModule({ - imports: [RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' })], - exports: [RouterModule], + imports: [RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' })], + exports: [RouterModule], }) export class AppRoutingModule {} diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts index 8ebd5a60b4..2a11b0340c 100644 --- a/src/app/app.component.spec.ts +++ b/src/app/app.component.spec.ts @@ -1,130 +1,132 @@ import { TestBed } from '@angular/core/testing'; +import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { MsalModule } from '@azure/msal-angular'; +import { PageNotFoundComponent } from '@core/components/page-not-found/page-not-found.component'; import { CoreModule } from '@core/core.module'; +import { GoogleAnalyticsServiceMock } from '@mocks/google-analytics-service.mock'; import { StoreModule } from '@ngrx/store'; import { provideMockStore } from '@ngrx/store/testing'; import { LoadingService } from '@services/loading/loading.service'; import { UserService } from '@services/user-service/user-service'; -import { Observable, of } from 'rxjs'; -import { Router } from '@angular/router'; -import { PageNotFoundComponent } from '@core/components/page-not-found/page-not-found.component'; // eslint-disable-next-line import/no-extraneous-dependencies import { GoogleTagManagerService } from 'angular-google-tag-manager'; -import { GoogleAnalyticsServiceMock } from '@mocks/google-analytics-service.mock'; +import { Observable, of } from 'rxjs'; +import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { State, initialAppState } from './store'; -import { AppRoutingModule } from './app-routing.module'; describe('AppComponent', () => { - const MockUserService = { - getUserName$: jest.fn().mockReturnValue(new Observable()), - }; - let router: Router; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [CoreModule, MsalModule, RouterTestingModule, AppRoutingModule, StoreModule.forRoot({})], - declarations: [PageNotFoundComponent, AppComponent], - providers: [ - provideMockStore({ initialState: initialAppState }), - { provide: LoadingService, useValue: { showSpinner$: of(false) } }, - { provide: UserService, useValue: MockUserService }, - PageNotFoundComponent, - { provide: GoogleTagManagerService, useClass: GoogleAnalyticsServiceMock }, - ], - }).compileComponents(); - router = TestBed.inject(Router); - }); - - it('should create the app', () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - fixture.detectChanges(); - expect(app).toBeTruthy(); - }); - - describe('router.initialNavigation', () => { - it('should init at default page', () => { - router.initialNavigation(); - expect(router.url).toBe('/'); - }); - }); - - describe('router.navigateByUrl', () => { - it('should navigate to search page', () => { - const navigateSpy = jest.spyOn(router, 'navigateByUrl'); - void router.navigateByUrl('/search'); - - expect(navigateSpy).toHaveBeenCalledWith('/search'); - }); - - it('should navigate to create page', () => { - const navigateSpy = jest.spyOn(router, 'navigateByUrl'); - void router.navigateByUrl('/create'); - - expect(navigateSpy).toHaveBeenCalledWith('/create'); - }); - - it('should navigate to create-batch page', () => { - const navigateSpy = jest.spyOn(router, 'navigateByUrl'); - void router.navigateByUrl('/create-batch'); - - expect(navigateSpy).toHaveBeenCalledWith('/create-batch'); - }); - - it('should navigate to test-records/:systemNumber/test-result/:testResultId/:testNumber', () => { - const navigateSpy = jest.spyOn(router, 'navigateByUrl'); - const systemNumber = '123'; - const testResultId = '456'; - const testNumber = '789'; - - void router.navigateByUrl(`test-records/${systemNumber}/test-result/${testResultId}/${testNumber}`); - - expect(navigateSpy).toHaveBeenCalledWith(`test-records/${systemNumber}/test-result/${testResultId}/${testNumber}`); - }); - - it('should navigate to tech-records/:systemNumber/:createdTimestamp', () => { - const navigateSpy = jest.spyOn(router, 'navigateByUrl'); - const systemNumber = '123'; - const createdTimestamp = '2024-02-23T09:56:12.872Z'; - - void router.navigateByUrl(`tech-records/${systemNumber}/${createdTimestamp}`); - - expect(navigateSpy).toHaveBeenCalledWith(`tech-records/${systemNumber}/${createdTimestamp}`); - }); - - it('should navigate to reference-data page', () => { - const navigateSpy = jest.spyOn(router, 'navigateByUrl'); - void router.navigateByUrl('/reference-data'); - - expect(navigateSpy).toHaveBeenCalledWith('/reference-data'); - }); - - it('should navigate to feature-toggle page', () => { - const navigateSpy = jest.spyOn(router, 'navigateByUrl'); - void router.navigateByUrl('/feature-toggle'); - - expect(navigateSpy).toHaveBeenCalledWith('/feature-toggle'); - }); - - it('should navigate to error page', () => { - const navigateSpy = jest.spyOn(router, 'navigateByUrl'); - void router.navigateByUrl('/error'); - - expect(navigateSpy).toHaveBeenCalledWith('/error'); - }); - - it('should navigate to PageNotFoundComponent page', () => { - const navigateSpy = jest.spyOn(router, 'navigateByUrl'); - const invalidRoute = 'invalid-url'; - void router.navigateByUrl(invalidRoute); - - expect(navigateSpy).toHaveBeenCalledWith(invalidRoute); - - const currentComponent = TestBed.inject(PageNotFoundComponent); - - expect(currentComponent).toBeTruthy(); - }); - }); + const MockUserService = { + getUserName$: jest.fn().mockReturnValue(new Observable()), + }; + let router: Router; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [CoreModule, MsalModule, RouterTestingModule, AppRoutingModule, StoreModule.forRoot({})], + declarations: [PageNotFoundComponent, AppComponent], + providers: [ + provideMockStore({ initialState: initialAppState }), + { provide: LoadingService, useValue: { showSpinner$: of(false) } }, + { provide: UserService, useValue: MockUserService }, + PageNotFoundComponent, + { provide: GoogleTagManagerService, useClass: GoogleAnalyticsServiceMock }, + ], + }).compileComponents(); + router = TestBed.inject(Router); + }); + + it('should create the app', () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.componentInstance; + fixture.detectChanges(); + expect(app).toBeTruthy(); + }); + + describe('router.initialNavigation', () => { + it('should init at default page', () => { + router.initialNavigation(); + expect(router.url).toBe('/'); + }); + }); + + describe('router.navigateByUrl', () => { + it('should navigate to search page', () => { + const navigateSpy = jest.spyOn(router, 'navigateByUrl'); + void router.navigateByUrl('/search'); + + expect(navigateSpy).toHaveBeenCalledWith('/search'); + }); + + it('should navigate to create page', () => { + const navigateSpy = jest.spyOn(router, 'navigateByUrl'); + void router.navigateByUrl('/create'); + + expect(navigateSpy).toHaveBeenCalledWith('/create'); + }); + + it('should navigate to create-batch page', () => { + const navigateSpy = jest.spyOn(router, 'navigateByUrl'); + void router.navigateByUrl('/create-batch'); + + expect(navigateSpy).toHaveBeenCalledWith('/create-batch'); + }); + + it('should navigate to test-records/:systemNumber/test-result/:testResultId/:testNumber', () => { + const navigateSpy = jest.spyOn(router, 'navigateByUrl'); + const systemNumber = '123'; + const testResultId = '456'; + const testNumber = '789'; + + void router.navigateByUrl(`test-records/${systemNumber}/test-result/${testResultId}/${testNumber}`); + + expect(navigateSpy).toHaveBeenCalledWith( + `test-records/${systemNumber}/test-result/${testResultId}/${testNumber}` + ); + }); + + it('should navigate to tech-records/:systemNumber/:createdTimestamp', () => { + const navigateSpy = jest.spyOn(router, 'navigateByUrl'); + const systemNumber = '123'; + const createdTimestamp = '2024-02-23T09:56:12.872Z'; + + void router.navigateByUrl(`tech-records/${systemNumber}/${createdTimestamp}`); + + expect(navigateSpy).toHaveBeenCalledWith(`tech-records/${systemNumber}/${createdTimestamp}`); + }); + + it('should navigate to reference-data page', () => { + const navigateSpy = jest.spyOn(router, 'navigateByUrl'); + void router.navigateByUrl('/reference-data'); + + expect(navigateSpy).toHaveBeenCalledWith('/reference-data'); + }); + + it('should navigate to feature-toggle page', () => { + const navigateSpy = jest.spyOn(router, 'navigateByUrl'); + void router.navigateByUrl('/feature-toggle'); + + expect(navigateSpy).toHaveBeenCalledWith('/feature-toggle'); + }); + + it('should navigate to error page', () => { + const navigateSpy = jest.spyOn(router, 'navigateByUrl'); + void router.navigateByUrl('/error'); + + expect(navigateSpy).toHaveBeenCalledWith('/error'); + }); + + it('should navigate to PageNotFoundComponent page', () => { + const navigateSpy = jest.spyOn(router, 'navigateByUrl'); + const invalidRoute = 'invalid-url'; + void router.navigateByUrl(invalidRoute); + + expect(navigateSpy).toHaveBeenCalledWith(invalidRoute); + + const currentComponent = TestBed.inject(PageNotFoundComponent); + + expect(currentComponent).toBeTruthy(); + }); + }); }); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 412589a369..90c2cfbf34 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -7,82 +7,77 @@ import * as Sentry from '@sentry/angular-ivy'; import { LoadingService } from '@services/loading/loading.service'; import { UserService } from '@services/user-service/user-service'; import { selectRouteData } from '@store/router/selectors/router.selectors'; -import { initAll } from 'govuk-frontend/govuk/all'; -import { - Subject, - map, - take, takeUntil, -} from 'rxjs'; // eslint-disable-next-line import/no-extraneous-dependencies import { GoogleTagManagerService } from 'angular-google-tag-manager'; +import { initAll } from 'govuk-frontend/govuk/all'; +import { Subject, map, take, takeUntil } from 'rxjs'; import packageInfo from '../../package.json'; import { environment } from '../environments/environment'; import { State } from './store'; @Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['app.component.scss'], + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['app.component.scss'], }) export class AppComponent implements OnInit, OnDestroy { - private destroy$ = new Subject(); - - constructor( - public userService: UserService, - private loadingService: LoadingService, - private router: Router, - private gtmService: GoogleTagManagerService, - private store: Store, - ) { } + private destroy$ = new Subject(); - async ngOnInit() { - this.startSentry(); - this.router.events.pipe(takeUntil(this.destroy$)).subscribe((event: Event) => { - if (event instanceof NavigationEnd) { + constructor( + public userService: UserService, + private loadingService: LoadingService, + private router: Router, + private gtmService: GoogleTagManagerService, + private store: Store + ) {} - const gtmTag = { - event: document.title, - pageName: event.urlAfterRedirects, - }; - void this.gtmService.pushTag(gtmTag); - } - }); - await this.gtmService.addGtmToDom(); - initAll(); - } + async ngOnInit() { + this.startSentry(); + this.router.events.pipe(takeUntil(this.destroy$)).subscribe((event: Event) => { + if (event instanceof NavigationEnd) { + const gtmTag = { + event: document.title, + pageName: event.urlAfterRedirects, + }; + void this.gtmService.pushTag(gtmTag); + } + }); + await this.gtmService.addGtmToDom(); + initAll(); + } - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } - get isStandardLayout() { - return this.store.pipe( - take(1), - select(selectRouteData), - map((routeData) => routeData && !routeData['isCustomLayout']), - ); - } + get isStandardLayout() { + return this.store.pipe( + take(1), + select(selectRouteData), + map((routeData) => routeData && !routeData['isCustomLayout']) + ); + } - get loading() { - return this.loadingService.showSpinner$; - } + get loading() { + return this.loadingService.showSpinner$; + } - startSentry() { - Sentry.init({ - dsn: environment.SENTRY_DSN, - environment: environment.production ? 'production' : 'development', - release: packageInfo.version, - replaysSessionSampleRate: 0.1, - tracesSampleRate: 0.025, - replaysOnErrorSampleRate: 1.0, - enableTracing: false, - integrations: [ - new Sentry.BrowserTracing({ - routingInstrumentation: Sentry.routingInstrumentation, - }), - new Sentry.Replay(), - ], - }); - } + startSentry() { + Sentry.init({ + dsn: environment.SENTRY_DSN, + environment: environment.production ? 'production' : 'development', + release: packageInfo.version, + replaysSessionSampleRate: 0.1, + tracesSampleRate: 0.025, + replaysOnErrorSampleRate: 1.0, + enableTracing: false, + integrations: [ + new Sentry.BrowserTracing({ + routingInstrumentation: Sentry.routingInstrumentation, + }), + new Sentry.Replay(), + ], + }); + } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 5dc98bda00..8b1dfd3271 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,9 +1,5 @@ import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http'; -import { - APP_INITIALIZER, - ErrorHandler, - LOCALE_ID, NgModule, -} from '@angular/core'; +import { APP_INITIALIZER, ErrorHandler, LOCALE_ID, NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { Router } from '@angular/router'; import { DocumentRetrievalApiModule, Configuration as DocumentRetrievalConfiguration } from '@api/document-retrieval'; @@ -11,23 +7,23 @@ import { ApiModule as ReferenceDataApiModule, Configuration as ReferenceDataConf import { Configuration as TestResultsApiConfiguration, ApiModule as TestResultsApiModule } from '@api/test-results'; import { Configuration as TestTypesApiConfiguration, ApiModule as TestTypesApiModule } from '@api/test-types'; import { - MSAL_GUARD_CONFIG, - MSAL_INSTANCE, - MSAL_INTERCEPTOR_CONFIG, - MsalBroadcastService, - MsalGuard, - MsalGuardConfiguration, - MsalInterceptor, - MsalInterceptorConfiguration, - MsalModule, - MsalRedirectComponent, - MsalService, + MSAL_GUARD_CONFIG, + MSAL_INSTANCE, + MSAL_INTERCEPTOR_CONFIG, + MsalBroadcastService, + MsalGuard, + MsalGuardConfiguration, + MsalInterceptor, + MsalInterceptorConfiguration, + MsalModule, + MsalRedirectComponent, + MsalService, } from '@azure/msal-angular'; import { - BrowserCacheLocation, - IPublicClientApplication, - InteractionType, - PublicClientApplication, + BrowserCacheLocation, + IPublicClientApplication, + InteractionType, + PublicClientApplication, } from '@azure/msal-browser'; import * as Sentry from '@sentry/angular-ivy'; import { FeatureToggleService } from '@services/feature-toggle-service/feature-toggle-service'; @@ -42,125 +38,123 @@ import { UserService } from './services/user-service/user-service'; import { AppStoreModule } from './store/app-store.module'; export function MSALInstanceFactory(): IPublicClientApplication { - return new PublicClientApplication({ - auth: { - clientId: environment.VTM_CLIENT_ID, - authority: environment.VTM_AUTHORITY_ID, - redirectUri: environment.VTM_REDIRECT_URI, - }, - cache: { - cacheLocation: BrowserCacheLocation.LocalStorage, - storeAuthStateInCookie: true, - }, - }); + return new PublicClientApplication({ + auth: { + clientId: environment.VTM_CLIENT_ID, + authority: environment.VTM_AUTHORITY_ID, + redirectUri: environment.VTM_REDIRECT_URI, + }, + cache: { + cacheLocation: BrowserCacheLocation.LocalStorage, + storeAuthStateInCookie: true, + }, + }); } export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration { - const protectedResourceMap = new Map>(); - protectedResourceMap.set(environment.VTM_API_URI, [`${environment.VTM_API_CLIENT_ID}/user_impersonation`, 'email']); + const protectedResourceMap = new Map>(); + protectedResourceMap.set(environment.VTM_API_URI, [`${environment.VTM_API_CLIENT_ID}/user_impersonation`, 'email']); - return { - interactionType: InteractionType.Redirect, - protectedResourceMap, - }; + return { + interactionType: InteractionType.Redirect, + protectedResourceMap, + }; } export function MSALGuardConfigFactory(): MsalGuardConfiguration { - return { - interactionType: InteractionType.Redirect, - authRequest: { - scopes: [`${environment.VTM_API_CLIENT_ID}/user_impersonation`, 'email'], - }, - loginFailedRoute: '', - }; + return { + interactionType: InteractionType.Redirect, + authRequest: { + scopes: [`${environment.VTM_API_CLIENT_ID}/user_impersonation`, 'email'], + }, + loginFailedRoute: '', + }; } -const featureFactory = (featureFlagsService: FeatureToggleService) => () => - featureFlagsService.loadConfig(); +const featureFactory = (featureFlagsService: FeatureToggleService) => () => featureFlagsService.loadConfig(); @NgModule({ - declarations: [AppComponent], - imports: [ - BrowserModule, - AppRoutingModule, - MsalModule, - HttpClientModule, - AppStoreModule, - InterceptorModule, - CoreModule, - TestResultsApiModule.forRoot(() => new TestResultsApiConfiguration({ basePath: environment.VTM_API_URI })), - TestTypesApiModule.forRoot(() => new TestTypesApiConfiguration({ basePath: environment.VTM_API_URI })), - ReferenceDataApiModule.forRoot(() => new ReferenceDataConfiguration({ basePath: environment.VTM_API_URI })), - DocumentRetrievalApiModule.forRoot( - () => - new DocumentRetrievalConfiguration({ - basePath: environment.VTM_API_URI, - apiKeys: { - 'X-Api-Key': environment.DOCUMENT_RETRIEVAL_API_KEY, - }, - }), - ), - GoogleTagManagerModule.forRoot({ - id: environment.VTM_GTM_CONTAINER_ID, - }), - ], - providers: [ - { - provide: LOCALE_ID, - useValue: 'en', - }, - { - provide: HTTP_INTERCEPTORS, - useClass: MsalInterceptor, - multi: true, - }, - { - provide: MSAL_INSTANCE, - useFactory: MSALInstanceFactory, - }, - { - provide: MSAL_GUARD_CONFIG, - useFactory: MSALGuardConfigFactory, - }, - { - provide: MSAL_INTERCEPTOR_CONFIG, - useFactory: MSALInterceptorConfigFactory, - }, - { - provide: APP_INITIALIZER, - useFactory: featureFactory, - deps: [FeatureToggleService], - multi: true, - }, - { - provide: ErrorHandler, - useValue: Sentry.createErrorHandler({ - showDialog: true, - }), - }, - { - provide: Sentry.TraceService, - deps: [Router], - }, - { - provide: APP_INITIALIZER, - useFactory: () => () => {}, - deps: [Sentry.TraceService], - multi: true, - }, - { - provide: ErrorHandler, - useValue: Sentry.createErrorHandler({ - showDialog: false, - }), - }, - MsalService, - MsalGuard, - MsalBroadcastService, - UserService, - ], - exports: [], - bootstrap: [AppComponent, MsalRedirectComponent], + declarations: [AppComponent], + imports: [ + BrowserModule, + AppRoutingModule, + MsalModule, + HttpClientModule, + AppStoreModule, + InterceptorModule, + CoreModule, + TestResultsApiModule.forRoot(() => new TestResultsApiConfiguration({ basePath: environment.VTM_API_URI })), + TestTypesApiModule.forRoot(() => new TestTypesApiConfiguration({ basePath: environment.VTM_API_URI })), + ReferenceDataApiModule.forRoot(() => new ReferenceDataConfiguration({ basePath: environment.VTM_API_URI })), + DocumentRetrievalApiModule.forRoot( + () => + new DocumentRetrievalConfiguration({ + basePath: environment.VTM_API_URI, + apiKeys: { + 'X-Api-Key': environment.DOCUMENT_RETRIEVAL_API_KEY, + }, + }) + ), + GoogleTagManagerModule.forRoot({ + id: environment.VTM_GTM_CONTAINER_ID, + }), + ], + providers: [ + { + provide: LOCALE_ID, + useValue: 'en', + }, + { + provide: HTTP_INTERCEPTORS, + useClass: MsalInterceptor, + multi: true, + }, + { + provide: MSAL_INSTANCE, + useFactory: MSALInstanceFactory, + }, + { + provide: MSAL_GUARD_CONFIG, + useFactory: MSALGuardConfigFactory, + }, + { + provide: MSAL_INTERCEPTOR_CONFIG, + useFactory: MSALInterceptorConfigFactory, + }, + { + provide: APP_INITIALIZER, + useFactory: featureFactory, + deps: [FeatureToggleService], + multi: true, + }, + { + provide: ErrorHandler, + useValue: Sentry.createErrorHandler({ + showDialog: true, + }), + }, + { + provide: Sentry.TraceService, + deps: [Router], + }, + { + provide: APP_INITIALIZER, + useFactory: () => () => {}, + deps: [Sentry.TraceService], + multi: true, + }, + { + provide: ErrorHandler, + useValue: Sentry.createErrorHandler({ + showDialog: false, + }), + }, + MsalService, + MsalGuard, + MsalBroadcastService, + UserService, + ], + exports: [], + bootstrap: [AppComponent, MsalRedirectComponent], }) -export class AppModule { -} +export class AppModule {} diff --git a/src/app/app.stories.ts b/src/app/app.stories.ts index bc53031a78..b52efe0a28 100644 --- a/src/app/app.stories.ts +++ b/src/app/app.stories.ts @@ -3,10 +3,10 @@ import { Meta, Story } from '@storybook/angular'; import { AppComponent } from './app.component'; export default { - title: 'App', - component: AppComponent + title: 'App', + component: AppComponent, } as Meta; export const Primary: Story = () => ({ - props: {} + props: {}, }); diff --git a/src/app/core/components/breadcrumbs/breadcrumbs.component.spec.ts b/src/app/core/components/breadcrumbs/breadcrumbs.component.spec.ts index dfd2ced1fb..9e23418c03 100644 --- a/src/app/core/components/breadcrumbs/breadcrumbs.component.spec.ts +++ b/src/app/core/components/breadcrumbs/breadcrumbs.component.spec.ts @@ -9,85 +9,102 @@ import { firstValueFrom } from 'rxjs'; import { BreadcrumbsComponent } from './breadcrumbs.component'; describe('BreadcrumbsComponent', () => { - let component: BreadcrumbsComponent; - let fixture: ComponentFixture; - let store: MockStore; + let component: BreadcrumbsComponent; + let fixture: ComponentFixture; + let store: MockStore; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [BreadcrumbsComponent], - imports: [RouterTestingModule], - providers: [RouterService, provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BreadcrumbsComponent], + imports: [RouterTestingModule], + providers: [RouterService, provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(BreadcrumbsComponent); - component = fixture.componentInstance; - store = TestBed.inject(MockStore); - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(BreadcrumbsComponent); + component = fixture.componentInstance; + store = TestBed.inject(MockStore); + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it.each([ - [[], { state: { root: { firstChild: { data: { title: 'Path1' }, url: [{ path: 'path1' }] } } } } as unknown as RouterReducerState], + it.each([ + [ + [], + { + state: { root: { firstChild: { data: { title: 'Path1' }, url: [{ path: 'path1' }] } } }, + } as unknown as RouterReducerState, + ], - [[{ label: 'Path1', path: '', preserveQueryParams: false }], - { state: { root: { firstChild: { data: { title: 'Path1' }, routeConfig: { path: 'path1' }, url: [] } } } } as unknown as RouterReducerState], + [ + [{ label: 'Path1', path: '', preserveQueryParams: false }], + { + state: { root: { firstChild: { data: { title: 'Path1' }, routeConfig: { path: 'path1' }, url: [] } } }, + } as unknown as RouterReducerState, + ], - [ - [{ label: 'Path1', path: 'path1', preserveQueryParams: false }], - { - state: - { root: { firstChild: { data: { title: 'Path1' }, routeConfig: { path: 'path1' }, url: [{ path: 'path1' }] } } }, - } as unknown as RouterReducerState, - ], + [ + [{ label: 'Path1', path: 'path1', preserveQueryParams: false }], + { + state: { + root: { firstChild: { data: { title: 'Path1' }, routeConfig: { path: 'path1' }, url: [{ path: 'path1' }] } }, + }, + } as unknown as RouterReducerState, + ], - [ - [ - { label: 'Path1', path: 'path1', preserveQueryParams: false }, - { label: 'Path2', path: 'path1/path2', preserveQueryParams: false }, - ], - { - state: { - root: { - firstChild: { - data: { title: 'Path1' }, - routeConfig: { path: 'path1' }, - url: [{ path: 'path1' }], - firstChild: { data: { title: 'Path2' }, routeConfig: { path: 'path2' }, url: [{ path: 'path2' }] }, - }, - }, - }, - } as unknown as RouterReducerState, - ], - [ - [ - { label: 'Path1', path: 'path1', preserveQueryParams: false }, - { label: 'Path2', path: 'path1/path2', preserveQueryParams: true }, - ], - { - navigationId: 'foo', - state: { - root: { - firstChild: { - data: { title: 'Path1' }, - routeConfig: { path: 'path1' }, - url: [{ path: 'path1' }], - firstChild: { data: { title: 'Path2', breadcrumbPreserveQueryParams: true }, routeConfig: { path: 'path2' }, url: [{ path: 'path2' }] }, - }, - }, - }, - } as unknown as RouterReducerState, - ], - ])( - 'should return %o when router state is %o', - async (expected: { label: string; path: string, preserveQueryParams: boolean }[], routeState: RouterReducerState) => { - store.overrideSelector(routerState, routeState); - expect(await firstValueFrom(component.breadcrumbs$)).toEqual(expected); - }, - ); + [ + [ + { label: 'Path1', path: 'path1', preserveQueryParams: false }, + { label: 'Path2', path: 'path1/path2', preserveQueryParams: false }, + ], + { + state: { + root: { + firstChild: { + data: { title: 'Path1' }, + routeConfig: { path: 'path1' }, + url: [{ path: 'path1' }], + firstChild: { data: { title: 'Path2' }, routeConfig: { path: 'path2' }, url: [{ path: 'path2' }] }, + }, + }, + }, + } as unknown as RouterReducerState, + ], + [ + [ + { label: 'Path1', path: 'path1', preserveQueryParams: false }, + { label: 'Path2', path: 'path1/path2', preserveQueryParams: true }, + ], + { + navigationId: 'foo', + state: { + root: { + firstChild: { + data: { title: 'Path1' }, + routeConfig: { path: 'path1' }, + url: [{ path: 'path1' }], + firstChild: { + data: { title: 'Path2', breadcrumbPreserveQueryParams: true }, + routeConfig: { path: 'path2' }, + url: [{ path: 'path2' }], + }, + }, + }, + }, + } as unknown as RouterReducerState, + ], + ])( + 'should return %o when router state is %o', + async ( + expected: { label: string; path: string; preserveQueryParams: boolean }[], + routeState: RouterReducerState + ) => { + store.overrideSelector(routerState, routeState); + expect(await firstValueFrom(component.breadcrumbs$)).toEqual(expected); + } + ); }); diff --git a/src/app/core/components/breadcrumbs/breadcrumbs.component.ts b/src/app/core/components/breadcrumbs/breadcrumbs.component.ts index 67f6d938ba..ff11ec3c95 100644 --- a/src/app/core/components/breadcrumbs/breadcrumbs.component.ts +++ b/src/app/core/components/breadcrumbs/breadcrumbs.component.ts @@ -3,39 +3,39 @@ import { RouterService } from '@services/router/router.service'; import { distinctUntilChanged, map } from 'rxjs'; @Component({ - selector: 'app-breadcrumbs', - templateUrl: './breadcrumbs.component.html', - styleUrls: ['./breadcrumbs.component.scss'], + selector: 'app-breadcrumbs', + templateUrl: './breadcrumbs.component.html', + styleUrls: ['./breadcrumbs.component.scss'], }) export class BreadcrumbsComponent { - constructor(private routerService: RouterService) {} + constructor(private routerService: RouterService) {} - get breadcrumbs$() { - return this.routerService.router$.pipe( - distinctUntilChanged(), - map((router) => { - let currentRoute = router?.state?.root; - const breadcrumbs: Array<{ label: string; path: string; preserveQueryParams: boolean }> = []; + get breadcrumbs$() { + return this.routerService.router$.pipe( + distinctUntilChanged(), + map((router) => { + let currentRoute = router?.state?.root; + const breadcrumbs: Array<{ label: string; path: string; preserveQueryParams: boolean }> = []; - while (currentRoute?.firstChild) { - const { routeConfig, data, url } = currentRoute.firstChild; + while (currentRoute?.firstChild) { + const { routeConfig, data, url } = currentRoute.firstChild; - if (data['title'] && routeConfig?.path && !breadcrumbs.some((b) => b.label === data['title'])) { - breadcrumbs.push({ - label: data['title'], - path: [...breadcrumbs.slice(-1).map((b) => b.path), ...url.map((urlValue) => urlValue.path)].join('/'), - preserveQueryParams: !!data['breadcrumbPreserveQueryParams'], - }); - } + if (data['title'] && routeConfig?.path && !breadcrumbs.some((b) => b.label === data['title'])) { + breadcrumbs.push({ + label: data['title'], + path: [...breadcrumbs.slice(-1).map((b) => b.path), ...url.map((urlValue) => urlValue.path)].join('/'), + preserveQueryParams: !!data['breadcrumbPreserveQueryParams'], + }); + } - currentRoute = currentRoute.firstChild; - } - return breadcrumbs; - }), - ); - } + currentRoute = currentRoute.firstChild; + } + return breadcrumbs; + }) + ); + } - trackByFn(index: number, breadcrumb: { label: string; path: string }) { - return breadcrumb.path || index; - } + trackByFn(index: number, breadcrumb: { label: string; path: string }) { + return breadcrumb.path || index; + } } diff --git a/src/app/core/components/footer/footer.component.spec.ts b/src/app/core/components/footer/footer.component.spec.ts index 36c31ab3d0..6c48f38b17 100644 --- a/src/app/core/components/footer/footer.component.spec.ts +++ b/src/app/core/components/footer/footer.component.spec.ts @@ -3,22 +3,22 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FooterComponent } from './footer.component'; describe('FooterComponent', () => { - let component: FooterComponent; - let fixture: ComponentFixture; + let component: FooterComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [FooterComponent], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [FooterComponent], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(FooterComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(FooterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/core/components/footer/footer.component.ts b/src/app/core/components/footer/footer.component.ts index 669de37488..a07c1f15dd 100644 --- a/src/app/core/components/footer/footer.component.ts +++ b/src/app/core/components/footer/footer.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; @Component({ - selector: 'app-footer', - templateUrl: './footer.component.html', + selector: 'app-footer', + templateUrl: './footer.component.html', }) export class FooterComponent {} diff --git a/src/app/core/components/footer/footer.stories.ts b/src/app/core/components/footer/footer.stories.ts index 4bc3ed48ad..0361eabdc0 100644 --- a/src/app/core/components/footer/footer.stories.ts +++ b/src/app/core/components/footer/footer.stories.ts @@ -3,10 +3,10 @@ import { Meta, Story } from '@storybook/angular'; import { FooterComponent } from './footer.component'; export default { - title: 'Footer', - component: FooterComponent + title: 'Footer', + component: FooterComponent, } as Meta; export const Primary: Story = () => ({ - props: {} + props: {}, }); diff --git a/src/app/core/components/global-error/global-error.component.spec.ts b/src/app/core/components/global-error/global-error.component.spec.ts index d4c0d183fc..fb2ebddc04 100644 --- a/src/app/core/components/global-error/global-error.component.spec.ts +++ b/src/app/core/components/global-error/global-error.component.spec.ts @@ -7,40 +7,40 @@ import { GlobalErrorComponent } from './global-error.component'; import { GlobalErrorService } from './global-error.service'; @Component({ - selector: 'app-mock-component', - template: '\n', - styles: [], + selector: 'app-mock-component', + template: '\n', + styles: [], }) class MockComponent {} describe('GlobalErrorComponent', () => { - let component: GlobalErrorComponent; - let fixture: ComponentFixture; + let component: GlobalErrorComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [GlobalErrorComponent, MockComponent], - imports: [], - providers: [GlobalErrorService, provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [GlobalErrorComponent, MockComponent], + imports: [], + providers: [GlobalErrorService, provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(MockComponent); - component = fixture.debugElement.query(By.directive(GlobalErrorComponent)).componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(MockComponent); + component = fixture.debugElement.query(By.directive(GlobalErrorComponent)).componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - describe('goto', () => { - it('should focus element', () => { - const input: HTMLInputElement = fixture.debugElement.query(By.css('#test-input')).nativeElement; - component.goto({ error: 'navigate', anchorLink: 'test-input' }); + describe('goto', () => { + it('should focus element', () => { + const input: HTMLInputElement = fixture.debugElement.query(By.css('#test-input')).nativeElement; + component.goto({ error: 'navigate', anchorLink: 'test-input' }); - expect(document.activeElement).toBe(input); - }); - }); + expect(document.activeElement).toBe(input); + }); + }); }); diff --git a/src/app/core/components/global-error/global-error.component.ts b/src/app/core/components/global-error/global-error.component.ts index d8dc2e79f6..be51a141ae 100644 --- a/src/app/core/components/global-error/global-error.component.ts +++ b/src/app/core/components/global-error/global-error.component.ts @@ -3,17 +3,18 @@ import { GlobalError } from './global-error.interface'; import { GlobalErrorService } from './global-error.service'; @Component({ - selector: 'app-global-error', - templateUrl: './global-error.component.html', + selector: 'app-global-error', + templateUrl: './global-error.component.html', }) export class GlobalErrorComponent { - constructor(public globalErrorService: GlobalErrorService) {} + constructor(public globalErrorService: GlobalErrorService) {} - goto(error: GlobalError) { - if (error.anchorLink) { - let focusCount = 0; + goto(error: GlobalError) { + if (error.anchorLink) { + let focusCount = 0; - document.querySelectorAll(` + document + .querySelectorAll(` #${error.anchorLink}, #${error.anchorLink} a[href]:not([tabindex='-1']), #${error.anchorLink} area[href]:not([tabindex='-1']), @@ -25,12 +26,12 @@ export class GlobalErrorComponent { #${error.anchorLink} [tabindex]:not([tabindex='-1']), #${error.anchorLink} [contentEditable=true]:not([tabindex='-1']) `) - .forEach((el) => { - if (el instanceof HTMLElement && focusCount < 2) { - focusCount++; - el.focus({ preventScroll: false }); - } - }); - } - } + .forEach((el) => { + if (el instanceof HTMLElement && focusCount < 2) { + focusCount++; + el.focus({ preventScroll: false }); + } + }); + } + } } diff --git a/src/app/core/components/global-error/global-error.interface.ts b/src/app/core/components/global-error/global-error.interface.ts index 21eb1e69c9..2d754bd2cf 100644 --- a/src/app/core/components/global-error/global-error.interface.ts +++ b/src/app/core/components/global-error/global-error.interface.ts @@ -1,4 +1,4 @@ export interface GlobalError { - error: string; - anchorLink?: string; + error: string; + anchorLink?: string; } diff --git a/src/app/core/components/global-error/global-error.service.spec.ts b/src/app/core/components/global-error/global-error.service.spec.ts index a3927d2f4a..8f0250c737 100644 --- a/src/app/core/components/global-error/global-error.service.spec.ts +++ b/src/app/core/components/global-error/global-error.service.spec.ts @@ -1,59 +1,57 @@ import { TestBed } from '@angular/core/testing'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { State, initialAppState } from '@store/.'; -import { - addError, clearError, patchErrors, setErrors, -} from '@store/global-error/actions/global-error.actions'; +import { addError, clearError, patchErrors, setErrors } from '@store/global-error/actions/global-error.actions'; import { GlobalError } from './global-error.interface'; import { GlobalErrorService } from './global-error.service'; describe('GlobalErrorService', () => { - let service: GlobalErrorService; - let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ providers: [provideMockStore({ initialState: initialAppState })] }); - service = TestBed.inject(GlobalErrorService); - store = TestBed.inject(MockStore); - }); + let service: GlobalErrorService; + let store: MockStore; + beforeEach(() => { + TestBed.configureTestingModule({ providers: [provideMockStore({ initialState: initialAppState })] }); + service = TestBed.inject(GlobalErrorService); + store = TestBed.inject(MockStore); + }); - it('should be created', () => { - expect(service).toBeTruthy(); - }); + it('should be created', () => { + expect(service).toBeTruthy(); + }); - it('should dispatch action addError', () => { - const expectedError: GlobalError = { error: 'erro 2', anchorLink: '' }; - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.addError(expectedError); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(addError(expectedError)); - }); + it('should dispatch action addError', () => { + const expectedError: GlobalError = { error: 'erro 2', anchorLink: '' }; + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.addError(expectedError); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith(addError(expectedError)); + }); - it('should dispatch action patchErrors', () => { - const expectedErrors: GlobalError[] = [{ error: 'erro 2', anchorLink: '' }]; - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.patchErrors(expectedErrors); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(patchErrors({ errors: expectedErrors })); - }); + it('should dispatch action patchErrors', () => { + const expectedErrors: GlobalError[] = [{ error: 'erro 2', anchorLink: '' }]; + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.patchErrors(expectedErrors); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith(patchErrors({ errors: expectedErrors })); + }); - it('should dispatch action clearError', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.clearErrors(); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(clearError()); - }); + it('should dispatch action clearError', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.clearErrors(); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith(clearError()); + }); - it('should dispatch action setErrors', () => { - const expectedErrors: GlobalError[] = [{ error: 'erro 2', anchorLink: '' }]; - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.setErrors(expectedErrors); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(setErrors({ errors: expectedErrors })); - }); + it('should dispatch action setErrors', () => { + const expectedErrors: GlobalError[] = [{ error: 'erro 2', anchorLink: '' }]; + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.setErrors(expectedErrors); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith(setErrors({ errors: expectedErrors })); + }); - it('should attempt to focus all focusable controls', () => { - const spy = jest.spyOn(document, 'querySelectorAll'); - service.focusAllControls(); - expect(spy).toHaveBeenCalled(); - }); + it('should attempt to focus all focusable controls', () => { + const spy = jest.spyOn(document, 'querySelectorAll'); + service.focusAllControls(); + expect(spy).toHaveBeenCalled(); + }); }); diff --git a/src/app/core/components/global-error/global-error.service.ts b/src/app/core/components/global-error/global-error.service.ts index a0014d152a..a89c349632 100644 --- a/src/app/core/components/global-error/global-error.service.ts +++ b/src/app/core/components/global-error/global-error.service.ts @@ -1,45 +1,44 @@ import { Injectable } from '@angular/core'; -import { select, Store } from '@ngrx/store'; +import { Store, select } from '@ngrx/store'; import { State } from '@store/.'; -import { - addError, clearError, patchErrors, setErrors, -} from '@store/global-error/actions/global-error.actions'; +import { addError, clearError, patchErrors, setErrors } from '@store/global-error/actions/global-error.actions'; import { globalErrorState } from '@store/global-error/reducers/global-error-service.reducer'; import { Observable } from 'rxjs'; import { GlobalError } from './global-error.interface'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class GlobalErrorService { - private errors: Observable; + private errors: Observable; - constructor(private store: Store) { - this.errors = this.store.pipe(select(globalErrorState)); - } + constructor(private store: Store) { + this.errors = this.store.pipe(select(globalErrorState)); + } - get errors$() { - return this.errors; - } + get errors$() { + return this.errors; + } - addError(error: GlobalError) { - this.store.dispatch(addError(error)); - } + addError(error: GlobalError) { + this.store.dispatch(addError(error)); + } - setErrors(errors: GlobalError[]) { - this.store.dispatch(setErrors({ errors })); - } + setErrors(errors: GlobalError[]) { + this.store.dispatch(setErrors({ errors })); + } - patchErrors(errors: GlobalError[]) { - this.store.dispatch(patchErrors({ errors })); - } + patchErrors(errors: GlobalError[]) { + this.store.dispatch(patchErrors({ errors })); + } - clearErrors(): void { - this.store.dispatch(clearError()); - } + clearErrors(): void { + this.store.dispatch(clearError()); + } - focusAllControls() { - document.querySelectorAll(` + focusAllControls() { + document + .querySelectorAll(` a[href]:not([tabindex='-1']), area[href]:not([tabindex='-1']), input:not([disabled]):not([tabindex='-1']), @@ -50,11 +49,11 @@ export class GlobalErrorService { [tabindex]:not([tabindex='-1']), [contentEditable=true]:not([tabindex='-1']) `) - .forEach((element) => { - if (element instanceof HTMLElement) { - element.focus(); - element.blur(); - } - }); - } + .forEach((element) => { + if (element instanceof HTMLElement) { + element.focus(); + element.blur(); + } + }); + } } diff --git a/src/app/core/components/global-error/global-error.stories.ts b/src/app/core/components/global-error/global-error.stories.ts index 10a4768ef2..6430a0a5e1 100644 --- a/src/app/core/components/global-error/global-error.stories.ts +++ b/src/app/core/components/global-error/global-error.stories.ts @@ -2,14 +2,14 @@ import { Meta, Story } from '@storybook/angular'; import { GlobalErrorComponent } from './global-error.component'; export default { - title: 'Global Error Component', - component: GlobalErrorComponent + title: 'Global Error Component', + component: GlobalErrorComponent, } as Meta; export const NoErrors: Story = () => ({ - props: {} + props: {}, }); export const Error: Story = () => ({ - props: { errorMessage$: 'error' } + props: { errorMessage$: 'error' }, }); diff --git a/src/app/core/components/global-warning/global-warning.component.spec.ts b/src/app/core/components/global-warning/global-warning.component.spec.ts index f26c795b53..65bc2ae2d8 100644 --- a/src/app/core/components/global-warning/global-warning.component.spec.ts +++ b/src/app/core/components/global-warning/global-warning.component.spec.ts @@ -7,46 +7,46 @@ import { GlobalWarningComponent } from './global-warning.component'; import { GlobalWarningService } from './global-warning.service'; @Component({ - selector: 'app-mock-component', - template: '\n', - styles: [], + selector: 'app-mock-component', + template: '\n', + styles: [], }) class MockComponent {} describe('GlobalWarningComponent', () => { - let component: GlobalWarningComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [GlobalWarningComponent, MockComponent], - imports: [], - providers: [GlobalWarningService, provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(MockComponent); - component = fixture.debugElement.query(By.directive(GlobalWarningComponent)).componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('goto', () => { - it('should focus element', () => { - const input: HTMLInputElement = fixture.debugElement.query(By.css('#test-input')).nativeElement; - component.goto({ warning: 'navigate', anchorLink: 'test-input' }); - - expect(document.activeElement).toBe(input); - }); - - it('should do nothing if no anchor link is provided', () => { - const spy = jest.spyOn(document, 'getElementById'); - component.goto({ warning: 'navigate', anchorLink: undefined }); - expect(spy).not.toHaveBeenCalled(); - }); - }); + let component: GlobalWarningComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [GlobalWarningComponent, MockComponent], + imports: [], + providers: [GlobalWarningService, provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(MockComponent); + component = fixture.debugElement.query(By.directive(GlobalWarningComponent)).componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('goto', () => { + it('should focus element', () => { + const input: HTMLInputElement = fixture.debugElement.query(By.css('#test-input')).nativeElement; + component.goto({ warning: 'navigate', anchorLink: 'test-input' }); + + expect(document.activeElement).toBe(input); + }); + + it('should do nothing if no anchor link is provided', () => { + const spy = jest.spyOn(document, 'getElementById'); + component.goto({ warning: 'navigate', anchorLink: undefined }); + expect(spy).not.toHaveBeenCalled(); + }); + }); }); diff --git a/src/app/core/components/global-warning/global-warning.component.ts b/src/app/core/components/global-warning/global-warning.component.ts index 0770edc945..d34809d08e 100644 --- a/src/app/core/components/global-warning/global-warning.component.ts +++ b/src/app/core/components/global-warning/global-warning.component.ts @@ -3,16 +3,16 @@ import { GlobalWarning } from './global-warning.interface'; import { GlobalWarningService } from './global-warning.service'; @Component({ - selector: 'app-global-warning', - templateUrl: './global-warning.component.html', + selector: 'app-global-warning', + templateUrl: './global-warning.component.html', }) export class GlobalWarningComponent { - constructor(public globalWarningService: GlobalWarningService) {} + constructor(public globalWarningService: GlobalWarningService) {} - goto(warning: GlobalWarning) { - if (warning.anchorLink) { - const el = document.getElementById(warning.anchorLink); - el?.focus({ preventScroll: false }); - } - } + goto(warning: GlobalWarning) { + if (warning.anchorLink) { + const el = document.getElementById(warning.anchorLink); + el?.focus({ preventScroll: false }); + } + } } diff --git a/src/app/core/components/global-warning/global-warning.interface.ts b/src/app/core/components/global-warning/global-warning.interface.ts index 9da5102102..9ae047e5d7 100644 --- a/src/app/core/components/global-warning/global-warning.interface.ts +++ b/src/app/core/components/global-warning/global-warning.interface.ts @@ -1,4 +1,4 @@ export interface GlobalWarning { - warning: string; - anchorLink?: string; + warning: string; + anchorLink?: string; } diff --git a/src/app/core/components/global-warning/global-warning.service.spec.ts b/src/app/core/components/global-warning/global-warning.service.spec.ts index 8bc261ee31..1dc9ed2f04 100644 --- a/src/app/core/components/global-warning/global-warning.service.spec.ts +++ b/src/app/core/components/global-warning/global-warning.service.spec.ts @@ -1,35 +1,35 @@ import { TestBed } from '@angular/core/testing'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; -import { initialAppState, State } from '@store/.'; -import { setWarnings, clearWarning } from '@store/global-warning/actions/global-warning.actions'; +import { State, initialAppState } from '@store/.'; +import { clearWarning, setWarnings } from '@store/global-warning/actions/global-warning.actions'; import { GlobalWarning } from './global-warning.interface'; import { GlobalWarningService } from './global-warning.service'; describe('GlobalWarningService', () => { - let service: GlobalWarningService; - let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ providers: [provideMockStore({ initialState: initialAppState })] }); - service = TestBed.inject(GlobalWarningService); - store = TestBed.inject(MockStore); - }); + let service: GlobalWarningService; + let store: MockStore; + beforeEach(() => { + TestBed.configureTestingModule({ providers: [provideMockStore({ initialState: initialAppState })] }); + service = TestBed.inject(GlobalWarningService); + store = TestBed.inject(MockStore); + }); - it('should be created', () => { - expect(service).toBeTruthy(); - }); + it('should be created', () => { + expect(service).toBeTruthy(); + }); - it('should dispatch action setWarnings', () => { - const expectedWarning: GlobalWarning = { warning: 'warn 2', anchorLink: '' }; - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.setWarnings([expectedWarning]); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(setWarnings({ warnings: [expectedWarning] })); - }); + it('should dispatch action setWarnings', () => { + const expectedWarning: GlobalWarning = { warning: 'warn 2', anchorLink: '' }; + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.setWarnings([expectedWarning]); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith(setWarnings({ warnings: [expectedWarning] })); + }); - it('should dispatch action clearError', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.clearWarnings(); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(clearWarning()); - }); + it('should dispatch action clearError', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.clearWarnings(); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith(clearWarning()); + }); }); diff --git a/src/app/core/components/global-warning/global-warning.service.ts b/src/app/core/components/global-warning/global-warning.service.ts index f0a7b61ba4..76d3445767 100644 --- a/src/app/core/components/global-warning/global-warning.service.ts +++ b/src/app/core/components/global-warning/global-warning.service.ts @@ -1,30 +1,30 @@ import { Injectable } from '@angular/core'; -import { select, Store } from '@ngrx/store'; +import { Store, select } from '@ngrx/store'; import { State } from '@store/.'; import { clearWarning, setWarnings } from '@store/global-warning/actions/global-warning.actions'; -import { Observable } from 'rxjs'; import { globalWarningState } from '@store/global-warning/reducers/global-warning-service.reducers'; +import { Observable } from 'rxjs'; import { GlobalWarning } from './global-warning.interface'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class GlobalWarningService { - private warnings: Observable; + private warnings: Observable; - constructor(private store: Store) { - this.warnings = this.store.pipe(select(globalWarningState)); - } + constructor(private store: Store) { + this.warnings = this.store.pipe(select(globalWarningState)); + } - get warnings$() { - return this.warnings; - } + get warnings$() { + return this.warnings; + } - setWarnings(warnings: GlobalWarning[]) { - this.store.dispatch(setWarnings({ warnings })); - } + setWarnings(warnings: GlobalWarning[]) { + this.store.dispatch(setWarnings({ warnings })); + } - clearWarnings(): void { - this.store.dispatch(clearWarning()); - } + clearWarnings(): void { + this.store.dispatch(clearWarning()); + } } diff --git a/src/app/core/components/header/header.component.spec.ts b/src/app/core/components/header/header.component.spec.ts index bc67bbde09..36543cc334 100644 --- a/src/app/core/components/header/header.component.spec.ts +++ b/src/app/core/components/header/header.component.spec.ts @@ -4,42 +4,42 @@ import { By } from '@angular/platform-browser'; import { HeaderComponent } from './header.component'; describe('HeaderComponent', () => { - let component: HeaderComponent; - let fixture: ComponentFixture; - let userNameText: HTMLElement; - let logOutButton: DebugElement; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [HeaderComponent], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(HeaderComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - - userNameText = fixture.debugElement.nativeElement.querySelector('#username'); - logOutButton = fixture.debugElement.query(By.css('#sign-out')); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('Change username updates page', () => { - component.username = 'Test'; - fixture.detectChanges(); - expect(userNameText.innerHTML).toBe('Test'); - }); - - it('Clicking logout fires off event', (done) => { - component.logOutEvent.subscribe(() => { - done(); - expect(done).toHaveBeenCalled(); - }); - - logOutButton.triggerEventHandler('click', null); - }); + let component: HeaderComponent; + let fixture: ComponentFixture; + let userNameText: HTMLElement; + let logOutButton: DebugElement; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [HeaderComponent], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(HeaderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + + userNameText = fixture.debugElement.nativeElement.querySelector('#username'); + logOutButton = fixture.debugElement.query(By.css('#sign-out')); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('Change username updates page', () => { + component.username = 'Test'; + fixture.detectChanges(); + expect(userNameText.innerHTML).toBe('Test'); + }); + + it('Clicking logout fires off event', (done) => { + component.logOutEvent.subscribe(() => { + done(); + expect(done).toHaveBeenCalled(); + }); + + logOutButton.triggerEventHandler('click', null); + }); }); diff --git a/src/app/core/components/header/header.component.ts b/src/app/core/components/header/header.component.ts index 2abccae52d..a918db42a6 100644 --- a/src/app/core/components/header/header.component.ts +++ b/src/app/core/components/header/header.component.ts @@ -1,17 +1,15 @@ -import { - Component, EventEmitter, Input, Output, -} from '@angular/core'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; @Component({ - selector: 'app-header', - templateUrl: './header.component.html', - styleUrls: ['./header.component.scss'], + selector: 'app-header', + templateUrl: './header.component.html', + styleUrls: ['./header.component.scss'], }) export class HeaderComponent { - @Output() logOutEvent = new EventEmitter(); - @Input() username: string | null = ''; + @Output() logOutEvent = new EventEmitter(); + @Input() username: string | null = ''; - logout() { - this.logOutEvent.emit(); - } + logout() { + this.logOutEvent.emit(); + } } diff --git a/src/app/core/components/header/header.stories.ts b/src/app/core/components/header/header.stories.ts index 65c88b90ad..41e063e96c 100644 --- a/src/app/core/components/header/header.stories.ts +++ b/src/app/core/components/header/header.stories.ts @@ -3,17 +3,17 @@ import { Meta, Story } from '@storybook/angular'; import { HeaderComponent } from './header.component'; export default { - title: 'Header', - component: HeaderComponent, - argTypes: { logOut: { action: 'clicked' } } + title: 'Header', + component: HeaderComponent, + argTypes: { logOut: { action: 'clicked' } }, } as Meta; const Template: Story = () => ({ - props: {} + props: {}, }); export const Primary: Story = () => ({ - props: { - username: 'username' - } + props: { + username: 'username', + }, }); diff --git a/src/app/core/components/page-not-found/page-not-found.component.spec.ts b/src/app/core/components/page-not-found/page-not-found.component.spec.ts index 70b685ca88..c1d2ff83e5 100644 --- a/src/app/core/components/page-not-found/page-not-found.component.spec.ts +++ b/src/app/core/components/page-not-found/page-not-found.component.spec.ts @@ -2,22 +2,22 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { PageNotFoundComponent } from './page-not-found.component'; describe('PageNotFoundComponent', () => { - let component: PageNotFoundComponent; - let fixture: ComponentFixture; + let component: PageNotFoundComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [PageNotFoundComponent], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [PageNotFoundComponent], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(PageNotFoundComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(PageNotFoundComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/core/components/page-not-found/page-not-found.component.ts b/src/app/core/components/page-not-found/page-not-found.component.ts index c2b9a0c43f..84b644b2e8 100644 --- a/src/app/core/components/page-not-found/page-not-found.component.ts +++ b/src/app/core/components/page-not-found/page-not-found.component.ts @@ -1,8 +1,8 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; @Component({ - selector: 'app-page-not-found', - templateUrl: './page-not-found.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-page-not-found', + templateUrl: './page-not-found.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class PageNotFoundComponent {} diff --git a/src/app/core/components/phase-banner/phase-banner.component.spec.ts b/src/app/core/components/phase-banner/phase-banner.component.spec.ts index 9589c37477..779d4b39f0 100644 --- a/src/app/core/components/phase-banner/phase-banner.component.spec.ts +++ b/src/app/core/components/phase-banner/phase-banner.component.spec.ts @@ -3,22 +3,22 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { PhaseBannerComponent } from './phase-banner.component'; describe('PhaseBannerComponent', () => { - let component: PhaseBannerComponent; - let fixture: ComponentFixture; + let component: PhaseBannerComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [PhaseBannerComponent], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [PhaseBannerComponent], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(PhaseBannerComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(PhaseBannerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/core/components/phase-banner/phase-banner.component.ts b/src/app/core/components/phase-banner/phase-banner.component.ts index 794aa3501d..4d1ed4b6de 100644 --- a/src/app/core/components/phase-banner/phase-banner.component.ts +++ b/src/app/core/components/phase-banner/phase-banner.component.ts @@ -2,13 +2,13 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { environment } from '../../../../environments/environment'; @Component({ - selector: 'app-phase-banner', - templateUrl: './phase-banner.component.html', - styleUrls: ['./phase-banner.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-phase-banner', + templateUrl: './phase-banner.component.html', + styleUrls: ['./phase-banner.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class PhaseBannerComponent { - get feedbackUri(): string { - return environment.FEEDBACK_URI; - } + get feedbackUri(): string { + return environment.FEEDBACK_URI; + } } diff --git a/src/app/core/components/server-error/server-error.component.spec.ts b/src/app/core/components/server-error/server-error.component.spec.ts index a2a2b5c421..10a1576600 100644 --- a/src/app/core/components/server-error/server-error.component.spec.ts +++ b/src/app/core/components/server-error/server-error.component.spec.ts @@ -2,22 +2,22 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ServerErrorComponent } from './server-error.component'; describe('ServerErrorComponent', () => { - let component: ServerErrorComponent; - let fixture: ComponentFixture; + let component: ServerErrorComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ServerErrorComponent], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ServerErrorComponent], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(ServerErrorComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(ServerErrorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/core/components/server-error/server-error.component.ts b/src/app/core/components/server-error/server-error.component.ts index 858e30837f..ed6c5fa435 100644 --- a/src/app/core/components/server-error/server-error.component.ts +++ b/src/app/core/components/server-error/server-error.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; @Component({ - selector: 'app-server-error', - templateUrl: './server-error.component.html', + selector: 'app-server-error', + templateUrl: './server-error.component.html', }) export class ServerErrorComponent {} diff --git a/src/app/core/components/spinner/spinner.component.spec.ts b/src/app/core/components/spinner/spinner.component.spec.ts index 42bf126ea1..e006a08470 100644 --- a/src/app/core/components/spinner/spinner.component.spec.ts +++ b/src/app/core/components/spinner/spinner.component.spec.ts @@ -2,37 +2,37 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { SpinnerComponent } from './spinner.component'; describe('SpinnerComponent', () => { - let component: SpinnerComponent; - let fixture: ComponentFixture; - let spinner: HTMLElement; + let component: SpinnerComponent; + let fixture: ComponentFixture; + let spinner: HTMLElement; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [SpinnerComponent], - }).compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [SpinnerComponent], + }).compileComponents(); - fixture = TestBed.createComponent(SpinnerComponent); - component = fixture.componentInstance; - }); + fixture = TestBed.createComponent(SpinnerComponent); + component = fixture.componentInstance; + }); - it('should create', () => { - expect(component).toBeTruthy(); - // Default should not show - spinner = fixture.debugElement.nativeElement.querySelector('.spinner'); - expect(spinner).toBeNull(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + // Default should not show + spinner = fixture.debugElement.nativeElement.querySelector('.spinner'); + expect(spinner).toBeNull(); + }); - it('should show', () => { - component.loading = true; - fixture.detectChanges(); - spinner = fixture.debugElement.nativeElement.querySelector('.spinner'); - expect(spinner).toBeTruthy(); - }); + it('should show', () => { + component.loading = true; + fixture.detectChanges(); + spinner = fixture.debugElement.nativeElement.querySelector('.spinner'); + expect(spinner).toBeTruthy(); + }); - it('should NOT show', () => { - component.loading = false; - fixture.detectChanges(); - spinner = fixture.debugElement.nativeElement.querySelector('.spinner'); - expect(spinner).toBeNull(); - }); + it('should NOT show', () => { + component.loading = false; + fixture.detectChanges(); + spinner = fixture.debugElement.nativeElement.querySelector('.spinner'); + expect(spinner).toBeNull(); + }); }); diff --git a/src/app/core/components/spinner/spinner.component.ts b/src/app/core/components/spinner/spinner.component.ts index 2b8ad6e335..aab8faeb28 100644 --- a/src/app/core/components/spinner/spinner.component.ts +++ b/src/app/core/components/spinner/spinner.component.ts @@ -1,11 +1,11 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; @Component({ - selector: 'app-spinner', - templateUrl: './spinner.component.html', - styleUrls: ['./spinner.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-spinner', + templateUrl: './spinner.component.html', + styleUrls: ['./spinner.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class SpinnerComponent { - @Input() loading: boolean | null = false; + @Input() loading: boolean | null = false; } diff --git a/src/app/core/core.module.ts b/src/app/core/core.module.ts index e33d2c0891..7df1a16490 100644 --- a/src/app/core/core.module.ts +++ b/src/app/core/core.module.ts @@ -1,37 +1,37 @@ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; +import { BreadcrumbsComponent } from './components/breadcrumbs/breadcrumbs.component'; +import { FooterComponent } from './components/footer/footer.component'; import { GlobalErrorComponent } from './components/global-error/global-error.component'; import { GlobalWarningComponent } from './components/global-warning/global-warning.component'; -import { SpinnerComponent } from './components/spinner/spinner.component'; -import { FooterComponent } from './components/footer/footer.component'; import { HeaderComponent } from './components/header/header.component'; -import { BreadcrumbsComponent } from './components/breadcrumbs/breadcrumbs.component'; import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component'; -import { ServerErrorComponent } from './components/server-error/server-error.component'; import { PhaseBannerComponent } from './components/phase-banner/phase-banner.component'; +import { ServerErrorComponent } from './components/server-error/server-error.component'; +import { SpinnerComponent } from './components/spinner/spinner.component'; @NgModule({ - declarations: [ - FooterComponent, - HeaderComponent, - GlobalErrorComponent, - GlobalWarningComponent, - SpinnerComponent, - BreadcrumbsComponent, - PageNotFoundComponent, - ServerErrorComponent, - PhaseBannerComponent, - ], - imports: [CommonModule, RouterModule], - exports: [ - FooterComponent, - HeaderComponent, - GlobalErrorComponent, - GlobalWarningComponent, - SpinnerComponent, - BreadcrumbsComponent, - PhaseBannerComponent, - ], + declarations: [ + FooterComponent, + HeaderComponent, + GlobalErrorComponent, + GlobalWarningComponent, + SpinnerComponent, + BreadcrumbsComponent, + PageNotFoundComponent, + ServerErrorComponent, + PhaseBannerComponent, + ], + imports: [CommonModule, RouterModule], + exports: [ + FooterComponent, + HeaderComponent, + GlobalErrorComponent, + GlobalWarningComponent, + SpinnerComponent, + BreadcrumbsComponent, + PhaseBannerComponent, + ], }) export class CoreModule {} diff --git a/src/app/directives/app-role-required.directive.spec.ts b/src/app/directives/app-role-required.directive.spec.ts index 141702b734..a588898f5b 100644 --- a/src/app/directives/app-role-required.directive.spec.ts +++ b/src/app/directives/app-role-required.directive.spec.ts @@ -9,7 +9,7 @@ import { of } from 'rxjs'; import { RoleRequiredDirective } from './app-role-required.directive'; @Component({ - template: ` + template: `

This can display

@@ -25,64 +25,76 @@ import { RoleRequiredDirective } from './app-role-required.directive'; `, }) class TestComponent { - public get Roles() { - return Roles; - } + public get Roles() { + return Roles; + } } describe('RoleRequiredDirective', () => { - const userRoles: string[] = ['TechRecord.View']; - let fixture: ComponentFixture; + const userRoles: string[] = ['TechRecord.View']; + let fixture: ComponentFixture; - beforeEach(() => { - fixture = TestBed.configureTestingModule({ - declarations: [RoleRequiredDirective, TestComponent], - providers: [provideMockStore({ initialState: initialAppState }), { provide: UserService, useValue: { roles$: of(userRoles) } }], - }).createComponent(TestComponent); + beforeEach(() => { + fixture = TestBed.configureTestingModule({ + declarations: [RoleRequiredDirective, TestComponent], + providers: [ + provideMockStore({ initialState: initialAppState }), + { provide: UserService, useValue: { roles$: of(userRoles) } }, + ], + }).createComponent(TestComponent); - fixture.detectChanges(); // initial binding - }); + fixture.detectChanges(); // initial binding + }); - it('should display the element', () => { - const seenBox = fixture.debugElement.queryAll(By.css('#displayBox')); - expect(seenBox).toHaveLength(1); - }); + it('should display the element', () => { + const seenBox = fixture.debugElement.queryAll(By.css('#displayBox')); + expect(seenBox).toHaveLength(1); + }); - it('should hide the element', () => { - const hiddenBox = fixture.debugElement.queryAll(By.css('#hiddenBox')); - expect(hiddenBox).toHaveLength(0); - }); + it('should hide the element', () => { + const hiddenBox = fixture.debugElement.queryAll(By.css('#hiddenBox')); + expect(hiddenBox).toHaveLength(0); + }); - it('should hide the element if the role needed is invalid (i.e. not from the Roles enum)', () => { - const errorBox = fixture.debugElement.queryAll(By.css('#errorBox')); - expect(errorBox).toHaveLength(0); - }); + it('should hide the element if the role needed is invalid (i.e. not from the Roles enum)', () => { + const errorBox = fixture.debugElement.queryAll(By.css('#errorBox')); + expect(errorBox).toHaveLength(0); + }); }); describe('RoleRequiredDirective with multiple optional roles', () => { - it.each([[['TestResult.View']], [['TechRecord.Amend']]])('should show the element when either role is present', (user) => { - const fixture: ComponentFixture = TestBed.configureTestingModule({ - declarations: [RoleRequiredDirective, TestComponent], - providers: [provideMockStore({ initialState: initialAppState }), { provide: UserService, useValue: { roles$: of(user) } }], - }).createComponent(TestComponent); + it.each([[['TestResult.View']], [['TechRecord.Amend']]])( + 'should show the element when either role is present', + (user) => { + const fixture: ComponentFixture = TestBed.configureTestingModule({ + declarations: [RoleRequiredDirective, TestComponent], + providers: [ + provideMockStore({ initialState: initialAppState }), + { provide: UserService, useValue: { roles$: of(user) } }, + ], + }).createComponent(TestComponent); - fixture.detectChanges(); // initial binding + fixture.detectChanges(); // initial binding - const seenBox = fixture.debugElement.queryAll(By.css('#displayEitherRoleBox')); - expect(seenBox).toHaveLength(1); - }); + const seenBox = fixture.debugElement.queryAll(By.css('#displayEitherRoleBox')); + expect(seenBox).toHaveLength(1); + } + ); }); describe('RoleRequiredDirective without roles', () => { - it('should hide the element when no roles are available', () => { - const fixture: ComponentFixture = TestBed.configureTestingModule({ - declarations: [RoleRequiredDirective, TestComponent], - providers: [provideMockStore({ initialState: initialAppState }), { provide: UserService, useValue: { roles$: of(null) } }], - }).createComponent(TestComponent); + it('should hide the element when no roles are available', () => { + const fixture: ComponentFixture = TestBed.configureTestingModule({ + declarations: [RoleRequiredDirective, TestComponent], + providers: [ + provideMockStore({ initialState: initialAppState }), + { provide: UserService, useValue: { roles$: of(null) } }, + ], + }).createComponent(TestComponent); - fixture.detectChanges(); // initial binding + fixture.detectChanges(); // initial binding - const seenBox = fixture.debugElement.queryAll(By.css('#errorBox')); - expect(seenBox).toHaveLength(0); - }); + const seenBox = fixture.debugElement.queryAll(By.css('#errorBox')); + expect(seenBox).toHaveLength(0); + }); }); diff --git a/src/app/directives/app-role-required.directive.ts b/src/app/directives/app-role-required.directive.ts index 6635e00a94..4af54d36b4 100644 --- a/src/app/directives/app-role-required.directive.ts +++ b/src/app/directives/app-role-required.directive.ts @@ -1,33 +1,34 @@ -import { - Directive, - Input, - OnInit, - TemplateRef, ViewContainerRef, -} from '@angular/core'; +import { Directive, Input, OnInit, TemplateRef, ViewContainerRef } from '@angular/core'; import { Roles } from '@models/roles.enum'; import { UserService } from '@services/user-service/user-service'; import { take } from 'rxjs'; @Directive({ selector: '[appRoleRequired]' }) export class RoleRequiredDirective implements OnInit { - constructor(private templateRef: TemplateRef, private userService: UserService, private viewContainer: ViewContainerRef) {} + constructor( + private templateRef: TemplateRef, + private userService: UserService, + private viewContainer: ViewContainerRef + ) {} - userRolesRequired: string[] | undefined; + userRolesRequired: string[] | undefined; - @Input() - set appRoleRequired(roles: Roles | Roles[]) { - this.userRolesRequired = Array.isArray(roles) ? [...new Set(roles.flatMap((role) => role.split(',')))] : roles?.split(','); - } + @Input() + set appRoleRequired(roles: Roles | Roles[]) { + this.userRolesRequired = Array.isArray(roles) + ? [...new Set(roles.flatMap((role) => role.split(',')))] + : roles?.split(','); + } - ngOnInit() { - this.userService.roles$.pipe(take(1)).subscribe((storedRoles) => { - const hasAccess = this.userRolesRequired?.some((role) => storedRoles?.includes(role)); + ngOnInit() { + this.userService.roles$.pipe(take(1)).subscribe((storedRoles) => { + const hasAccess = this.userRolesRequired?.some((role) => storedRoles?.includes(role)); - if (hasAccess) { - this.viewContainer.createEmbeddedView(this.templateRef); - } else { - this.viewContainer.clear(); - } - }); - } + if (hasAccess) { + this.viewContainer.createEmbeddedView(this.templateRef); + } else { + this.viewContainer.clear(); + } + }); + } } diff --git a/src/app/directives/feature-toggle.directive.spec.ts b/src/app/directives/feature-toggle.directive.spec.ts index 6125da2394..a740497a80 100644 --- a/src/app/directives/feature-toggle.directive.spec.ts +++ b/src/app/directives/feature-toggle.directive.spec.ts @@ -6,7 +6,7 @@ import { FeatureToggleService } from '@services/feature-toggle-service/feature-t import { FeatureToggleDirective } from './feature-toggle.directive'; @Component({ - template: ` + template: `

This does display

@@ -24,38 +24,38 @@ import { FeatureToggleDirective } from './feature-toggle.directive'; class TestComponent {} describe('FeatureToggleDirective', () => { - let fixture: ComponentFixture; - let service: FeatureToggleService; - - beforeEach(() => { - fixture = TestBed.configureTestingModule({ - declarations: [FeatureToggleDirective, TestComponent], - providers: [FeatureToggleService, HttpClient, HttpHandler], - }).createComponent(TestComponent); - - service = TestBed.inject(FeatureToggleService); - service.config = { testToggleEnabled: true, testToggleDisabled: false }; - - fixture.detectChanges(); // initial binding - }); - - it('should be able to see the enabled toggled state', () => { - const seenBox = fixture.debugElement.queryAll(By.css('#testToggleEnabled')); - expect(seenBox).toHaveLength(1); - }); - - it('should not be able to see the disabled toggled state', () => { - const seenBox = fixture.debugElement.queryAll(By.css('#testToggleDisabled')); - expect(seenBox).toEqual([]); - }); - - it('should not be able to see the random key state', () => { - const seenBox = fixture.debugElement.queryAll(By.css('#randomKey')); - expect(seenBox).toEqual([]); - }); - - it('should be able to see with no directive', () => { - const seenBox = fixture.debugElement.queryAll(By.css('#noToggle')); - expect(seenBox).toHaveLength(1); - }); + let fixture: ComponentFixture; + let service: FeatureToggleService; + + beforeEach(() => { + fixture = TestBed.configureTestingModule({ + declarations: [FeatureToggleDirective, TestComponent], + providers: [FeatureToggleService, HttpClient, HttpHandler], + }).createComponent(TestComponent); + + service = TestBed.inject(FeatureToggleService); + service.config = { testToggleEnabled: true, testToggleDisabled: false }; + + fixture.detectChanges(); // initial binding + }); + + it('should be able to see the enabled toggled state', () => { + const seenBox = fixture.debugElement.queryAll(By.css('#testToggleEnabled')); + expect(seenBox).toHaveLength(1); + }); + + it('should not be able to see the disabled toggled state', () => { + const seenBox = fixture.debugElement.queryAll(By.css('#testToggleDisabled')); + expect(seenBox).toEqual([]); + }); + + it('should not be able to see the random key state', () => { + const seenBox = fixture.debugElement.queryAll(By.css('#randomKey')); + expect(seenBox).toEqual([]); + }); + + it('should be able to see with no directive', () => { + const seenBox = fixture.debugElement.queryAll(By.css('#noToggle')); + expect(seenBox).toHaveLength(1); + }); }); diff --git a/src/app/directives/feature-toggle.directive.ts b/src/app/directives/feature-toggle.directive.ts index 9708b9787d..bc1d9c3b4d 100644 --- a/src/app/directives/feature-toggle.directive.ts +++ b/src/app/directives/feature-toggle.directive.ts @@ -1,22 +1,20 @@ -import { - Directive, Input, OnInit, TemplateRef, ViewContainerRef, -} from '@angular/core'; +import { Directive, Input, OnInit, TemplateRef, ViewContainerRef } from '@angular/core'; import { FeatureToggleService } from '@services/feature-toggle-service/feature-toggle-service'; @Directive({ selector: '[featureToggleName]' }) export class FeatureToggleDirective implements OnInit { - @Input() featureToggleName!: string; + @Input() featureToggleName!: string; - constructor( - private templateRef: TemplateRef, - private featureToggleService: FeatureToggleService, - private viewContainer: ViewContainerRef, - ) {} + constructor( + private templateRef: TemplateRef, + private featureToggleService: FeatureToggleService, + private viewContainer: ViewContainerRef + ) {} - ngOnInit() { - const isEnabled = this.featureToggleService.isFeatureEnabled(this.featureToggleName); - if (isEnabled) { - this.viewContainer.createEmbeddedView(this.templateRef); - } - } + ngOnInit() { + const isEnabled = this.featureToggleService.isFeatureEnabled(this.featureToggleName); + if (isEnabled) { + this.viewContainer.createEmbeddedView(this.templateRef); + } + } } diff --git a/src/app/features/feature-toggle/feature-toggle-routing.module.ts b/src/app/features/feature-toggle/feature-toggle-routing.module.ts index 5452f68002..ae9465ab06 100644 --- a/src/app/features/feature-toggle/feature-toggle-routing.module.ts +++ b/src/app/features/feature-toggle/feature-toggle-routing.module.ts @@ -5,16 +5,16 @@ import { FeatureToggleGuard } from '@guards/feature-toggle-guard/feature-toggle. import { FeatureToggleComponent } from './feature-toggle/feature-toggle.component'; const routes = [ - { - path: '', - component: FeatureToggleComponent, - data: { title: 'Feature Toggle', featureToggleName: 'testToggle' }, - canActivate: [MsalGuard, FeatureToggleGuard], - }, + { + path: '', + component: FeatureToggleComponent, + data: { title: 'Feature Toggle', featureToggleName: 'testToggle' }, + canActivate: [MsalGuard, FeatureToggleGuard], + }, ]; @NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], }) export class FeatureToggleRoutingModule {} diff --git a/src/app/features/feature-toggle/feature-toggle.module.ts b/src/app/features/feature-toggle/feature-toggle.module.ts index f1637312e7..49cd43249c 100644 --- a/src/app/features/feature-toggle/feature-toggle.module.ts +++ b/src/app/features/feature-toggle/feature-toggle.module.ts @@ -5,9 +5,7 @@ import { FeatureToggleRoutingModule } from './feature-toggle-routing.module'; import { FeatureToggleComponent } from './feature-toggle/feature-toggle.component'; @NgModule({ - declarations: [FeatureToggleComponent], - imports: [ - CommonModule, SharedModule, FeatureToggleRoutingModule, - ], + declarations: [FeatureToggleComponent], + imports: [CommonModule, SharedModule, FeatureToggleRoutingModule], }) -export class FeatureToggleModule { } +export class FeatureToggleModule {} diff --git a/src/app/features/feature-toggle/feature-toggle/feature-toggle.component.ts b/src/app/features/feature-toggle/feature-toggle/feature-toggle.component.ts index 7e5f4b5eb4..97df34703e 100644 --- a/src/app/features/feature-toggle/feature-toggle/feature-toggle.component.ts +++ b/src/app/features/feature-toggle/feature-toggle/feature-toggle.component.ts @@ -1,8 +1,7 @@ import { Component } from '@angular/core'; @Component({ - selector: 'feature-toggle', - templateUrl: './feature-toggle.component.html', + selector: 'feature-toggle', + templateUrl: './feature-toggle.component.html', }) -export class FeatureToggleComponent { -} +export class FeatureToggleComponent {} diff --git a/src/app/features/home/components/home-button/home-button.component.spec.ts b/src/app/features/home/components/home-button/home-button.component.spec.ts index 1331308687..e7d4916c58 100644 --- a/src/app/features/home/components/home-button/home-button.component.spec.ts +++ b/src/app/features/home/components/home-button/home-button.component.spec.ts @@ -3,23 +3,23 @@ import { RouterTestingModule } from '@angular/router/testing'; import { HomeButtonComponent } from './home-button.component'; describe('HomeButtonComponent', () => { - let component: HomeButtonComponent; - let fixture: ComponentFixture; + let component: HomeButtonComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [HomeButtonComponent], - imports: [RouterTestingModule], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [HomeButtonComponent], + imports: [RouterTestingModule], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(HomeButtonComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(HomeButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/features/home/components/home-button/home-button.component.ts b/src/app/features/home/components/home-button/home-button.component.ts index 49ade3c0e7..5cdefb047d 100644 --- a/src/app/features/home/components/home-button/home-button.component.ts +++ b/src/app/features/home/components/home-button/home-button.component.ts @@ -1,13 +1,13 @@ import { Component, Input } from '@angular/core'; @Component({ - selector: 'app-home-button', - templateUrl: './home-button.component.html', - styleUrls: ['./home-button.component.scss'], + selector: 'app-home-button', + templateUrl: './home-button.component.html', + styleUrls: ['./home-button.component.scss'], }) export class HomeButtonComponent { - @Input() url = ''; - @Input() linkText = ''; - @Input() description = ''; - @Input() linkId = ''; + @Input() url = ''; + @Input() linkText = ''; + @Input() description = ''; + @Input() linkId = ''; } diff --git a/src/app/features/home/components/home-button/home-button.stories.ts b/src/app/features/home/components/home-button/home-button.stories.ts index 5819289225..193ae30a66 100644 --- a/src/app/features/home/components/home-button/home-button.stories.ts +++ b/src/app/features/home/components/home-button/home-button.stories.ts @@ -3,10 +3,10 @@ import { Meta, Story } from '@storybook/angular'; import { HomeButtonComponent } from './home-button.component'; export default { - title: 'Home Button', - component: HomeButtonComponent + title: 'Home Button', + component: HomeButtonComponent, } as Meta; export const Primary: Story = () => ({ - props: {} + props: {}, }); diff --git a/src/app/features/home/home-routing.module.ts b/src/app/features/home/home-routing.module.ts index a0f5430231..8150ff3cbf 100644 --- a/src/app/features/home/home-routing.module.ts +++ b/src/app/features/home/home-routing.module.ts @@ -3,15 +3,15 @@ import { RouterModule, Routes } from '@angular/router'; import { HomeComponent } from './home.component'; const routes: Routes = [ - { - path: '', - pathMatch: 'prefix', - component: HomeComponent, - }, + { + path: '', + pathMatch: 'prefix', + component: HomeComponent, + }, ]; @NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], }) export class HomeRoutingModule {} diff --git a/src/app/features/home/home.component.spec.ts b/src/app/features/home/home.component.spec.ts index 31eee3e014..3d3e56ae45 100644 --- a/src/app/features/home/home.component.spec.ts +++ b/src/app/features/home/home.component.spec.ts @@ -12,34 +12,34 @@ import { HomeButtonComponent } from './components/home-button/home-button.compon import { HomeComponent } from './home.component'; describe('HomeComponent', () => { - let component: HomeComponent; - let fixture: ComponentFixture; - const actions$ = new ReplaySubject(); + let component: HomeComponent; + let fixture: ComponentFixture; + const actions$ = new ReplaySubject(); - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [HomeComponent, HomeButtonComponent, RoleRequiredDirective], - imports: [RouterTestingModule, SharedModule, HttpClientModule], - providers: [ - FormBuilder, - provideMockActions(() => actions$), - { - provide: UserService, - useValue: { - roles$: of(['TechRecord.View']), - }, - }, - ], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [HomeComponent, HomeButtonComponent, RoleRequiredDirective], + imports: [RouterTestingModule, SharedModule, HttpClientModule], + providers: [ + FormBuilder, + provideMockActions(() => actions$), + { + provide: UserService, + useValue: { + roles$: of(['TechRecord.View']), + }, + }, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(HomeComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(HomeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/features/home/home.component.ts b/src/app/features/home/home.component.ts index 52e87cf706..f44b128606 100644 --- a/src/app/features/home/home.component.ts +++ b/src/app/features/home/home.component.ts @@ -2,11 +2,11 @@ import { Component } from '@angular/core'; import { Roles } from '@models/roles.enum'; @Component({ - selector: 'app-home', - templateUrl: './home.component.html', + selector: 'app-home', + templateUrl: './home.component.html', }) export class HomeComponent { - public get Roles() { - return Roles; - } + public get Roles() { + return Roles; + } } diff --git a/src/app/features/home/home.module.ts b/src/app/features/home/home.module.ts index 42ba21d5f6..a129d43e69 100644 --- a/src/app/features/home/home.module.ts +++ b/src/app/features/home/home.module.ts @@ -6,7 +6,7 @@ import { HomeRoutingModule } from './home-routing.module'; import { HomeComponent } from './home.component'; @NgModule({ - declarations: [HomeComponent, HomeButtonComponent], - imports: [CommonModule, HomeRoutingModule, SharedModule], + declarations: [HomeComponent, HomeButtonComponent], + imports: [CommonModule, HomeRoutingModule, SharedModule], }) export class HomeModule {} diff --git a/src/app/features/home/home.stories.ts b/src/app/features/home/home.stories.ts index ddd825dcc9..d6aaa85fd3 100644 --- a/src/app/features/home/home.stories.ts +++ b/src/app/features/home/home.stories.ts @@ -3,10 +3,10 @@ import { Meta, Story } from '@storybook/angular'; import { HomeComponent } from './home.component'; export default { - title: 'Home Page', - component: HomeComponent + title: 'Home Page', + component: HomeComponent, } as Meta; export const Primary: Story = () => ({ - props: {} + props: {}, }); diff --git a/src/app/features/reference-data/reference-data-add/reference-data-add.component.spec.ts b/src/app/features/reference-data/reference-data-add/reference-data-add.component.spec.ts index c5509678e8..5ef1ceacce 100644 --- a/src/app/features/reference-data/reference-data-add/reference-data-add.component.spec.ts +++ b/src/app/features/reference-data/reference-data-add/reference-data-add.component.spec.ts @@ -11,109 +11,109 @@ import { of } from 'rxjs'; import { ReferenceDataCreateComponent } from './reference-data-add.component'; const mockRefDataService = { - loadReferenceData: jest.fn(), - loadReferenceDataByKey: jest.fn(), - fetchReferenceDataByKey: jest.fn(), + loadReferenceData: jest.fn(), + loadReferenceDataByKey: jest.fn(), + fetchReferenceDataByKey: jest.fn(), }; describe('ReferenceDataCreateComponent', () => { - let component: ReferenceDataCreateComponent; - let fixture: ComponentFixture; - let store: MockStore; - let router: Router; - let route: ActivatedRoute; - let errorService: GlobalErrorService; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ReferenceDataCreateComponent], - imports: [RouterTestingModule, HttpClientTestingModule], - providers: [ - GlobalErrorService, - provideMockStore({ initialState: initialAppState }), - ReferenceDataService, - { provide: UserService, useValue: {} }, - { provide: ReferenceDataService, useValue: mockRefDataService }, - ], - }).compileComponents(); - }); - - beforeEach(() => { - store = TestBed.inject(MockStore); - fixture = TestBed.createComponent(ReferenceDataCreateComponent); - component = fixture.componentInstance; - router = TestBed.inject(Router); - fixture.detectChanges(); - errorService = TestBed.inject(GlobalErrorService); - route = TestBed.inject(ActivatedRoute); - fixture.detectChanges(); - component.checkForms = jest.fn(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('navigateBack', () => { - it('should clear all errors', () => { - jest.spyOn(router, 'navigate').mockImplementation(); - - const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); - - component.navigateBack(); - - expect(clearErrorsSpy).toHaveBeenCalledTimes(1); - }); - - it('should navigate back to the previous page', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - component.navigateBack(); - - expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); - }); - }); - - describe('handleFormChange', () => { - it('should set newRefData', () => { - component.handleFormChange({ foo: 'bar' }); - - expect(component.newRefData).toEqual({ foo: 'bar' }); - }); - }); - - describe('handleSubmit', () => { - it('should dispatch if form is valid', () => { - fixture.ngZone?.run(() => { - component.newRefData = { description: 'test' }; - jest.spyOn(component, 'checkForms').mockImplementationOnce(() => { - component.isFormInvalid = false; - }); - const dispatch = jest.spyOn(store, 'dispatch'); - - component.handleSubmit(); - - expect(dispatch).toHaveBeenCalled(); - }); - }); - it('should not dispatch if form is invalid', () => { - jest.spyOn(component, 'checkForms').mockImplementationOnce(() => { - component.isFormInvalid = true; - }); - const dispatch = jest.spyOn(store, 'dispatch'); - - component.handleSubmit(); - - expect(dispatch).not.toHaveBeenCalled(); - }); - it('should not dispatch if ref data already exists', () => { - jest.spyOn(mockRefDataService, 'fetchReferenceDataByKey').mockReturnValueOnce(of({ foo: 'bar' })); - - const dispatch = jest.spyOn(store, 'dispatch'); - - component.handleSubmit(); - - expect(dispatch).not.toHaveBeenCalled(); - }); - }); + let component: ReferenceDataCreateComponent; + let fixture: ComponentFixture; + let store: MockStore; + let router: Router; + let route: ActivatedRoute; + let errorService: GlobalErrorService; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ReferenceDataCreateComponent], + imports: [RouterTestingModule, HttpClientTestingModule], + providers: [ + GlobalErrorService, + provideMockStore({ initialState: initialAppState }), + ReferenceDataService, + { provide: UserService, useValue: {} }, + { provide: ReferenceDataService, useValue: mockRefDataService }, + ], + }).compileComponents(); + }); + + beforeEach(() => { + store = TestBed.inject(MockStore); + fixture = TestBed.createComponent(ReferenceDataCreateComponent); + component = fixture.componentInstance; + router = TestBed.inject(Router); + fixture.detectChanges(); + errorService = TestBed.inject(GlobalErrorService); + route = TestBed.inject(ActivatedRoute); + fixture.detectChanges(); + component.checkForms = jest.fn(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('navigateBack', () => { + it('should clear all errors', () => { + jest.spyOn(router, 'navigate').mockImplementation(); + + const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); + + component.navigateBack(); + + expect(clearErrorsSpy).toHaveBeenCalledTimes(1); + }); + + it('should navigate back to the previous page', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + component.navigateBack(); + + expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); + }); + }); + + describe('handleFormChange', () => { + it('should set newRefData', () => { + component.handleFormChange({ foo: 'bar' }); + + expect(component.newRefData).toEqual({ foo: 'bar' }); + }); + }); + + describe('handleSubmit', () => { + it('should dispatch if form is valid', () => { + fixture.ngZone?.run(() => { + component.newRefData = { description: 'test' }; + jest.spyOn(component, 'checkForms').mockImplementationOnce(() => { + component.isFormInvalid = false; + }); + const dispatch = jest.spyOn(store, 'dispatch'); + + component.handleSubmit(); + + expect(dispatch).toHaveBeenCalled(); + }); + }); + it('should not dispatch if form is invalid', () => { + jest.spyOn(component, 'checkForms').mockImplementationOnce(() => { + component.isFormInvalid = true; + }); + const dispatch = jest.spyOn(store, 'dispatch'); + + component.handleSubmit(); + + expect(dispatch).not.toHaveBeenCalled(); + }); + it('should not dispatch if ref data already exists', () => { + jest.spyOn(mockRefDataService, 'fetchReferenceDataByKey').mockReturnValueOnce(of({ foo: 'bar' })); + + const dispatch = jest.spyOn(store, 'dispatch'); + + component.handleSubmit(); + + expect(dispatch).not.toHaveBeenCalled(); + }); + }); }); diff --git a/src/app/features/reference-data/reference-data-add/reference-data-add.component.ts b/src/app/features/reference-data/reference-data-add/reference-data-add.component.ts index 8a4e09d012..c1624909a5 100644 --- a/src/app/features/reference-data/reference-data-add/reference-data-add.component.ts +++ b/src/app/features/reference-data/reference-data-add/reference-data-add.component.ts @@ -1,6 +1,4 @@ -import { - Component, OnInit, QueryList, ViewChildren, -} from '@angular/core'; +import { Component, OnInit, QueryList, ViewChildren } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalError } from '@core/components/global-error/global-error.interface'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; @@ -12,127 +10,131 @@ import { Roles } from '@models/roles.enum'; import { Store, select } from '@ngrx/store'; import { ReferenceDataService } from '@services/reference-data/reference-data.service'; import { ReferenceDataState, createReferenceDataItem, selectReferenceDataByResourceKey } from '@store/reference-data'; -import { - Observable, catchError, filter, of, switchMap, take, throwError, -} from 'rxjs'; +import { Observable, catchError, filter, of, switchMap, take, throwError } from 'rxjs'; @Component({ - selector: 'app-reference-data-add', - templateUrl: './reference-data-add.component.html', + selector: 'app-reference-data-add', + templateUrl: './reference-data-add.component.html', }) export class ReferenceDataCreateComponent implements OnInit { - type: ReferenceDataResourceType = ReferenceDataResourceType.Brakes; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - newRefData: any; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - data: any = {}; - isFormDirty = false; - isFormInvalid = true; - - @ViewChildren(DynamicFormGroupComponent) sections!: QueryList; - - constructor( - public globalErrorService: GlobalErrorService, - public dfs: DynamicFormService, - private referenceDataService: ReferenceDataService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - ) {} - - ngOnInit(): void { - this.route.parent?.params.pipe(take(1)).subscribe((params) => { - this.type = params['type']; - this.referenceDataService.loadReferenceDataByKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type); - }); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - get refDataAdminType$(): Observable { - return this.store.pipe(select(selectReferenceDataByResourceKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type))); - } - - get roles(): typeof Roles { - return Roles; - } - - get widths(): typeof FormNodeWidth { - return FormNodeWidth; - } - - navigateBack() { - this.globalErrorService.clearErrors(); - void this.router.navigate(['..'], { relativeTo: this.route }); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - handleFormChange(event: any) { - this.newRefData = event; - } - - handleSubmit() { - this.checkForms(); - - if (this.isFormInvalid) return; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const referenceData: any = {}; - - Object.keys(this.newRefData) - .filter((newRefDataKey) => newRefDataKey !== 'resourceKey') - .forEach((dataKey) => { - referenceData[`${dataKey}`] = this.newRefData[`${dataKey}`]; - }); - - this.globalErrorService.errors$ - .pipe( - take(1), - filter((errors) => !errors.length), - switchMap(() => this.referenceDataService.fetchReferenceDataByKey(this.type, this.newRefData.resourceKey)), - take(1), - catchError((error) => (error.status === 200 ? of(true) : throwError(() => new Error('Error')))), - ) - .subscribe({ - next: (res) => { - if (res) return this.globalErrorService.addError({ error: 'Resource Key already exists', anchorLink: 'newReferenceData' }); - }, - error: (e) => { - if (e.status === 404) { - of(true); - } else { - this.store.dispatch( - createReferenceDataItem({ - resourceType: this.type, - resourceKey: encodeURIComponent(String(this.newRefData.resourceKey)), - payload: referenceData, - }), - ); - this.navigateBack(); - } - }, - }); - } - - checkForms(): void { - const forms = this.sections.map((section) => section.form) as Array; - - this.isFormDirty = forms.some((form) => form.dirty); - - this.setErrors(forms); - - this.isFormInvalid = forms.some((form) => form.invalid); - } - - setErrors(forms: Array): void { - const errors: GlobalError[] = []; - - forms.forEach((form) => DynamicFormService.validate(form, errors)); - - if (errors.length) { - this.globalErrorService.setErrors(errors); - return; - } - - this.globalErrorService.clearErrors(); - } + type: ReferenceDataResourceType = ReferenceDataResourceType.Brakes; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + newRefData: any; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data: any = {}; + isFormDirty = false; + isFormInvalid = true; + + @ViewChildren(DynamicFormGroupComponent) sections!: QueryList; + + constructor( + public globalErrorService: GlobalErrorService, + public dfs: DynamicFormService, + private referenceDataService: ReferenceDataService, + private route: ActivatedRoute, + private router: Router, + private store: Store + ) {} + + ngOnInit(): void { + this.route.parent?.params.pipe(take(1)).subscribe((params) => { + this.type = params['type']; + this.referenceDataService.loadReferenceDataByKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type); + }); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + get refDataAdminType$(): Observable { + return this.store.pipe( + select(selectReferenceDataByResourceKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type)) + ); + } + + get roles(): typeof Roles { + return Roles; + } + + get widths(): typeof FormNodeWidth { + return FormNodeWidth; + } + + navigateBack() { + this.globalErrorService.clearErrors(); + void this.router.navigate(['..'], { relativeTo: this.route }); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + handleFormChange(event: any) { + this.newRefData = event; + } + + handleSubmit() { + this.checkForms(); + + if (this.isFormInvalid) return; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const referenceData: any = {}; + + Object.keys(this.newRefData) + .filter((newRefDataKey) => newRefDataKey !== 'resourceKey') + .forEach((dataKey) => { + referenceData[`${dataKey}`] = this.newRefData[`${dataKey}`]; + }); + + this.globalErrorService.errors$ + .pipe( + take(1), + filter((errors) => !errors.length), + switchMap(() => this.referenceDataService.fetchReferenceDataByKey(this.type, this.newRefData.resourceKey)), + take(1), + catchError((error) => (error.status === 200 ? of(true) : throwError(() => new Error('Error')))) + ) + .subscribe({ + next: (res) => { + if (res) + return this.globalErrorService.addError({ + error: 'Resource Key already exists', + anchorLink: 'newReferenceData', + }); + }, + error: (e) => { + if (e.status === 404) { + of(true); + } else { + this.store.dispatch( + createReferenceDataItem({ + resourceType: this.type, + resourceKey: encodeURIComponent(String(this.newRefData.resourceKey)), + payload: referenceData, + }) + ); + this.navigateBack(); + } + }, + }); + } + + checkForms(): void { + const forms = this.sections.map((section) => section.form) as Array; + + this.isFormDirty = forms.some((form) => form.dirty); + + this.setErrors(forms); + + this.isFormInvalid = forms.some((form) => form.invalid); + } + + setErrors(forms: Array): void { + const errors: GlobalError[] = []; + + forms.forEach((form) => DynamicFormService.validate(form, errors)); + + if (errors.length) { + this.globalErrorService.setErrors(errors); + return; + } + + this.globalErrorService.clearErrors(); + } } diff --git a/src/app/features/reference-data/reference-data-amend-history/reference-data-amend-history.component.spec.ts b/src/app/features/reference-data/reference-data-amend-history/reference-data-amend-history.component.spec.ts index 32488da71e..2b271cda86 100644 --- a/src/app/features/reference-data/reference-data-amend-history/reference-data-amend-history.component.spec.ts +++ b/src/app/features/reference-data/reference-data-amend-history/reference-data-amend-history.component.spec.ts @@ -8,33 +8,37 @@ import { initialAppState } from '@store/.'; import { ReferenceDataAmendHistoryComponent } from './reference-data-amend-history.component'; describe('ReferenceDataAmendHistoryComponent', () => { - let component: ReferenceDataAmendHistoryComponent; - let fixture: ComponentFixture; + let component: ReferenceDataAmendHistoryComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ReferenceDataAmendHistoryComponent], - imports: [RouterTestingModule, HttpClientTestingModule], - providers: [provideMockStore({ initialState: initialAppState }), ReferenceDataService, { provide: UserService, useValue: {} }], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ReferenceDataAmendHistoryComponent], + imports: [RouterTestingModule, HttpClientTestingModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + ReferenceDataService, + { provide: UserService, useValue: {} }, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(ReferenceDataAmendHistoryComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(ReferenceDataAmendHistoryComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - describe('handlePaginationChange', () => { - it('should set pageStart and pageEnd', () => { - component.handlePaginationChange({ start: 7, end: 20 }); + describe('handlePaginationChange', () => { + it('should set pageStart and pageEnd', () => { + component.handlePaginationChange({ start: 7, end: 20 }); - expect(component.pageStart).toBe(7); - expect(component.pageEnd).toBe(20); - }); - }); + expect(component.pageStart).toBe(7); + expect(component.pageEnd).toBe(20); + }); + }); }); diff --git a/src/app/features/reference-data/reference-data-amend-history/reference-data-amend-history.component.ts b/src/app/features/reference-data/reference-data-amend-history/reference-data-amend-history.component.ts index 17ccaa9da8..3c4c1d6456 100644 --- a/src/app/features/reference-data/reference-data-amend-history/reference-data-amend-history.component.ts +++ b/src/app/features/reference-data/reference-data-amend-history/reference-data-amend-history.component.ts @@ -1,52 +1,57 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; import { - ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, -} from '@angular/core'; -import { ReferenceDataAdminColumn, ReferenceDataModelBase, ReferenceDataResourceType } from '@models/reference-data.model'; + ReferenceDataAdminColumn, + ReferenceDataModelBase, + ReferenceDataResourceType, +} from '@models/reference-data.model'; import { Store, select } from '@ngrx/store'; import { ReferenceDataState, fetchReferenceDataByKeySearch, selectSearchReturn } from '@store/reference-data'; import { Observable, map } from 'rxjs'; @Component({ - selector: 'app-reference-data-amend-history', - templateUrl: './reference-data-amend-history.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-reference-data-amend-history', + templateUrl: './reference-data-amend-history.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class ReferenceDataAmendHistoryComponent implements OnInit { - @Input() type = ''; - @Input() key = ''; - @Input() title = ''; - @Input() columns: ReferenceDataAdminColumn[] = []; - - pageStart?: number; - pageEnd?: number; - - constructor(private cdr: ChangeDetectorRef, private store: Store) {} - - ngOnInit(): void { - // load the audit history - this.store.dispatch( - fetchReferenceDataByKeySearch({ - resourceType: `${this.type}#AUDIT` as ReferenceDataResourceType, - resourceKey: `${decodeURIComponent(this.key)}#`, - }), - ); - } - - get history$(): Observable { - return this.store.pipe(select(selectSearchReturn(`${this.type}#AUDIT` as ReferenceDataResourceType))); - } - - get numberOfRecords$(): Observable { - return this.history$.pipe(map((items) => items?.length ?? 0)); - } - - get paginatedItems$() { - return this.history$.pipe(map((items) => items?.slice(this.pageStart, this.pageEnd) ?? [])); - } - - handlePaginationChange({ start, end }: { start: number; end: number }) { - this.pageStart = start; - this.pageEnd = end; - this.cdr.detectChanges(); - } + @Input() type = ''; + @Input() key = ''; + @Input() title = ''; + @Input() columns: ReferenceDataAdminColumn[] = []; + + pageStart?: number; + pageEnd?: number; + + constructor( + private cdr: ChangeDetectorRef, + private store: Store + ) {} + + ngOnInit(): void { + // load the audit history + this.store.dispatch( + fetchReferenceDataByKeySearch({ + resourceType: `${this.type}#AUDIT` as ReferenceDataResourceType, + resourceKey: `${decodeURIComponent(this.key)}#`, + }) + ); + } + + get history$(): Observable { + return this.store.pipe(select(selectSearchReturn(`${this.type}#AUDIT` as ReferenceDataResourceType))); + } + + get numberOfRecords$(): Observable { + return this.history$.pipe(map((items) => items?.length ?? 0)); + } + + get paginatedItems$() { + return this.history$.pipe(map((items) => items?.slice(this.pageStart, this.pageEnd) ?? [])); + } + + handlePaginationChange({ start, end }: { start: number; end: number }) { + this.pageStart = start; + this.pageEnd = end; + this.cdr.detectChanges(); + } } diff --git a/src/app/features/reference-data/reference-data-amend/reference-data-amend.component.spec.ts b/src/app/features/reference-data/reference-data-amend/reference-data-amend.component.spec.ts index 8d47f7f92b..7f50174b69 100644 --- a/src/app/features/reference-data/reference-data-amend/reference-data-amend.component.spec.ts +++ b/src/app/features/reference-data/reference-data-amend/reference-data-amend.component.spec.ts @@ -10,98 +10,98 @@ import { State, initialAppState } from '@store/.'; import { ReferenceDataAmendComponent } from './reference-data-amend.component'; const mockRefDataService = { - loadReferenceData: jest.fn(), - loadReferenceDataByKey: jest.fn(), - fetchReferenceDataByKey: jest.fn(), + loadReferenceData: jest.fn(), + loadReferenceDataByKey: jest.fn(), + fetchReferenceDataByKey: jest.fn(), }; describe('ReferenceDataAmendComponent', () => { - let component: ReferenceDataAmendComponent; - let fixture: ComponentFixture; - let store: MockStore; - let router: Router; - let route: ActivatedRoute; - let errorService: GlobalErrorService; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ReferenceDataAmendComponent], - imports: [RouterTestingModule, HttpClientTestingModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - ReferenceDataService, - { provide: UserService, useValue: {} }, - { provide: ReferenceDataService, useValue: mockRefDataService }, - ], - }).compileComponents(); - }); - - beforeEach(() => { - store = TestBed.inject(MockStore); - fixture = TestBed.createComponent(ReferenceDataAmendComponent); - component = fixture.componentInstance; - router = TestBed.inject(Router); - errorService = TestBed.inject(GlobalErrorService); - route = TestBed.inject(ActivatedRoute); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('navigateBack', () => { - it('should clear all errors', () => { - jest.spyOn(router, 'navigate').mockImplementation(); - - const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); - - component.navigateBack(); - - expect(clearErrorsSpy).toHaveBeenCalledTimes(1); - }); - - it('should navigate back to the previous page', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - component.navigateBack(); - - expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); - }); - }); - - describe('handleFormChange', () => { - it('should set amendedData', () => { - component.handleFormChange({ foo: 'bar' }); - - expect(component.amendedData).toEqual({ foo: 'bar' }); - }); - }); - - describe('handleSubmit', () => { - it('should dispatch if form is valid', () => { - fixture.ngZone?.run(() => { - component.amendedData = { description: 'testing' }; - jest.spyOn(component, 'checkForms').mockImplementationOnce(() => { - component.isFormInvalid = false; - }); - const dispatch = jest.spyOn(store, 'dispatch'); - - component.handleSubmit(); - - expect(dispatch).toHaveBeenCalled(); - }); - }); - - it('should not dispatch if form is invalid', () => { - jest.spyOn(component, 'checkForms').mockImplementationOnce(() => { - component.isFormInvalid = true; - }); - const dispatch = jest.spyOn(store, 'dispatch'); - - component.handleSubmit(); - - expect(dispatch).not.toHaveBeenCalled(); - }); - }); + let component: ReferenceDataAmendComponent; + let fixture: ComponentFixture; + let store: MockStore; + let router: Router; + let route: ActivatedRoute; + let errorService: GlobalErrorService; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ReferenceDataAmendComponent], + imports: [RouterTestingModule, HttpClientTestingModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + ReferenceDataService, + { provide: UserService, useValue: {} }, + { provide: ReferenceDataService, useValue: mockRefDataService }, + ], + }).compileComponents(); + }); + + beforeEach(() => { + store = TestBed.inject(MockStore); + fixture = TestBed.createComponent(ReferenceDataAmendComponent); + component = fixture.componentInstance; + router = TestBed.inject(Router); + errorService = TestBed.inject(GlobalErrorService); + route = TestBed.inject(ActivatedRoute); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('navigateBack', () => { + it('should clear all errors', () => { + jest.spyOn(router, 'navigate').mockImplementation(); + + const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); + + component.navigateBack(); + + expect(clearErrorsSpy).toHaveBeenCalledTimes(1); + }); + + it('should navigate back to the previous page', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + component.navigateBack(); + + expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); + }); + }); + + describe('handleFormChange', () => { + it('should set amendedData', () => { + component.handleFormChange({ foo: 'bar' }); + + expect(component.amendedData).toEqual({ foo: 'bar' }); + }); + }); + + describe('handleSubmit', () => { + it('should dispatch if form is valid', () => { + fixture.ngZone?.run(() => { + component.amendedData = { description: 'testing' }; + jest.spyOn(component, 'checkForms').mockImplementationOnce(() => { + component.isFormInvalid = false; + }); + const dispatch = jest.spyOn(store, 'dispatch'); + + component.handleSubmit(); + + expect(dispatch).toHaveBeenCalled(); + }); + }); + + it('should not dispatch if form is invalid', () => { + jest.spyOn(component, 'checkForms').mockImplementationOnce(() => { + component.isFormInvalid = true; + }); + const dispatch = jest.spyOn(store, 'dispatch'); + + component.handleSubmit(); + + expect(dispatch).not.toHaveBeenCalled(); + }); + }); }); diff --git a/src/app/features/reference-data/reference-data-amend/reference-data-amend.component.ts b/src/app/features/reference-data/reference-data-amend/reference-data-amend.component.ts index f3fef4e437..3a7bb8346d 100644 --- a/src/app/features/reference-data/reference-data-amend/reference-data-amend.component.ts +++ b/src/app/features/reference-data/reference-data-amend/reference-data-amend.component.ts @@ -1,6 +1,4 @@ -import { - Component, OnInit, QueryList, ViewChildren, -} from '@angular/core'; +import { Component, OnInit, QueryList, ViewChildren } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalError } from '@core/components/global-error/global-error.interface'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; @@ -15,110 +13,112 @@ import { ReferenceDataState, amendReferenceDataItem, selectReferenceDataByResour import { Observable, first } from 'rxjs'; @Component({ - selector: 'app-reference-data-amend', - templateUrl: './reference-data-amend.component.html', + selector: 'app-reference-data-amend', + templateUrl: './reference-data-amend.component.html', }) export class ReferenceDataAmendComponent implements OnInit { - type!: ReferenceDataResourceType; - key!: string; - isFormDirty = false; - isFormInvalid = true; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - amendedData: any; - - @ViewChildren(DynamicFormGroupComponent) sections!: QueryList; - - constructor( - public globalErrorService: GlobalErrorService, - public dfs: DynamicFormService, - private referenceDataService: ReferenceDataService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - ) {} - - ngOnInit(): void { - this.route.parent?.params.pipe(first()).subscribe((params) => { - this.type = params['type']; - // load the reference data admin type - this.referenceDataService.loadReferenceDataByKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type); - }); - - this.route.params.pipe(first()).subscribe((params) => { - this.key = decodeURIComponent(params['key']); - - if (this.type && this.key) { - // load the current item - this.referenceDataService.loadReferenceDataByKey(this.type, this.key); - } - }); - } - - get roles(): typeof Roles { - return Roles; - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - get refDataAdminType$(): Observable { - return this.store.pipe(select(selectReferenceDataByResourceKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type))); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - get data$(): Observable { - return this.store.pipe(select(selectReferenceDataByResourceKey(this.type, this.key))); - } - - navigateBack() { - this.globalErrorService.clearErrors(); - void this.router.navigate(['..'], { relativeTo: this.route }); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - handleFormChange(event: any) { - this.amendedData = event; - } - - checkForms(): void { - const forms = this.sections.map((section) => section.form) as Array; - - this.isFormDirty = forms.some((form) => form.dirty); - - this.setErrors(forms); - - this.isFormInvalid = forms.some((form) => form.invalid); - } - - setErrors(forms: Array): void { - const errors: GlobalError[] = []; - - forms.forEach((form) => DynamicFormService.validate(form, errors)); - - if (errors.length) { - this.globalErrorService.setErrors(errors); - return; - } - - this.globalErrorService.clearErrors(); - } - - handleSubmit() { - this.checkForms(); - - if (this.isFormInvalid) return; - - this.store.dispatch( - amendReferenceDataItem({ - resourceType: this.type, - resourceKey: encodeURIComponent(String(this.key)), - payload: this.amendedData, - }), - ); - - this.sections.forEach((form) => { - form.ngOnDestroy(); - }); - - this.navigateBack(); - } + type!: ReferenceDataResourceType; + key!: string; + isFormDirty = false; + isFormInvalid = true; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + amendedData: any; + + @ViewChildren(DynamicFormGroupComponent) sections!: QueryList; + + constructor( + public globalErrorService: GlobalErrorService, + public dfs: DynamicFormService, + private referenceDataService: ReferenceDataService, + private route: ActivatedRoute, + private router: Router, + private store: Store + ) {} + + ngOnInit(): void { + this.route.parent?.params.pipe(first()).subscribe((params) => { + this.type = params['type']; + // load the reference data admin type + this.referenceDataService.loadReferenceDataByKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type); + }); + + this.route.params.pipe(first()).subscribe((params) => { + this.key = decodeURIComponent(params['key']); + + if (this.type && this.key) { + // load the current item + this.referenceDataService.loadReferenceDataByKey(this.type, this.key); + } + }); + } + + get roles(): typeof Roles { + return Roles; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + get refDataAdminType$(): Observable { + return this.store.pipe( + select(selectReferenceDataByResourceKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type)) + ); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + get data$(): Observable { + return this.store.pipe(select(selectReferenceDataByResourceKey(this.type, this.key))); + } + + navigateBack() { + this.globalErrorService.clearErrors(); + void this.router.navigate(['..'], { relativeTo: this.route }); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + handleFormChange(event: any) { + this.amendedData = event; + } + + checkForms(): void { + const forms = this.sections.map((section) => section.form) as Array; + + this.isFormDirty = forms.some((form) => form.dirty); + + this.setErrors(forms); + + this.isFormInvalid = forms.some((form) => form.invalid); + } + + setErrors(forms: Array): void { + const errors: GlobalError[] = []; + + forms.forEach((form) => DynamicFormService.validate(form, errors)); + + if (errors.length) { + this.globalErrorService.setErrors(errors); + return; + } + + this.globalErrorService.clearErrors(); + } + + handleSubmit() { + this.checkForms(); + + if (this.isFormInvalid) return; + + this.store.dispatch( + amendReferenceDataItem({ + resourceType: this.type, + resourceKey: encodeURIComponent(String(this.key)), + payload: this.amendedData, + }) + ); + + this.sections.forEach((form) => { + form.ngOnDestroy(); + }); + + this.navigateBack(); + } } diff --git a/src/app/features/reference-data/reference-data-delete/reference-data-delete.component.spec.ts b/src/app/features/reference-data/reference-data-delete/reference-data-delete.component.spec.ts index 1f3c01b783..de0205b757 100644 --- a/src/app/features/reference-data/reference-data-delete/reference-data-delete.component.spec.ts +++ b/src/app/features/reference-data/reference-data-delete/reference-data-delete.component.spec.ts @@ -11,96 +11,96 @@ import { State, initialAppState } from '@store/.'; import { ReferenceDataDeleteComponent } from './reference-data-delete.component'; describe('ReferenceDataAddComponent', () => { - let component: ReferenceDataDeleteComponent; - let fixture: ComponentFixture; - let store: MockStore; - let router: Router; - let route: ActivatedRoute; - let errorService: GlobalErrorService; + let component: ReferenceDataDeleteComponent; + let fixture: ComponentFixture; + let store: MockStore; + let router: Router; + let route: ActivatedRoute; + let errorService: GlobalErrorService; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ReferenceDataDeleteComponent], - imports: [RouterTestingModule, HttpClientTestingModule], - providers: [ - GlobalErrorService, - provideMockStore({ initialState: initialAppState }), - ReferenceDataService, - { provide: UserService, useValue: {} }, - ], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ReferenceDataDeleteComponent], + imports: [RouterTestingModule, HttpClientTestingModule], + providers: [ + GlobalErrorService, + provideMockStore({ initialState: initialAppState }), + ReferenceDataService, + { provide: UserService, useValue: {} }, + ], + }).compileComponents(); + }); - beforeEach(() => { - store = TestBed.inject(MockStore); - fixture = TestBed.createComponent(ReferenceDataDeleteComponent); - component = fixture.componentInstance; - router = TestBed.inject(Router); - route = TestBed.inject(ActivatedRoute); - errorService = TestBed.inject(GlobalErrorService); - fixture.detectChanges(); - }); + beforeEach(() => { + store = TestBed.inject(MockStore); + fixture = TestBed.createComponent(ReferenceDataDeleteComponent); + component = fixture.componentInstance; + router = TestBed.inject(Router); + route = TestBed.inject(ActivatedRoute); + errorService = TestBed.inject(GlobalErrorService); + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); - describe('navigateBack', () => { - it('should clear all errors', () => { - jest.spyOn(router, 'navigate').mockImplementation(); + it('should create', () => { + expect(component).toBeTruthy(); + }); + describe('navigateBack', () => { + it('should clear all errors', () => { + jest.spyOn(router, 'navigate').mockImplementation(); - const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); + const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); - component.navigateBack(); + component.navigateBack(); - expect(clearErrorsSpy).toHaveBeenCalledTimes(1); - }); + expect(clearErrorsSpy).toHaveBeenCalledTimes(1); + }); - it('should navigate back to the previous page', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + it('should navigate back to the previous page', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - component.navigateBack(); + component.navigateBack(); - expect(navigateSpy).toHaveBeenCalledWith(['../..'], { relativeTo: route }); - }); - }); - describe('handleFormChange', () => { - it('should change reason for deletion to the form value', () => { - component.handleFormChange({ reason: 'test reason' }); + expect(navigateSpy).toHaveBeenCalledWith(['../..'], { relativeTo: route }); + }); + }); + describe('handleFormChange', () => { + it('should change reason for deletion to the form value', () => { + component.handleFormChange({ reason: 'test reason' }); - expect(component.reasonForDeletion).toEqual({ reason: 'test reason' }); - }); - }); - describe('handleSubmit', () => { - it('will not dispatch there is no reason for deletion', () => { - component.type = ReferenceDataResourceType.CountryOfRegistration; - const dispatch = jest.spyOn(store, 'dispatch'); + expect(component.reasonForDeletion).toEqual({ reason: 'test reason' }); + }); + }); + describe('handleSubmit', () => { + it('will not dispatch there is no reason for deletion', () => { + component.type = ReferenceDataResourceType.CountryOfRegistration; + const dispatch = jest.spyOn(store, 'dispatch'); - component.handleSubmit(); + component.handleSubmit(); - expect(dispatch).not.toHaveBeenCalledWith({ - reason: 'test reason', - resourceKey: 'testkey', - resourceType: 'COUNTRY_OF_REGISTRATION', - type: '[API/reference-data] deleteReferenceDataItem', - }); - }); - it('will dispatches if there is a reason and type defined', () => { - fixture.ngZone?.run(() => { - component.type = ReferenceDataResourceType.CountryOfRegistration; - component.key = 'testkey'; - component.handleFormChange({ reason: 'test reason' }); - const dispatch = jest.spyOn(store, 'dispatch'); + expect(dispatch).not.toHaveBeenCalledWith({ + reason: 'test reason', + resourceKey: 'testkey', + resourceType: 'COUNTRY_OF_REGISTRATION', + type: '[API/reference-data] deleteReferenceDataItem', + }); + }); + it('will dispatches if there is a reason and type defined', () => { + fixture.ngZone?.run(() => { + component.type = ReferenceDataResourceType.CountryOfRegistration; + component.key = 'testkey'; + component.handleFormChange({ reason: 'test reason' }); + const dispatch = jest.spyOn(store, 'dispatch'); - component.handleSubmit(); + component.handleSubmit(); - expect(dispatch).toHaveBeenCalled(); - expect(dispatch).toHaveBeenCalledWith({ - reason: 'test reason', - resourceKey: 'testkey', - resourceType: 'COUNTRY_OF_REGISTRATION', - type: '[API/reference-data] deleteReferenceDataItem', - }); - }); - }); - }); + expect(dispatch).toHaveBeenCalled(); + expect(dispatch).toHaveBeenCalledWith({ + reason: 'test reason', + resourceKey: 'testkey', + resourceType: 'COUNTRY_OF_REGISTRATION', + type: '[API/reference-data] deleteReferenceDataItem', + }); + }); + }); + }); }); diff --git a/src/app/features/reference-data/reference-data-delete/reference-data-delete.component.ts b/src/app/features/reference-data/reference-data-delete/reference-data-delete.component.ts index 420d2f97bc..5b6dc49978 100644 --- a/src/app/features/reference-data/reference-data-delete/reference-data-delete.component.ts +++ b/src/app/features/reference-data/reference-data-delete/reference-data-delete.component.ts @@ -1,144 +1,145 @@ -import { - Component, OnInit, QueryList, ViewChildren, -} from '@angular/core'; +import { Component, OnInit, QueryList, ViewChildren } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalError } from '@core/components/global-error/global-error.interface'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { DynamicFormGroupComponent } from '@forms/components/dynamic-form-group/dynamic-form-group.component'; import { ValidatorNames } from '@forms/models/validators.enum'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; -import { - CustomFormGroup, FormNodeEditTypes, FormNodeTypes, FormNodeWidth, -} from '@forms/services/dynamic-form.types'; +import { CustomFormGroup, FormNodeEditTypes, FormNodeTypes, FormNodeWidth } from '@forms/services/dynamic-form.types'; import { ReferenceDataResourceType } from '@models/reference-data.model'; import { Roles } from '@models/roles.enum'; import { Store, select } from '@ngrx/store'; import { ReferenceDataService } from '@services/reference-data/reference-data.service'; import { - ReferenceDataState, deleteReferenceDataItem, fetchReferenceDataByKey, selectReferenceDataByResourceKey, + ReferenceDataState, + deleteReferenceDataItem, + fetchReferenceDataByKey, + selectReferenceDataByResourceKey, } from '@store/reference-data'; import { Observable, take } from 'rxjs'; @Component({ - selector: 'app-reference-data-delete', - templateUrl: './reference-data-delete.component.html', + selector: 'app-reference-data-delete', + templateUrl: './reference-data-delete.component.html', }) export class ReferenceDataDeleteComponent implements OnInit { - type!: ReferenceDataResourceType; - key!: string; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - reasonForDeletion: any; - isFormDirty = false; - isFormInvalid = true; - - reasonTemplate = { - name: 'reason-for-deletion', - type: FormNodeTypes.GROUP, - label: 'reason', - children: [ - { - name: 'reason', - label: 'Reason for Deletion', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXTAREA, - validators: [ - { - name: ValidatorNames.Required, - }, - ], - }, - ], - }; - - @ViewChildren(DynamicFormGroupComponent) sections!: QueryList; - - constructor( - public globalErrorService: GlobalErrorService, - private referenceDataService: ReferenceDataService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - ) {} - - ngOnInit(): void { - this.route.parent?.params.pipe(take(1)).subscribe((params) => { - this.type = params['type']; - - this.referenceDataService.loadReferenceDataByKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type); - }); - - this.route.params.pipe(take(1)).subscribe((params) => { - this.key = decodeURIComponent(params['key']); - - if (this.type && this.key) { - this.store.dispatch(fetchReferenceDataByKey({ resourceType: this.type, resourceKey: this.key })); - } - }); - } - - get roles(): typeof Roles { - return Roles; - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - get refData$(): Observable { - return this.store.pipe(select(selectReferenceDataByResourceKey(this.type, decodeURIComponent(this.key)))); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - get refDataAdminType$(): Observable { - return this.store.pipe(select(selectReferenceDataByResourceKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type))); - } - - get widths(): typeof FormNodeWidth { - return FormNodeWidth; - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - handleFormChange(event: any) { - this.reasonForDeletion = event; - } - - checkForms(): void { - const forms = this.sections.map((section) => section.form) as Array; - - this.isFormDirty = forms.some((form) => form.dirty); - - this.setErrors(forms); - - this.isFormInvalid = forms.some((form) => form.invalid); - } - - setErrors(forms: Array): void { - const errors: GlobalError[] = []; - - forms.forEach((form) => DynamicFormService.validate(form, errors)); - - if (errors.length) { - this.globalErrorService.setErrors(errors); - return; - } - - this.globalErrorService.clearErrors(); - } - - navigateBack() { - this.globalErrorService.clearErrors(); - void this.router.navigate(['../..'], { relativeTo: this.route }); - } - - handleSubmit() { - this.checkForms(); - - if (this.isFormInvalid || !this.reasonForDeletion) return; - - this.store.dispatch( - deleteReferenceDataItem({ - resourceType: this.type, - resourceKey: this.key, - reason: this.reasonForDeletion.reason, - }), - ); - this.navigateBack(); - } + type!: ReferenceDataResourceType; + key!: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + reasonForDeletion: any; + isFormDirty = false; + isFormInvalid = true; + + reasonTemplate = { + name: 'reason-for-deletion', + type: FormNodeTypes.GROUP, + label: 'reason', + children: [ + { + name: 'reason', + label: 'Reason for Deletion', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXTAREA, + validators: [ + { + name: ValidatorNames.Required, + }, + ], + }, + ], + }; + + @ViewChildren(DynamicFormGroupComponent) sections!: QueryList; + + constructor( + public globalErrorService: GlobalErrorService, + private referenceDataService: ReferenceDataService, + private route: ActivatedRoute, + private router: Router, + private store: Store + ) {} + + ngOnInit(): void { + this.route.parent?.params.pipe(take(1)).subscribe((params) => { + this.type = params['type']; + + this.referenceDataService.loadReferenceDataByKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type); + }); + + this.route.params.pipe(take(1)).subscribe((params) => { + this.key = decodeURIComponent(params['key']); + + if (this.type && this.key) { + this.store.dispatch(fetchReferenceDataByKey({ resourceType: this.type, resourceKey: this.key })); + } + }); + } + + get roles(): typeof Roles { + return Roles; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + get refData$(): Observable { + return this.store.pipe(select(selectReferenceDataByResourceKey(this.type, decodeURIComponent(this.key)))); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + get refDataAdminType$(): Observable { + return this.store.pipe( + select(selectReferenceDataByResourceKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type)) + ); + } + + get widths(): typeof FormNodeWidth { + return FormNodeWidth; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + handleFormChange(event: any) { + this.reasonForDeletion = event; + } + + checkForms(): void { + const forms = this.sections.map((section) => section.form) as Array; + + this.isFormDirty = forms.some((form) => form.dirty); + + this.setErrors(forms); + + this.isFormInvalid = forms.some((form) => form.invalid); + } + + setErrors(forms: Array): void { + const errors: GlobalError[] = []; + + forms.forEach((form) => DynamicFormService.validate(form, errors)); + + if (errors.length) { + this.globalErrorService.setErrors(errors); + return; + } + + this.globalErrorService.clearErrors(); + } + + navigateBack() { + this.globalErrorService.clearErrors(); + void this.router.navigate(['../..'], { relativeTo: this.route }); + } + + handleSubmit() { + this.checkForms(); + + if (this.isFormInvalid || !this.reasonForDeletion) return; + + this.store.dispatch( + deleteReferenceDataItem({ + resourceType: this.type, + resourceKey: this.key, + reason: this.reasonForDeletion.reason, + }) + ); + this.navigateBack(); + } } diff --git a/src/app/features/reference-data/reference-data-deleted-list/reference-data-deleted-list.component.spec.ts b/src/app/features/reference-data/reference-data-deleted-list/reference-data-deleted-list.component.spec.ts index adc3a94fea..8ea4c02b9e 100644 --- a/src/app/features/reference-data/reference-data-deleted-list/reference-data-deleted-list.component.spec.ts +++ b/src/app/features/reference-data/reference-data-deleted-list/reference-data-deleted-list.component.spec.ts @@ -13,29 +13,33 @@ import { of } from 'rxjs'; import { ReferenceDataDeletedListComponent } from './reference-data-deleted-list.component'; describe('DataTypeListComponent', () => { - let component: ReferenceDataDeletedListComponent; - let fixture: ComponentFixture; + let component: ReferenceDataDeletedListComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ReferenceDataDeletedListComponent, RoleRequiredDirective, PaginationComponent], - imports: [RouterTestingModule, HttpClientTestingModule, HttpClientModule], - providers: [provideMockStore({ initialState: initialAppState }), ReferenceDataService, { - provide: UserService, - useValue: { - roles$: of([Roles.ReferenceDataView]), - }, - }], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ReferenceDataDeletedListComponent, RoleRequiredDirective, PaginationComponent], + imports: [RouterTestingModule, HttpClientTestingModule, HttpClientModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + ReferenceDataService, + { + provide: UserService, + useValue: { + roles$: of([Roles.ReferenceDataView]), + }, + }, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(ReferenceDataDeletedListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(ReferenceDataDeletedListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/features/reference-data/reference-data-deleted-list/reference-data-deleted-list.component.ts b/src/app/features/reference-data/reference-data-deleted-list/reference-data-deleted-list.component.ts index f986c65371..2427f4a3ab 100644 --- a/src/app/features/reference-data/reference-data-deleted-list/reference-data-deleted-list.component.ts +++ b/src/app/features/reference-data/reference-data-deleted-list/reference-data-deleted-list.component.ts @@ -8,55 +8,57 @@ import { fetchReferenceDataAudit, selectReferenceDataByResourceKey, selectSearch import { Observable, map, take } from 'rxjs'; @Component({ - selector: 'app-reference-data-deleted-list', - templateUrl: './reference-data-deleted-list.component.html', + selector: 'app-reference-data-deleted-list', + templateUrl: './reference-data-deleted-list.component.html', }) export class ReferenceDataDeletedListComponent implements OnInit { - type!: ReferenceDataResourceType; - pageStart?: number; - pageEnd?: number; - - constructor( - private referenceDataService: ReferenceDataService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - private cdr: ChangeDetectorRef, - ) {} - - ngOnInit(): void { - this.route.parent?.params.pipe(take(1)).subscribe((params) => { - this.type = params['type']; - this.referenceDataService.loadReferenceDataByKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type); - this.store.dispatch(fetchReferenceDataAudit({ resourceType: (`${this.type}#AUDIT`) as ReferenceDataResourceType })); - }); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - get refDataAdminType$(): Observable { - return this.store.pipe(select(selectReferenceDataByResourceKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type))); - } - - get data$(): Observable { - return this.store.pipe(select(selectSearchReturn((`${this.type}#AUDIT`) as ReferenceDataResourceType))); - } - - get roles(): typeof Roles { - return Roles; - } - - handlePaginationChange({ start, end }: { start: number; end: number }) { - this.pageStart = start; - this.pageEnd = end; - this.cdr.detectChanges(); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - get paginatedItems$(): Observable { - return this.data$.pipe(map((items) => items?.slice(this.pageStart, this.pageEnd) ?? [])); - } - - get numberOfRecords$(): Observable { - return this.data$.pipe(map((items) => items?.length ?? 0)); - } + type!: ReferenceDataResourceType; + pageStart?: number; + pageEnd?: number; + + constructor( + private referenceDataService: ReferenceDataService, + private route: ActivatedRoute, + private router: Router, + private store: Store, + private cdr: ChangeDetectorRef + ) {} + + ngOnInit(): void { + this.route.parent?.params.pipe(take(1)).subscribe((params) => { + this.type = params['type']; + this.referenceDataService.loadReferenceDataByKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type); + this.store.dispatch(fetchReferenceDataAudit({ resourceType: `${this.type}#AUDIT` as ReferenceDataResourceType })); + }); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + get refDataAdminType$(): Observable { + return this.store.pipe( + select(selectReferenceDataByResourceKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type)) + ); + } + + get data$(): Observable { + return this.store.pipe(select(selectSearchReturn(`${this.type}#AUDIT` as ReferenceDataResourceType))); + } + + get roles(): typeof Roles { + return Roles; + } + + handlePaginationChange({ start, end }: { start: number; end: number }) { + this.pageStart = start; + this.pageEnd = end; + this.cdr.detectChanges(); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + get paginatedItems$(): Observable { + return this.data$.pipe(map((items) => items?.slice(this.pageStart, this.pageEnd) ?? [])); + } + + get numberOfRecords$(): Observable { + return this.data$.pipe(map((items) => items?.length ?? 0)); + } } diff --git a/src/app/features/reference-data/reference-data-list/reference-data-list.component.spec.ts b/src/app/features/reference-data/reference-data-list/reference-data-list.component.spec.ts index 650be5e0f0..ca02ef1826 100644 --- a/src/app/features/reference-data/reference-data-list/reference-data-list.component.spec.ts +++ b/src/app/features/reference-data/reference-data-list/reference-data-list.component.spec.ts @@ -17,145 +17,151 @@ import * as refSelectors from '../../../store/reference-data/selectors/reference import { ReferenceDataListComponent } from './reference-data-list.component'; describe('DataTypeListComponent', () => { - let component: ReferenceDataListComponent; - let fixture: ComponentFixture; - let router: Router; - let errorService: GlobalErrorService; - let route: ActivatedRoute; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ReferenceDataListComponent, RoleRequiredDirective], - imports: [RouterTestingModule, HttpClientTestingModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - ReferenceDataService, - GlobalErrorService, - { provide: UserService, useValue: { roles$: of([Roles.ReferenceDataView]) } }, - ], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ReferenceDataListComponent); - component = fixture.componentInstance; - route = TestBed.inject(ActivatedRoute); - router = TestBed.inject(Router); - errorService = TestBed.inject(GlobalErrorService); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - describe('amend', () => { - it('should navigate to the selected items key', () => { - fixture.ngZone?.run(() => { - const navigateSpy = jest.spyOn(router, 'navigate'); - - component.amend({ resourceKey: 'foo', resourceType: ReferenceDataResourceType.CountryOfRegistration }); - - expect(navigateSpy).toHaveBeenCalledWith(['foo'], { relativeTo: route }); - }); - }); - }); - describe('delete', () => { - it('should navigate to the selected items :key/delete', () => { - fixture.ngZone?.run(() => { - const navigateSpy = jest.spyOn(router, 'navigate'); - - component.delete({ resourceKey: 'foo', resourceType: ReferenceDataResourceType.CountryOfRegistration }); - - expect(navigateSpy).toHaveBeenCalledWith(['foo/delete'], { relativeTo: route }); - }); - }); - }); - describe('addNew', () => { - it('should navigate to the selected items create', () => { - fixture.ngZone?.run(() => { - const navigateSpy = jest.spyOn(router, 'navigate'); - - component.addNew(); - - expect(navigateSpy).toHaveBeenCalledWith(['create'], { relativeTo: route }); - }); - }); - }); - describe('navigateToDeletedItems', () => { - it('should navigate to the selected items create', () => { - fixture.ngZone?.run(() => { - const navigateSpy = jest.spyOn(router, 'navigate'); - - component.navigateToDeletedItems(); - - expect(navigateSpy).toHaveBeenCalledWith(['deleted-items'], { relativeTo: route }); - }); - }); - }); - describe('handlePaginationChange', () => { - it('should set the start and end pages', () => { - component.handlePaginationChange({ start: 0, end: 24 }); - - expect(component.pageStart).toBe(0); - expect(component.pageEnd).toBe(24); - }); - }); - describe('clear', () => { - it('should reset the form', () => { - component.form.controls['term'].patchValue('foo'); - expect(component.form.controls['term'].value).toBe('foo'); - - component.clear(); - expect(component.form.controls['term'].value).toBeNull(); - }); - it('should navigate to page 1 of pagination', () => { - fixture.ngZone?.run(() => { - const navigateSpy = jest.spyOn(router, 'navigate'); - component.type = ReferenceDataResourceType.Tyres; - component.searchReturned = true; - component.clear(); - - expect(navigateSpy).toHaveBeenCalledWith(['../TYRES'], { relativeTo: route, queryParams: { 'reference-data-items-page': 1 } }); - }); - }); - }); - - describe('search', () => { - it('should call add error if there is no search term', () => { - const errorSpy = jest.spyOn(errorService, 'addError'); - component.search('', 'tyreCode'); - - expect(errorSpy).toHaveBeenCalled(); - }); - it('should call add error if there is no filter', () => { - const errorSpy = jest.spyOn(errorService, 'addError'); - component.search('term', ''); - - expect(errorSpy).toHaveBeenCalled(); - }); - it('should call add error if there are no items returned', () => { - const errorSpy = jest.spyOn(errorService, 'addError'); - component.type = ReferenceDataResourceType.Tyres; - - component.search('term', 'brakeCode'); - - expect(errorSpy).toHaveBeenCalled(); - }); - it('should navigate to page 1 of pagination', () => { - fixture.ngZone?.run(() => { - const navigateSpy = jest.spyOn(router, 'navigate'); - component.type = ReferenceDataResourceType.Tyres; - component.searchReturned = true; - jest.spyOn(refSelectors, 'selectRefDataBySearchTerm').mockReturnValue( - createSelector( - (v) => v, - () => [{ resourceKey: 'foo', resourceType: 'bar' }] as ReferenceDataItem[] | undefined, - ), - ); - component.search('foo', 'bar'); - - expect(navigateSpy).toHaveBeenCalledWith(['../TYRES'], { relativeTo: route, queryParams: { 'reference-data-items-page': 1 } }); - }); - }); - }); + let component: ReferenceDataListComponent; + let fixture: ComponentFixture; + let router: Router; + let errorService: GlobalErrorService; + let route: ActivatedRoute; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ReferenceDataListComponent, RoleRequiredDirective], + imports: [RouterTestingModule, HttpClientTestingModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + ReferenceDataService, + GlobalErrorService, + { provide: UserService, useValue: { roles$: of([Roles.ReferenceDataView]) } }, + ], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ReferenceDataListComponent); + component = fixture.componentInstance; + route = TestBed.inject(ActivatedRoute); + router = TestBed.inject(Router); + errorService = TestBed.inject(GlobalErrorService); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + describe('amend', () => { + it('should navigate to the selected items key', () => { + fixture.ngZone?.run(() => { + const navigateSpy = jest.spyOn(router, 'navigate'); + + component.amend({ resourceKey: 'foo', resourceType: ReferenceDataResourceType.CountryOfRegistration }); + + expect(navigateSpy).toHaveBeenCalledWith(['foo'], { relativeTo: route }); + }); + }); + }); + describe('delete', () => { + it('should navigate to the selected items :key/delete', () => { + fixture.ngZone?.run(() => { + const navigateSpy = jest.spyOn(router, 'navigate'); + + component.delete({ resourceKey: 'foo', resourceType: ReferenceDataResourceType.CountryOfRegistration }); + + expect(navigateSpy).toHaveBeenCalledWith(['foo/delete'], { relativeTo: route }); + }); + }); + }); + describe('addNew', () => { + it('should navigate to the selected items create', () => { + fixture.ngZone?.run(() => { + const navigateSpy = jest.spyOn(router, 'navigate'); + + component.addNew(); + + expect(navigateSpy).toHaveBeenCalledWith(['create'], { relativeTo: route }); + }); + }); + }); + describe('navigateToDeletedItems', () => { + it('should navigate to the selected items create', () => { + fixture.ngZone?.run(() => { + const navigateSpy = jest.spyOn(router, 'navigate'); + + component.navigateToDeletedItems(); + + expect(navigateSpy).toHaveBeenCalledWith(['deleted-items'], { relativeTo: route }); + }); + }); + }); + describe('handlePaginationChange', () => { + it('should set the start and end pages', () => { + component.handlePaginationChange({ start: 0, end: 24 }); + + expect(component.pageStart).toBe(0); + expect(component.pageEnd).toBe(24); + }); + }); + describe('clear', () => { + it('should reset the form', () => { + component.form.controls['term'].patchValue('foo'); + expect(component.form.controls['term'].value).toBe('foo'); + + component.clear(); + expect(component.form.controls['term'].value).toBeNull(); + }); + it('should navigate to page 1 of pagination', () => { + fixture.ngZone?.run(() => { + const navigateSpy = jest.spyOn(router, 'navigate'); + component.type = ReferenceDataResourceType.Tyres; + component.searchReturned = true; + component.clear(); + + expect(navigateSpy).toHaveBeenCalledWith(['../TYRES'], { + relativeTo: route, + queryParams: { 'reference-data-items-page': 1 }, + }); + }); + }); + }); + + describe('search', () => { + it('should call add error if there is no search term', () => { + const errorSpy = jest.spyOn(errorService, 'addError'); + component.search('', 'tyreCode'); + + expect(errorSpy).toHaveBeenCalled(); + }); + it('should call add error if there is no filter', () => { + const errorSpy = jest.spyOn(errorService, 'addError'); + component.search('term', ''); + + expect(errorSpy).toHaveBeenCalled(); + }); + it('should call add error if there are no items returned', () => { + const errorSpy = jest.spyOn(errorService, 'addError'); + component.type = ReferenceDataResourceType.Tyres; + + component.search('term', 'brakeCode'); + + expect(errorSpy).toHaveBeenCalled(); + }); + it('should navigate to page 1 of pagination', () => { + fixture.ngZone?.run(() => { + const navigateSpy = jest.spyOn(router, 'navigate'); + component.type = ReferenceDataResourceType.Tyres; + component.searchReturned = true; + jest.spyOn(refSelectors, 'selectRefDataBySearchTerm').mockReturnValue( + createSelector( + (v) => v, + () => [{ resourceKey: 'foo', resourceType: 'bar' }] as ReferenceDataItem[] | undefined + ) + ); + component.search('foo', 'bar'); + + expect(navigateSpy).toHaveBeenCalledWith(['../TYRES'], { + relativeTo: route, + queryParams: { 'reference-data-items-page': 1 }, + }); + }); + }); + }); }); diff --git a/src/app/features/reference-data/reference-data-list/reference-data-list.component.ts b/src/app/features/reference-data/reference-data-list/reference-data-list.component.ts index d5627500fd..5dd21cbc39 100644 --- a/src/app/features/reference-data/reference-data-list/reference-data-list.component.ts +++ b/src/app/features/reference-data/reference-data-list/reference-data-list.component.ts @@ -1,6 +1,4 @@ -import { - ChangeDetectorRef, Component, OnDestroy, OnInit, -} from '@angular/core'; +import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; @@ -9,178 +7,186 @@ import { ReferenceDataModelBase, ReferenceDataResourceType } from '@models/refer import { Roles } from '@models/roles.enum'; import { Store, select } from '@ngrx/store'; import { ReferenceDataService } from '@services/reference-data/reference-data.service'; -import { selectAllReferenceDataByResourceType, selectRefDataBySearchTerm, selectReferenceDataByResourceKey } from '@store/reference-data'; import { - Observable, Subject, catchError, filter, map, of, switchMap, take, -} from 'rxjs'; + selectAllReferenceDataByResourceType, + selectRefDataBySearchTerm, + selectReferenceDataByResourceKey, +} from '@store/reference-data'; +import { Observable, Subject, catchError, filter, map, of, switchMap, take } from 'rxjs'; @Component({ - selector: 'app-reference-data-list', - templateUrl: './reference-data-list.component.html', - styleUrls: ['./reference-data-list.component.scss'], + selector: 'app-reference-data-list', + templateUrl: './reference-data-list.component.html', + styleUrls: ['./reference-data-list.component.scss'], }) export class ReferenceDataListComponent implements OnInit, OnDestroy { - type!: ReferenceDataResourceType; - disabled = true; - pageStart?: number; - pageEnd?: number; - currentPage?: number; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - data?: Observable | undefined>; - private destroy$ = new Subject(); - - public form!: CustomFormGroup; - public searchReturned = false; - - public searchTemplate: FormNode = { - name: 'criteria', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'filter', - label: 'Search filter', - value: '', - type: FormNodeTypes.CONTROL, - }, - { - name: 'term', - value: '', - type: FormNodeTypes.CONTROL, - }, - ], - }; - - constructor( - private referenceDataService: ReferenceDataService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - private cdr: ChangeDetectorRef, - private globalErrorService: GlobalErrorService, - public dfs: DynamicFormService, - ) {} - - ngOnInit(): void { - this.form = this.dfs.createForm(this.searchTemplate) as CustomFormGroup; - this.route.params.pipe(take(1)).subscribe((params) => { - this.type = params['type']; - this.referenceDataService.loadReferenceData(this.type); - this.referenceDataService.loadReferenceDataByKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type); - }); - - this.globalErrorService.errors$ - .pipe( - take(1), - filter((errors) => !errors.length), - switchMap(() => - this.referenceDataService.fetchReferenceDataAudit(`${this.type}#AUDIT` as ReferenceDataResourceType).pipe( - map((array) => - array.data.map((item) => { - if (item.reason !== undefined) { - this.disabled = false; - } - })), - )), - catchError((error) => { - if (error.status === 404) { - this.disabled = true; - return of(true); - } - return of(false); - }), - ) - .subscribe({ - next: (res) => of(!!res), - }); - this.data = this.store.pipe(select(selectAllReferenceDataByResourceType(this.type))); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - get refDataAdminType$(): Observable { - return this.store.pipe(select(selectReferenceDataByResourceKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type))); - } - - public get roles(): typeof Roles { - return Roles; - } - - addNew(): void { - void this.router.navigate(['create'], { relativeTo: this.route }).then(() => { - window.location.reload(); - }); - } - - navigateToDeletedItems(): void { - void this.router.navigate(['deleted-items'], { relativeTo: this.route }); - } - - amend(item: ReferenceDataModelBase): void { - const key = encodeURIComponent(String(item.resourceKey)); - void this.router.navigate([key], { relativeTo: this.route }).then(() => { - window.location.reload(); - }); - } - - delete(item: ReferenceDataModelBase): void { - const key = encodeURIComponent(String(item.resourceKey)); - void this.router.navigate([`${key}/delete`], { relativeTo: this.route }); - } - - handlePaginationChange({ start, end }: { start: number; end: number }) { - this.pageStart = start; - this.pageEnd = end; - this.cdr.detectChanges(); - } - - get paginatedItems$() { - return (this.data ?? of([])).pipe(map((items) => items?.slice(this.pageStart, this.pageEnd) ?? [])); - } - - get numberOfRecords$() { - return (this.data ?? of([])).pipe(map((items) => items?.length ?? 0)); - } - - search(term: string, filterterm: string) { - this.globalErrorService.clearErrors(); - const trimmedTerm = term?.trim(); - if (!trimmedTerm || !filterterm) { - const error = !trimmedTerm - ? { error: 'You must provide a search term', anchorLink: 'refSearch' } - : { error: 'You must select a valid search filter', anchorLink: 'filter' }; - this.globalErrorService.addError(error); - return; - } - - this.store.pipe(select(selectRefDataBySearchTerm(trimmedTerm, this.type, filterterm)), take(1)).subscribe((items) => { - if (!items?.length) { - this.globalErrorService.addError({ error: 'Your search returned no results', anchorLink: 'refSearch' }); - this.data = of([]); - } else { - this.data = of(items); - void this.router.navigate([`../${this.type}`], { - relativeTo: this.route, - queryParams: { 'reference-data-items-page': 1 }, - }); - } - this.searchReturned = true; - }); - } - - clear() { - this.form.reset(); - this.globalErrorService.clearErrors(); - if (this.searchReturned) { - this.data = this.store.pipe(select(selectAllReferenceDataByResourceType(this.type))); - void this.router.navigate([`../${this.type}`], { - relativeTo: this.route, - queryParams: { 'reference-data-items-page': 1 }, - }); - this.searchReturned = false; - } - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } + type!: ReferenceDataResourceType; + disabled = true; + pageStart?: number; + pageEnd?: number; + currentPage?: number; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data?: Observable | undefined>; + private destroy$ = new Subject(); + + public form!: CustomFormGroup; + public searchReturned = false; + + public searchTemplate: FormNode = { + name: 'criteria', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'filter', + label: 'Search filter', + value: '', + type: FormNodeTypes.CONTROL, + }, + { + name: 'term', + value: '', + type: FormNodeTypes.CONTROL, + }, + ], + }; + + constructor( + private referenceDataService: ReferenceDataService, + private route: ActivatedRoute, + private router: Router, + private store: Store, + private cdr: ChangeDetectorRef, + private globalErrorService: GlobalErrorService, + public dfs: DynamicFormService + ) {} + + ngOnInit(): void { + this.form = this.dfs.createForm(this.searchTemplate) as CustomFormGroup; + this.route.params.pipe(take(1)).subscribe((params) => { + this.type = params['type']; + this.referenceDataService.loadReferenceData(this.type); + this.referenceDataService.loadReferenceDataByKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type); + }); + + this.globalErrorService.errors$ + .pipe( + take(1), + filter((errors) => !errors.length), + switchMap(() => + this.referenceDataService.fetchReferenceDataAudit(`${this.type}#AUDIT` as ReferenceDataResourceType).pipe( + map((array) => + array.data.map((item) => { + if (item.reason !== undefined) { + this.disabled = false; + } + }) + ) + ) + ), + catchError((error) => { + if (error.status === 404) { + this.disabled = true; + return of(true); + } + return of(false); + }) + ) + .subscribe({ + next: (res) => of(!!res), + }); + this.data = this.store.pipe(select(selectAllReferenceDataByResourceType(this.type))); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + get refDataAdminType$(): Observable { + return this.store.pipe( + select(selectReferenceDataByResourceKey(ReferenceDataResourceType.ReferenceDataAdminType, this.type)) + ); + } + + public get roles(): typeof Roles { + return Roles; + } + + addNew(): void { + void this.router.navigate(['create'], { relativeTo: this.route }).then(() => { + window.location.reload(); + }); + } + + navigateToDeletedItems(): void { + void this.router.navigate(['deleted-items'], { relativeTo: this.route }); + } + + amend(item: ReferenceDataModelBase): void { + const key = encodeURIComponent(String(item.resourceKey)); + void this.router.navigate([key], { relativeTo: this.route }).then(() => { + window.location.reload(); + }); + } + + delete(item: ReferenceDataModelBase): void { + const key = encodeURIComponent(String(item.resourceKey)); + void this.router.navigate([`${key}/delete`], { relativeTo: this.route }); + } + + handlePaginationChange({ start, end }: { start: number; end: number }) { + this.pageStart = start; + this.pageEnd = end; + this.cdr.detectChanges(); + } + + get paginatedItems$() { + return (this.data ?? of([])).pipe(map((items) => items?.slice(this.pageStart, this.pageEnd) ?? [])); + } + + get numberOfRecords$() { + return (this.data ?? of([])).pipe(map((items) => items?.length ?? 0)); + } + + search(term: string, filterterm: string) { + this.globalErrorService.clearErrors(); + const trimmedTerm = term?.trim(); + if (!trimmedTerm || !filterterm) { + const error = !trimmedTerm + ? { error: 'You must provide a search term', anchorLink: 'refSearch' } + : { error: 'You must select a valid search filter', anchorLink: 'filter' }; + this.globalErrorService.addError(error); + return; + } + + this.store + .pipe(select(selectRefDataBySearchTerm(trimmedTerm, this.type, filterterm)), take(1)) + .subscribe((items) => { + if (!items?.length) { + this.globalErrorService.addError({ error: 'Your search returned no results', anchorLink: 'refSearch' }); + this.data = of([]); + } else { + this.data = of(items); + void this.router.navigate([`../${this.type}`], { + relativeTo: this.route, + queryParams: { 'reference-data-items-page': 1 }, + }); + } + this.searchReturned = true; + }); + } + + clear() { + this.form.reset(); + this.globalErrorService.clearErrors(); + if (this.searchReturned) { + this.data = this.store.pipe(select(selectAllReferenceDataByResourceType(this.type))); + void this.router.navigate([`../${this.type}`], { + relativeTo: this.route, + queryParams: { 'reference-data-items-page': 1 }, + }); + this.searchReturned = false; + } + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } } diff --git a/src/app/features/reference-data/reference-data-routing.module.ts b/src/app/features/reference-data/reference-data-routing.module.ts index 3210bdf8a7..d04c2c1002 100644 --- a/src/app/features/reference-data/reference-data-routing.module.ts +++ b/src/app/features/reference-data/reference-data-routing.module.ts @@ -3,8 +3,8 @@ import { RouterModule, Routes } from '@angular/router'; import { MsalGuard } from '@azure/msal-angular'; import { RoleGuard } from '@guards/role-guard/roles.guard'; import { Roles } from '@models/roles.enum'; -import { RouterOutletComponent } from '@shared/components/router-outlet/router-outlet.component'; import { ReferenceDataRoutes } from '@models/routes.enum'; +import { RouterOutletComponent } from '@shared/components/router-outlet/router-outlet.component'; import { ReferenceDataCreateComponent } from './reference-data-add/reference-data-add.component'; import { ReferenceDataAmendComponent } from './reference-data-amend/reference-data-amend.component'; import { ReferenceDataDeleteComponent } from './reference-data-delete/reference-data-delete.component'; @@ -13,61 +13,61 @@ import { ReferenceDataListComponent } from './reference-data-list/reference-data import { ReferenceDataSelectTypeComponent } from './reference-data-select-type/reference-data-select-type.component'; const routes: Routes = [ - { - path: '', - component: RouterOutletComponent, - data: { title: 'Select Reference Data Type', roles: Roles.ReferenceDataView }, - canActivate: [MsalGuard, RoleGuard], - children: [ - { - path: '', - component: ReferenceDataSelectTypeComponent, - data: { title: 'Select Reference Data Type', roles: Roles.ReferenceDataView }, - canActivate: [MsalGuard, RoleGuard], - }, - { - path: ReferenceDataRoutes.TYPE, - component: RouterOutletComponent, - data: { title: 'Search Reference Data', roles: Roles.ReferenceDataView }, - canActivate: [MsalGuard, RoleGuard], - children: [ - { - path: '', - component: ReferenceDataListComponent, - data: { title: 'Search Reference Data', roles: Roles.ReferenceDataView }, - canActivate: [MsalGuard, RoleGuard], - }, - { - path: ReferenceDataRoutes.CREATE, - component: ReferenceDataCreateComponent, - data: { title: 'Add Reference Data', roles: Roles.ReferenceDataAmend }, - canActivate: [MsalGuard, RoleGuard], - }, - { - path: ReferenceDataRoutes.DELETED_ITEMS, - component: ReferenceDataDeletedListComponent, - data: { title: 'View deleted Reference Data', roles: Roles.ReferenceDataView }, - canActivate: [MsalGuard, RoleGuard], - }, - { - path: ReferenceDataRoutes.KEY, - component: ReferenceDataAmendComponent, - data: { title: 'Amend Reference Data', roles: Roles.ReferenceDataAmend }, - canActivate: [MsalGuard, RoleGuard], - }, - { - path: ReferenceDataRoutes.DELETE, - component: ReferenceDataDeleteComponent, - data: { title: 'Delete Reference Data', roles: Roles.ReferenceDataAmend }, - canActivate: [MsalGuard, RoleGuard], - }, - ], - }, - ], - }, + { + path: '', + component: RouterOutletComponent, + data: { title: 'Select Reference Data Type', roles: Roles.ReferenceDataView }, + canActivate: [MsalGuard, RoleGuard], + children: [ + { + path: '', + component: ReferenceDataSelectTypeComponent, + data: { title: 'Select Reference Data Type', roles: Roles.ReferenceDataView }, + canActivate: [MsalGuard, RoleGuard], + }, + { + path: ReferenceDataRoutes.TYPE, + component: RouterOutletComponent, + data: { title: 'Search Reference Data', roles: Roles.ReferenceDataView }, + canActivate: [MsalGuard, RoleGuard], + children: [ + { + path: '', + component: ReferenceDataListComponent, + data: { title: 'Search Reference Data', roles: Roles.ReferenceDataView }, + canActivate: [MsalGuard, RoleGuard], + }, + { + path: ReferenceDataRoutes.CREATE, + component: ReferenceDataCreateComponent, + data: { title: 'Add Reference Data', roles: Roles.ReferenceDataAmend }, + canActivate: [MsalGuard, RoleGuard], + }, + { + path: ReferenceDataRoutes.DELETED_ITEMS, + component: ReferenceDataDeletedListComponent, + data: { title: 'View deleted Reference Data', roles: Roles.ReferenceDataView }, + canActivate: [MsalGuard, RoleGuard], + }, + { + path: ReferenceDataRoutes.KEY, + component: ReferenceDataAmendComponent, + data: { title: 'Amend Reference Data', roles: Roles.ReferenceDataAmend }, + canActivate: [MsalGuard, RoleGuard], + }, + { + path: ReferenceDataRoutes.DELETE, + component: ReferenceDataDeleteComponent, + data: { title: 'Delete Reference Data', roles: Roles.ReferenceDataAmend }, + canActivate: [MsalGuard, RoleGuard], + }, + ], + }, + ], + }, ]; @NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], }) export class ReferenceDataRoutingModule {} diff --git a/src/app/features/reference-data/reference-data-select-type/reference-data-select-type.component.spec.ts b/src/app/features/reference-data/reference-data-select-type/reference-data-select-type.component.spec.ts index 68287d3444..b118e4e9e1 100644 --- a/src/app/features/reference-data/reference-data-select-type/reference-data-select-type.component.spec.ts +++ b/src/app/features/reference-data/reference-data-select-type/reference-data-select-type.component.spec.ts @@ -17,64 +17,65 @@ import { of } from 'rxjs'; import { ReferenceDataSelectTypeComponent } from './reference-data-select-type.component'; describe('ReferenceDataComponent', () => { - let component: ReferenceDataSelectTypeComponent; - let fixture: ComponentFixture; - let router: Router; - let route: ActivatedRoute; + let component: ReferenceDataSelectTypeComponent; + let fixture: ComponentFixture; + let router: Router; + let route: ActivatedRoute; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ReferenceDataSelectTypeComponent, RoleRequiredDirective, RadioGroupComponent, ButtonComponent], - imports: [HttpClientTestingModule, RouterTestingModule, FormsModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - ReferenceDataService, { provide: UserService, useValue: { roles$: of([Roles.ReferenceDataView]) } }, - ], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ReferenceDataSelectTypeComponent, RoleRequiredDirective, RadioGroupComponent, ButtonComponent], + imports: [HttpClientTestingModule, RouterTestingModule, FormsModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + ReferenceDataService, + { provide: UserService, useValue: { roles$: of([Roles.ReferenceDataView]) } }, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(ReferenceDataSelectTypeComponent); - component = fixture.componentInstance; - router = TestBed.inject(Router); - route = TestBed.inject(ActivatedRoute); - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(ReferenceDataSelectTypeComponent); + component = fixture.componentInstance; + router = TestBed.inject(Router); + route = TestBed.inject(ActivatedRoute); + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - describe('cancel', () => { - it('should navigate back relative to the route', () => { - jest.spyOn(router, 'navigate').mockImplementation(); + describe('cancel', () => { + it('should navigate back relative to the route', () => { + jest.spyOn(router, 'navigate').mockImplementation(); - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(); + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(); - component.cancel(); + component.cancel(); - expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); - }); - }); + expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); + }); + }); - describe('navigateTo', () => { - it('should navigate to the reference data resource type', () => { - jest.spyOn(router, 'navigate').mockImplementation(); - jest.spyOn(component, 'isFormValid', 'get').mockReturnValueOnce(true); + describe('navigateTo', () => { + it('should navigate to the reference data resource type', () => { + jest.spyOn(router, 'navigate').mockImplementation(); + jest.spyOn(component, 'isFormValid', 'get').mockReturnValueOnce(true); - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(); + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(); - component.navigateTo(ReferenceDataResourceType.CountryOfRegistration); + component.navigateTo(ReferenceDataResourceType.CountryOfRegistration); - expect(navigateSpy).toHaveBeenCalledWith(['COUNTRY_OF_REGISTRATION'], { relativeTo: route }); - }); - }); + expect(navigateSpy).toHaveBeenCalledWith(['COUNTRY_OF_REGISTRATION'], { relativeTo: route }); + }); + }); - describe('isFormValid', () => { - it('checks the form is valid', () => { - jest.spyOn(DynamicFormService, 'validate').mockReturnValueOnce(); - component.form.setValue({ referenceType: 'COUNTRY_OF_REGISTRATION' }); - expect(component.isFormValid).toBe(true); - }); - }); + describe('isFormValid', () => { + it('checks the form is valid', () => { + jest.spyOn(DynamicFormService, 'validate').mockReturnValueOnce(); + component.form.setValue({ referenceType: 'COUNTRY_OF_REGISTRATION' }); + expect(component.isFormValid).toBe(true); + }); + }); }); diff --git a/src/app/features/reference-data/reference-data-select-type/reference-data-select-type.component.ts b/src/app/features/reference-data/reference-data-select-type/reference-data-select-type.component.ts index b60a4d4796..97a3cd732a 100644 --- a/src/app/features/reference-data/reference-data-select-type/reference-data-select-type.component.ts +++ b/src/app/features/reference-data/reference-data-select-type/reference-data-select-type.component.ts @@ -4,9 +4,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { GlobalError } from '@core/components/global-error/global-error.interface'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; -import { - CustomFormControl, CustomFormGroup, FormNodeOption, FormNodeTypes, -} from '@forms/services/dynamic-form.types'; +import { CustomFormControl, CustomFormGroup, FormNodeOption, FormNodeTypes } from '@forms/services/dynamic-form.types'; import { ReferenceDataResourceType } from '@models/reference-data.model'; import { Roles } from '@models/roles.enum'; import { Store, select } from '@ngrx/store'; @@ -15,58 +13,63 @@ import { ReferenceDataState, selectAllReferenceDataByResourceType } from '@store import { Observable, map, take } from 'rxjs'; @Component({ - selector: 'app-reference-data-select-type', - templateUrl: './reference-data-select-type.component.html', + selector: 'app-reference-data-select-type', + templateUrl: './reference-data-select-type.component.html', }) export class ReferenceDataSelectTypeComponent { - form: CustomFormGroup = new CustomFormGroup( - { name: 'form-group', type: FormNodeTypes.GROUP }, - { - referenceType: new CustomFormControl({ name: 'referenceType', type: FormNodeTypes.CONTROL }, undefined, [Validators.required]), - }, - ); + form: CustomFormGroup = new CustomFormGroup( + { name: 'form-group', type: FormNodeTypes.GROUP }, + { + referenceType: new CustomFormControl({ name: 'referenceType', type: FormNodeTypes.CONTROL }, undefined, [ + Validators.required, + ]), + } + ); - constructor( - private globalErrorService: GlobalErrorService, - private referenceDataService: ReferenceDataService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - ) { - this.referenceDataService.loadReferenceData(ReferenceDataResourceType.ReferenceDataAdminType); - } + constructor( + private globalErrorService: GlobalErrorService, + private referenceDataService: ReferenceDataService, + private route: ActivatedRoute, + private router: Router, + private store: Store + ) { + this.referenceDataService.loadReferenceData(ReferenceDataResourceType.ReferenceDataAdminType); + } - get options$(): Observable>> { - return this.store.pipe( - select(selectAllReferenceDataByResourceType(ReferenceDataResourceType.ReferenceDataAdminType)), - take(1), - map( - (types) => - types - ?.sort((a, b) => (a.label ?? a.resourceType).localeCompare(b.label ?? b.resourceType)) - .map((type) => ({ label: type.label ?? type.resourceKey.toString(), value: type.resourceKey.toString() })) ?? [], - ), - ); - } + get options$(): Observable>> { + return this.store.pipe( + select(selectAllReferenceDataByResourceType(ReferenceDataResourceType.ReferenceDataAdminType)), + take(1), + map( + (types) => + types + ?.sort((a, b) => (a.label ?? a.resourceType).localeCompare(b.label ?? b.resourceType)) + .map((type) => ({ + label: type.label ?? type.resourceKey.toString(), + value: type.resourceKey.toString(), + })) ?? [] + ) + ); + } - get roles(): typeof Roles { - return Roles; - } + get roles(): typeof Roles { + return Roles; + } - get isFormValid(): boolean { - const errors: GlobalError[] = []; - DynamicFormService.validate(this.form, errors); - this.globalErrorService.setErrors(errors); - return this.form.valid; - } + get isFormValid(): boolean { + const errors: GlobalError[] = []; + DynamicFormService.validate(this.form, errors); + this.globalErrorService.setErrors(errors); + return this.form.valid; + } - cancel(): void { - void this.router.navigate(['..'], { relativeTo: this.route }); - } + cancel(): void { + void this.router.navigate(['..'], { relativeTo: this.route }); + } - navigateTo(type: string): void { - if (this.isFormValid) { - void this.router.navigate([type], { relativeTo: this.route }); - } - } + navigateTo(type: string): void { + if (this.isFormValid) { + void this.router.navigate([type], { relativeTo: this.route }); + } + } } diff --git a/src/app/features/reference-data/reference-data.module.ts b/src/app/features/reference-data/reference-data.module.ts index 886d529a9d..83752cf8be 100644 --- a/src/app/features/reference-data/reference-data.module.ts +++ b/src/app/features/reference-data/reference-data.module.ts @@ -14,15 +14,22 @@ import { ReferenceDataRoutingModule } from './reference-data-routing.module'; import { ReferenceDataSelectTypeComponent } from './reference-data-select-type/reference-data-select-type.component'; @NgModule({ - declarations: [ - ReferenceDataSelectTypeComponent, - ReferenceDataListComponent, - ReferenceDataDeletedListComponent, - ReferenceDataCreateComponent, - ReferenceDataAmendComponent, - ReferenceDataDeleteComponent, - ReferenceDataAmendHistoryComponent, - ], - imports: [CommonModule, DynamicFormsModule, RouterModule, ReactiveFormsModule, ReferenceDataRoutingModule, SharedModule], + declarations: [ + ReferenceDataSelectTypeComponent, + ReferenceDataListComponent, + ReferenceDataDeletedListComponent, + ReferenceDataCreateComponent, + ReferenceDataAmendComponent, + ReferenceDataDeleteComponent, + ReferenceDataAmendHistoryComponent, + ], + imports: [ + CommonModule, + DynamicFormsModule, + RouterModule, + ReactiveFormsModule, + ReferenceDataRoutingModule, + SharedModule, + ], }) export class ReferenceDataModule {} diff --git a/src/app/features/search/multiple-search-results/multiple-search-results.component.spec.ts b/src/app/features/search/multiple-search-results/multiple-search-results.component.spec.ts index 9b80fb0603..3b0983a7a0 100644 --- a/src/app/features/search/multiple-search-results/multiple-search-results.component.spec.ts +++ b/src/app/features/search/multiple-search-results/multiple-search-results.component.spec.ts @@ -1,137 +1,133 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { - ComponentFixture, fakeAsync, TestBed, tick, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { RouterTestingModule } from '@angular/router/testing'; import { RoleRequiredDirective } from '@directives/app-role-required.directive'; +import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; import { DynamicFormsModule } from '@forms/dynamic-forms.module'; import { provideMockActions } from '@ngrx/effects/testing'; import { Action } from '@ngrx/store'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { TechnicalRecordHttpService } from '@services/technical-record-http/technical-record-http.service'; import { UserService } from '@services/user-service/user-service'; -import { initialAppState, State } from '@store/.'; +import { State, initialAppState } from '@store/.'; import { selectQueryParams } from '@store/router/selectors/router.selectors'; -import { - firstValueFrom, of, ReplaySubject, BehaviorSubject, -} from 'rxjs'; -import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; +import { BehaviorSubject, ReplaySubject, firstValueFrom, of } from 'rxjs'; import { SingleSearchResultComponent } from '../single-search-result/single-search-result.component'; import { MultipleSearchResultsComponent } from './multiple-search-results.component'; describe('MultipleSearchResultsComponent', () => { - let component: MultipleSearchResultsComponent; - let fixture: ComponentFixture; - let store: MockStore; - const actions$ = new ReplaySubject(); - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [SingleSearchResultComponent, MultipleSearchResultsComponent, RoleRequiredDirective], - imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - provideMockActions(() => actions$), - { - provide: UserService, - useValue: { - roles$: of(['TechRecord.View', 'TechRecord.Create']), - }, - }, - TechnicalRecordHttpService, - ], - }).compileComponents(); - }); - - describe('default tests', () => { - beforeEach(() => { - store = TestBed.inject(MockStore); - store.overrideSelector(selectQueryParams, { vin: '123456' }); - - fixture = TestBed.createComponent(MultipleSearchResultsComponent); - component = fixture.componentInstance; - - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should show create link when searchResults is null', () => { - const button = fixture.debugElement.query(By.css('.govuk-link')); - expect(button).toBeTruthy(); - }); - - it('should navigate back when searchResults not null', fakeAsync(() => { - const navigateBackSpy = jest.spyOn(component, 'navigateBack'); - const newData: TechRecordSearchSchema[] = [ - { - vin: '1B7GG36N12S678410', - techRecord_statusCode: 'provisional', - techRecord_vehicleType: 'psv', - createdTimestamp: '2023-09-27T12:00:00Z', - systemNumber: '12345', - techRecord_manufactureYear: 2013, - }, - ]; - component.searchResults$ = new BehaviorSubject(newData); - fixture.detectChanges(); - - const button = fixture.debugElement.query(By.css('.govuk-back-link')); - expect(button).toBeTruthy(); - (button.nativeElement as HTMLButtonElement).click(); - - tick(); - - expect(navigateBackSpy).toHaveBeenCalled(); - })); - }); - - describe('searching', () => { - beforeEach(() => { - store = TestBed.inject(MockStore); - }); - - it('should search using a vin', async () => { - store.overrideSelector(selectQueryParams, { vin: '123456' }); - - fixture = TestBed.createComponent(MultipleSearchResultsComponent); - component = fixture.componentInstance; - const searchResult = await firstValueFrom(component.searchResults$); - - expect(searchResult).toBeDefined(); - }); - - it('should search using a partial vin', async () => { - store.overrideSelector(selectQueryParams, { partialVin: '123456' }); - - fixture = TestBed.createComponent(MultipleSearchResultsComponent); - component = fixture.componentInstance; - const searchResult = await firstValueFrom(component.searchResults$); - - expect(searchResult).toBeDefined(); - }); - - it('should search using a vrm', async () => { - store.overrideSelector(selectQueryParams, { vrm: '123456' }); - - fixture = TestBed.createComponent(MultipleSearchResultsComponent); - component = fixture.componentInstance; - const searchResult = await firstValueFrom(component.searchResults$); - - expect(searchResult).toBeDefined(); - }); - - it('should search using a trailer id', async () => { - store.overrideSelector(selectQueryParams, { trailerId: '123456' }); - - fixture = TestBed.createComponent(MultipleSearchResultsComponent); - component = fixture.componentInstance; - const searchResult = await firstValueFrom(component.searchResults$); - - expect(searchResult).toBeDefined(); - }); - }); + let component: MultipleSearchResultsComponent; + let fixture: ComponentFixture; + let store: MockStore; + const actions$ = new ReplaySubject(); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [SingleSearchResultComponent, MultipleSearchResultsComponent, RoleRequiredDirective], + imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + provideMockActions(() => actions$), + { + provide: UserService, + useValue: { + roles$: of(['TechRecord.View', 'TechRecord.Create']), + }, + }, + TechnicalRecordHttpService, + ], + }).compileComponents(); + }); + + describe('default tests', () => { + beforeEach(() => { + store = TestBed.inject(MockStore); + store.overrideSelector(selectQueryParams, { vin: '123456' }); + + fixture = TestBed.createComponent(MultipleSearchResultsComponent); + component = fixture.componentInstance; + + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should show create link when searchResults is null', () => { + const button = fixture.debugElement.query(By.css('.govuk-link')); + expect(button).toBeTruthy(); + }); + + it('should navigate back when searchResults not null', fakeAsync(() => { + const navigateBackSpy = jest.spyOn(component, 'navigateBack'); + const newData: TechRecordSearchSchema[] = [ + { + vin: '1B7GG36N12S678410', + techRecord_statusCode: 'provisional', + techRecord_vehicleType: 'psv', + createdTimestamp: '2023-09-27T12:00:00Z', + systemNumber: '12345', + techRecord_manufactureYear: 2013, + }, + ]; + component.searchResults$ = new BehaviorSubject(newData); + fixture.detectChanges(); + + const button = fixture.debugElement.query(By.css('.govuk-back-link')); + expect(button).toBeTruthy(); + (button.nativeElement as HTMLButtonElement).click(); + + tick(); + + expect(navigateBackSpy).toHaveBeenCalled(); + })); + }); + + describe('searching', () => { + beforeEach(() => { + store = TestBed.inject(MockStore); + }); + + it('should search using a vin', async () => { + store.overrideSelector(selectQueryParams, { vin: '123456' }); + + fixture = TestBed.createComponent(MultipleSearchResultsComponent); + component = fixture.componentInstance; + const searchResult = await firstValueFrom(component.searchResults$); + + expect(searchResult).toBeDefined(); + }); + + it('should search using a partial vin', async () => { + store.overrideSelector(selectQueryParams, { partialVin: '123456' }); + + fixture = TestBed.createComponent(MultipleSearchResultsComponent); + component = fixture.componentInstance; + const searchResult = await firstValueFrom(component.searchResults$); + + expect(searchResult).toBeDefined(); + }); + + it('should search using a vrm', async () => { + store.overrideSelector(selectQueryParams, { vrm: '123456' }); + + fixture = TestBed.createComponent(MultipleSearchResultsComponent); + component = fixture.componentInstance; + const searchResult = await firstValueFrom(component.searchResults$); + + expect(searchResult).toBeDefined(); + }); + + it('should search using a trailer id', async () => { + store.overrideSelector(selectQueryParams, { trailerId: '123456' }); + + fixture = TestBed.createComponent(MultipleSearchResultsComponent); + component = fixture.componentInstance; + const searchResult = await firstValueFrom(component.searchResults$); + + expect(searchResult).toBeDefined(); + }); + }); }); diff --git a/src/app/features/search/multiple-search-results/multiple-search-results.component.ts b/src/app/features/search/multiple-search-results/multiple-search-results.component.ts index d62cdb34a2..4a3a181da7 100644 --- a/src/app/features/search/multiple-search-results/multiple-search-results.component.ts +++ b/src/app/features/search/multiple-search-results/multiple-search-results.component.ts @@ -3,56 +3,56 @@ import { Component, OnDestroy } from '@angular/core'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; import { Roles } from '@models/roles.enum'; +import { SEARCH_TYPES } from '@models/search-types-enum'; import { Store, select } from '@ngrx/store'; import { TechnicalRecordHttpService } from '@services/technical-record-http/technical-record-http.service'; -import { SEARCH_TYPES } from '@models/search-types-enum'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { selectQueryParams } from '@store/router/selectors/router.selectors'; import { Observable, Subject, takeUntil } from 'rxjs'; @Component({ - selector: 'app-multiple-search-results', - templateUrl: './multiple-search-results.component.html', - styleUrls: ['multiple-search-results.component.scss'], + selector: 'app-multiple-search-results', + templateUrl: './multiple-search-results.component.html', + styleUrls: ['multiple-search-results.component.scss'], }) export class MultipleSearchResultsComponent implements OnDestroy { - searchResults$: Observable; - ngDestroy$ = new Subject(); + searchResults$: Observable; + ngDestroy$ = new Subject(); - constructor( - public globalErrorService: GlobalErrorService, - private technicalRecordService: TechnicalRecordService, - private technicalRecordHttpService: TechnicalRecordHttpService, - private store: Store, - private location: Location, - ) { - this.store.pipe(select(selectQueryParams), takeUntil(this.ngDestroy$)).subscribe((params) => { - if (Object.keys(params).length === 1) { - const type = Object.keys(params)[0] as SEARCH_TYPES; - // eslint-disable-next-line security/detect-object-injection - const searchTerm = params[type] as string; + constructor( + public globalErrorService: GlobalErrorService, + private technicalRecordService: TechnicalRecordService, + private technicalRecordHttpService: TechnicalRecordHttpService, + private store: Store, + private location: Location + ) { + this.store.pipe(select(selectQueryParams), takeUntil(this.ngDestroy$)).subscribe((params) => { + if (Object.keys(params).length === 1) { + const type = Object.keys(params)[0] as SEARCH_TYPES; + // eslint-disable-next-line security/detect-object-injection + const searchTerm = params[type] as string; - if (searchTerm && Object.values(SEARCH_TYPES).includes(type)) { - this.globalErrorService.clearErrors(); - this.technicalRecordHttpService.searchBy(type, searchTerm); - } - } - }); + if (searchTerm && Object.values(SEARCH_TYPES).includes(type)) { + this.globalErrorService.clearErrors(); + this.technicalRecordHttpService.searchBy(type, searchTerm); + } + } + }); - this.searchResults$ = this.technicalRecordService.searchResultsWithUniqueSystemNumbers$; - } + this.searchResults$ = this.technicalRecordService.searchResultsWithUniqueSystemNumbers$; + } - navigateBack() { - this.globalErrorService.clearErrors(); - this.location.back(); - } + navigateBack() { + this.globalErrorService.clearErrors(); + this.location.back(); + } - ngOnDestroy() { - this.ngDestroy$.next(true); - this.ngDestroy$.complete(); - } + ngOnDestroy() { + this.ngDestroy$.next(true); + this.ngDestroy$.complete(); + } - public get Roles() { - return Roles; - } + public get Roles() { + return Roles; + } } diff --git a/src/app/features/search/search-routing.module.ts b/src/app/features/search/search-routing.module.ts index f65f369045..d1cfbbf88d 100644 --- a/src/app/features/search/search-routing.module.ts +++ b/src/app/features/search/search-routing.module.ts @@ -6,21 +6,21 @@ import { MultipleSearchResultsComponent } from './multiple-search-results/multip import { SearchComponent } from './search.component'; const routes: Routes = [ - { - path: '', - pathMatch: 'prefix', - component: SearchComponent, - }, - { - path: SearchRoutes.SEARCH_RESULT, - component: MultipleSearchResultsComponent, - canActivate: [NoQueryParamsGuard], - data: { title: 'Search Results' }, - }, + { + path: '', + pathMatch: 'prefix', + component: SearchComponent, + }, + { + path: SearchRoutes.SEARCH_RESULT, + component: MultipleSearchResultsComponent, + canActivate: [NoQueryParamsGuard], + data: { title: 'Search Results' }, + }, ]; @NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], }) export class SearchRoutingModule {} diff --git a/src/app/features/search/search.component.spec.ts b/src/app/features/search/search.component.spec.ts index 76324f6ba7..6949a51442 100644 --- a/src/app/features/search/search.component.spec.ts +++ b/src/app/features/search/search.component.spec.ts @@ -5,124 +5,136 @@ import { RouterTestingModule } from '@angular/router/testing'; import { GlobalError } from '@core/components/global-error/global-error.interface'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { Roles } from '@models/roles.enum'; -import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { SEARCH_TYPES } from '@models/search-types-enum'; +import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; -import { initialAppState, State } from '@store/.'; +import { State, initialAppState } from '@store/.'; import { globalErrorState } from '@store/global-error/reducers/global-error-service.reducer'; import { of } from 'rxjs'; import { SearchComponent } from './search.component'; describe('SearchComponent', () => { - let component: SearchComponent; - let fixture: ComponentFixture; - let globalErrorService: GlobalErrorService; - let router: Router; - let store: MockStore; - const expectedError: GlobalError = { error: 'some-error', anchorLink: 'some-link' }; - const expectedErrors: GlobalError[] = [expectedError]; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [SearchComponent], - imports: [HttpClientTestingModule, RouterTestingModule], - providers: [GlobalErrorService, TechnicalRecordService, provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); - - beforeEach(() => { - store = TestBed.inject(MockStore); - store.overrideSelector(globalErrorState, expectedErrors); - fixture = TestBed.createComponent(SearchComponent); - component = fixture.componentInstance; - globalErrorService = TestBed.inject(GlobalErrorService); - router = TestBed.inject(Router); - - jest.clearAllMocks(); - }); - - it('should create', () => expect(component).toBeTruthy()); - - describe('searching', () => { - describe('navigateSearch', () => { - it('should navigate to vin search result', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - const expectedVin = 'someVin'; - component.navigateSearch(expectedVin, SEARCH_TYPES.VIN); - - expect(navigateSpy).toHaveBeenCalledWith(['/search/results'], { queryParams: { vin: expectedVin } }); - }); - - it('should navigate to partialVin search result', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - const expectedPartialVin = 'somePartialVin'; - component.navigateSearch(expectedPartialVin, SEARCH_TYPES.PARTIAL_VIN); - - expect(navigateSpy).toHaveBeenCalledWith(['/search/results'], { queryParams: { partialVin: expectedPartialVin } }); - }); - - it('should navigate to vrm search result', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - const expectedVrm = 'someVrm'; - component.navigateSearch(expectedVrm, SEARCH_TYPES.VRM); - - expect(navigateSpy).toHaveBeenCalledWith(['/search/results'], { queryParams: { primaryVrm: expectedVrm } }); - }); - - it('should navigate to trailerId search result', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - const expectedTrailerId = 'someTrailerId'; - component.navigateSearch(expectedTrailerId, SEARCH_TYPES.TRAILER_ID); - - expect(navigateSpy).toHaveBeenCalledWith(['/search/results'], { queryParams: { trailerId: expectedTrailerId } }); - }); - }); - - describe('invalid input', () => { - it('should add search-term error', () => { - const addErrorSpy = jest.spyOn(globalErrorService, 'addError').mockImplementation(() => {}); - - component.navigateSearch('', ''); - - expect(addErrorSpy).toHaveBeenCalledWith({ error: component.missingTermErrorMessage, anchorLink: 'search-term' }); - }); - - it('should add search-type error', () => { - const addErrorSpy = jest.spyOn(globalErrorService, 'addError').mockImplementation(() => {}); - - component.navigateSearch('some term', ''); - - expect(addErrorSpy).toHaveBeenCalledWith({ error: component.missingTypeErrorMessage, anchorLink: 'search-type' }); - }); - }); - - describe('helper methods', () => { - it('should get inline error message', (done) => { - const addErrorSpy = jest.spyOn(globalErrorService, 'errors$', 'get').mockImplementation(() => of(expectedErrors)); - - component.getInlineErrorMessage(expectedError.anchorLink ?? '').subscribe((response) => { - expect(response).toBeTruthy(); - done(); - }); // subscribe to activate the map inside 'getInlineErrorMessage()' + let component: SearchComponent; + let fixture: ComponentFixture; + let globalErrorService: GlobalErrorService; + let router: Router; + let store: MockStore; + const expectedError: GlobalError = { error: 'some-error', anchorLink: 'some-link' }; + const expectedErrors: GlobalError[] = [expectedError]; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [SearchComponent], + imports: [HttpClientTestingModule, RouterTestingModule], + providers: [GlobalErrorService, TechnicalRecordService, provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); + + beforeEach(() => { + store = TestBed.inject(MockStore); + store.overrideSelector(globalErrorState, expectedErrors); + fixture = TestBed.createComponent(SearchComponent); + component = fixture.componentInstance; + globalErrorService = TestBed.inject(GlobalErrorService); + router = TestBed.inject(Router); + + jest.clearAllMocks(); + }); + + it('should create', () => expect(component).toBeTruthy()); + + describe('searching', () => { + describe('navigateSearch', () => { + it('should navigate to vin search result', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + const expectedVin = 'someVin'; + component.navigateSearch(expectedVin, SEARCH_TYPES.VIN); + + expect(navigateSpy).toHaveBeenCalledWith(['/search/results'], { queryParams: { vin: expectedVin } }); + }); + + it('should navigate to partialVin search result', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + const expectedPartialVin = 'somePartialVin'; + component.navigateSearch(expectedPartialVin, SEARCH_TYPES.PARTIAL_VIN); + + expect(navigateSpy).toHaveBeenCalledWith(['/search/results'], { + queryParams: { partialVin: expectedPartialVin }, + }); + }); + + it('should navigate to vrm search result', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + const expectedVrm = 'someVrm'; + component.navigateSearch(expectedVrm, SEARCH_TYPES.VRM); + + expect(navigateSpy).toHaveBeenCalledWith(['/search/results'], { queryParams: { primaryVrm: expectedVrm } }); + }); + + it('should navigate to trailerId search result', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + const expectedTrailerId = 'someTrailerId'; + component.navigateSearch(expectedTrailerId, SEARCH_TYPES.TRAILER_ID); + + expect(navigateSpy).toHaveBeenCalledWith(['/search/results'], { + queryParams: { trailerId: expectedTrailerId }, + }); + }); + }); + + describe('invalid input', () => { + it('should add search-term error', () => { + const addErrorSpy = jest.spyOn(globalErrorService, 'addError').mockImplementation(() => {}); + + component.navigateSearch('', ''); + + expect(addErrorSpy).toHaveBeenCalledWith({ + error: component.missingTermErrorMessage, + anchorLink: 'search-term', + }); + }); + + it('should add search-type error', () => { + const addErrorSpy = jest.spyOn(globalErrorService, 'addError').mockImplementation(() => {}); + + component.navigateSearch('some term', ''); + + expect(addErrorSpy).toHaveBeenCalledWith({ + error: component.missingTypeErrorMessage, + anchorLink: 'search-type', + }); + }); + }); + + describe('helper methods', () => { + it('should get inline error message', (done) => { + const addErrorSpy = jest + .spyOn(globalErrorService, 'errors$', 'get') + .mockImplementation(() => of(expectedErrors)); + + component.getInlineErrorMessage(expectedError.anchorLink ?? '').subscribe((response) => { + expect(response).toBeTruthy(); + done(); + }); // subscribe to activate the map inside 'getInlineErrorMessage()' - expect(addErrorSpy).toHaveBeenCalled(); - }); + expect(addErrorSpy).toHaveBeenCalled(); + }); - it('should get error by name', () => { - const error = component.getErrorByName(expectedErrors, expectedError.anchorLink ?? ''); + it('should get error by name', () => { + const error = component.getErrorByName(expectedErrors, expectedError.anchorLink ?? ''); - expect(error).toEqual(expectedError); - }); + expect(error).toEqual(expectedError); + }); - it('should return roles', () => { - const { roles } = component; + it('should return roles', () => { + const { roles } = component; - expect(roles).toBe(Roles); - }); - }); - }); + expect(roles).toBe(Roles); + }); + }); + }); }); diff --git a/src/app/features/search/search.component.ts b/src/app/features/search/search.component.ts index e571720163..cba92aacbd 100644 --- a/src/app/features/search/search.component.ts +++ b/src/app/features/search/search.component.ts @@ -9,39 +9,44 @@ import { clearAllSectionStates, clearScrollPosition } from '@store/technical-rec import { Observable, map } from 'rxjs'; @Component({ - selector: 'app-search', - templateUrl: './search.component.html', + selector: 'app-search', + templateUrl: './search.component.html', }) export class SearchComponent { - missingTermErrorMessage = 'You must provide a vehicle registration mark, trailer ID or vehicle identification number.'; - missingTypeErrorMessage = 'You must select a valid search criteria'; + missingTermErrorMessage = + 'You must provide a vehicle registration mark, trailer ID or vehicle identification number.'; + missingTypeErrorMessage = 'You must select a valid search criteria'; - constructor(public globalErrorService: GlobalErrorService, private router: Router, private store: Store) {} + constructor( + public globalErrorService: GlobalErrorService, + private router: Router, + private store: Store + ) {} - navigateSearch(term: string, type: string): void { - this.globalErrorService.clearErrors(); - this.store.dispatch(clearAllSectionStates()); - this.store.dispatch(clearScrollPosition()); - term = term.trim(); + navigateSearch(term: string, type: string): void { + this.globalErrorService.clearErrors(); + this.store.dispatch(clearAllSectionStates()); + this.store.dispatch(clearScrollPosition()); + term = term.trim(); - if (!term) { - this.globalErrorService.addError({ error: this.missingTermErrorMessage, anchorLink: 'search-term' }); - } else if (!Object.values(SEARCH_TYPES).includes(type as SEARCH_TYPES)) { - this.globalErrorService.addError({ error: this.missingTypeErrorMessage, anchorLink: 'search-type' }); - } else { - void this.router.navigate(['/search/results'], { queryParams: { [type]: term } }); - } - } + if (!term) { + this.globalErrorService.addError({ error: this.missingTermErrorMessage, anchorLink: 'search-term' }); + } else if (!Object.values(SEARCH_TYPES).includes(type as SEARCH_TYPES)) { + this.globalErrorService.addError({ error: this.missingTypeErrorMessage, anchorLink: 'search-type' }); + } else { + void this.router.navigate(['/search/results'], { queryParams: { [type]: term } }); + } + } - getInlineErrorMessage(name: string): Observable { - return this.globalErrorService.errors$.pipe(map((errors) => errors.some((error) => error.anchorLink === name))); - } + getInlineErrorMessage(name: string): Observable { + return this.globalErrorService.errors$.pipe(map((errors) => errors.some((error) => error.anchorLink === name))); + } - getErrorByName(errors: GlobalError[], name: string): GlobalError | undefined { - return errors.find((error) => error.anchorLink === name); - } + getErrorByName(errors: GlobalError[], name: string): GlobalError | undefined { + return errors.find((error) => error.anchorLink === name); + } - public get roles() { - return Roles; - } + public get roles() { + return Roles; + } } diff --git a/src/app/features/search/search.module.ts b/src/app/features/search/search.module.ts index 2f71da2d2b..bd3df06de8 100644 --- a/src/app/features/search/search.module.ts +++ b/src/app/features/search/search.module.ts @@ -3,13 +3,13 @@ import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; import { DynamicFormsModule } from '@forms/dynamic-forms.module'; import { SharedModule } from '@shared/shared.module'; +import { MultipleSearchResultsComponent } from './multiple-search-results/multiple-search-results.component'; import { SearchRoutingModule } from './search-routing.module'; import { SearchComponent } from './search.component'; import { SingleSearchResultComponent } from './single-search-result/single-search-result.component'; -import { MultipleSearchResultsComponent } from './multiple-search-results/multiple-search-results.component'; @NgModule({ - declarations: [SearchComponent, SingleSearchResultComponent, MultipleSearchResultsComponent], - imports: [CommonModule, DynamicFormsModule, RouterModule, SearchRoutingModule, SharedModule], + declarations: [SearchComponent, SingleSearchResultComponent, MultipleSearchResultsComponent], + imports: [CommonModule, DynamicFormsModule, RouterModule, SearchRoutingModule, SharedModule], }) export class SearchModule {} diff --git a/src/app/features/search/search.stories.ts b/src/app/features/search/search.stories.ts index b4f29e1394..f28c11f69e 100644 --- a/src/app/features/search/search.stories.ts +++ b/src/app/features/search/search.stories.ts @@ -1,20 +1,20 @@ -import { moduleMetadata, Meta, Story } from '@storybook/angular'; import { HttpClientModule } from '@angular/common/http'; +import { Meta, Story, moduleMetadata } from '@storybook/angular'; import { SearchComponent } from './search.component'; export default { - title: 'Search Page', - component: SearchComponent, - decorators: [ - moduleMetadata({ - declarations: [SearchComponent], - imports: [HttpClientModule] - }) - ] + title: 'Search Page', + component: SearchComponent, + decorators: [ + moduleMetadata({ + declarations: [SearchComponent], + imports: [HttpClientModule], + }), + ], } as Meta; -const Template: Story = args => ({ - props: args +const Template: Story = (args) => ({ + props: args, }); export const Initial = Template.bind({}); @@ -22,10 +22,10 @@ Initial.args = {}; export const Loading = Template.bind({}); Loading.args = { - isLoading: true + isLoading: true, }; export const Error = Template.bind({}); Error.args = { - searchError: 'This is an error' + searchError: 'This is an error', }; diff --git a/src/app/features/search/single-search-result/single-search-result.component.spec.ts b/src/app/features/search/single-search-result/single-search-result.component.spec.ts index e8c9d70cc1..8218f51eff 100644 --- a/src/app/features/search/single-search-result/single-search-result.component.spec.ts +++ b/src/app/features/search/single-search-result/single-search-result.component.spec.ts @@ -12,42 +12,42 @@ import { ReplaySubject, of } from 'rxjs'; import { SingleSearchResultComponent } from './single-search-result.component'; describe('SingleSearchResultComponent', () => { - let component: SingleSearchResultComponent; - let fixture: ComponentFixture; - const actions$ = new ReplaySubject(); + let component: SingleSearchResultComponent; + let fixture: ComponentFixture; + const actions$ = new ReplaySubject(); - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [SingleSearchResultComponent, RoleRequiredDirective], - imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - provideMockActions(() => actions$), - { - provide: UserService, - useValue: { - roles$: of(['TechRecord.View']), - }, - }, - ], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [SingleSearchResultComponent, RoleRequiredDirective], + imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + provideMockActions(() => actions$), + { + provide: UserService, + useValue: { + roles$: of(['TechRecord.View']), + }, + }, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(SingleSearchResultComponent); - component = fixture.componentInstance; - component.searchResult = { - systemNumber: '123', - createdTimestamp: '123', - vin: '76890', - techRecord_vehicleType: 'psv', - techRecord_statusCode: 'current', - techRecord_manufactureYear: 1998, - }; - }); + beforeEach(() => { + fixture = TestBed.createComponent(SingleSearchResultComponent); + component = fixture.componentInstance; + component.searchResult = { + systemNumber: '123', + createdTimestamp: '123', + vin: '76890', + techRecord_vehicleType: 'psv', + techRecord_statusCode: 'current', + techRecord_manufactureYear: 1998, + }; + }); - it('should create', () => { - fixture.detectChanges(); - expect(component).toBeTruthy(); - }); + it('should create', () => { + fixture.detectChanges(); + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/features/search/single-search-result/single-search-result.component.ts b/src/app/features/search/single-search-result/single-search-result.component.ts index 9cbfa2ca50..205aee4a80 100644 --- a/src/app/features/search/single-search-result/single-search-result.component.ts +++ b/src/app/features/search/single-search-result/single-search-result.component.ts @@ -1,46 +1,50 @@ -import { - ChangeDetectionStrategy, Component, Input, OnInit, -} from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; import { FormNode } from '@forms/services/dynamic-form.types'; import { createSingleSearchResult } from '@forms/templates/search/single-search-result.template'; import { Roles } from '@models/roles.enum'; @Component({ - selector: 'app-single-search-result[searchResult]', - templateUrl: './single-search-result.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-single-search-result[searchResult]', + templateUrl: './single-search-result.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class SingleSearchResultComponent implements OnInit { - @Input() searchResult!: TechRecordSearchSchema; - vehicleDisplayData?: VehicleDisplayData; - template?: FormNode; + @Input() searchResult!: TechRecordSearchSchema; + vehicleDisplayData?: VehicleDisplayData; + template?: FormNode; - ngOnInit(): void { - this.vehicleDisplayData = { - vin: this.searchResult.vin, - vrm: this.searchResult.primaryVrm, - trailerId: this.searchResult.trailerId, - make: this.searchResult.techRecord_vehicleType === 'psv' ? this.searchResult.techRecord_chassisMake : this.searchResult.techRecord_make, - model: this.searchResult.techRecord_vehicleType === 'psv' ? this.searchResult.techRecord_chassisModel : this.searchResult.techRecord_model, - manufactureYear: this.searchResult.techRecord_manufactureYear, - vehicleType: this.searchResult.techRecord_vehicleType.toUpperCase(), - }; + ngOnInit(): void { + this.vehicleDisplayData = { + vin: this.searchResult.vin, + vrm: this.searchResult.primaryVrm, + trailerId: this.searchResult.trailerId, + make: + this.searchResult.techRecord_vehicleType === 'psv' + ? this.searchResult.techRecord_chassisMake + : this.searchResult.techRecord_make, + model: + this.searchResult.techRecord_vehicleType === 'psv' + ? this.searchResult.techRecord_chassisModel + : this.searchResult.techRecord_model, + manufactureYear: this.searchResult.techRecord_manufactureYear, + vehicleType: this.searchResult.techRecord_vehicleType.toUpperCase(), + }; - this.template = createSingleSearchResult(this.searchResult.systemNumber, this.searchResult.createdTimestamp); - } + this.template = createSingleSearchResult(this.searchResult.systemNumber, this.searchResult.createdTimestamp); + } - public get roles() { - return Roles; - } + public get roles() { + return Roles; + } } interface VehicleDisplayData { - vin?: string; - vrm?: string; - trailerId?: string; - make?: string | null; - model?: string | null; - manufactureYear?: number | null; - vehicleType?: string; + vin?: string; + vrm?: string; + trailerId?: string; + make?: string | null; + model?: string | null; + manufactureYear?: number | null; + vehicleType?: string; } diff --git a/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.spec.ts b/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.spec.ts index 1aa04bbc4d..85982abf07 100644 --- a/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.spec.ts +++ b/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.spec.ts @@ -1,7 +1,5 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { - ComponentFixture, fakeAsync, TestBed, tick, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; @@ -17,146 +15,151 @@ import { UserService } from '@services/user-service/user-service'; import { SharedModule } from '@shared/shared.module'; import { initialAppState } from '@store/index'; import { generateADRCertificate, generateADRCertificateSuccess } from '@store/technical-records'; -import { of, ReplaySubject } from 'rxjs'; +import { ReplaySubject, of } from 'rxjs'; import { AdrGenerateCertificateComponent } from './adr-generate-certificate.component'; const mockDynamicFormService = { - createForm: jest.fn(), + createForm: jest.fn(), }; describe('AdrGenerateCertificateComponent', () => { - let component: AdrGenerateCertificateComponent; - let fixture: ComponentFixture; - const actions$ = new ReplaySubject(); - let errorService: GlobalErrorService; - let route: ActivatedRoute; - let router: Router; - let store: MockStore; - let technicalRecordService: TechnicalRecordService; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AdrGenerateCertificateComponent], - providers: [ - GlobalErrorService, - provideMockActions(() => actions$), - provideMockStore({ initialState: initialAppState }), - { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, - { provide: DynamicFormService, useValue: mockDynamicFormService }, - TechnicalRecordService, - { - provide: UserService, - useValue: { - roles$: of(['TechRecord.Amend']), - }, - }, - ], - imports: [RouterTestingModule, SharedModule, ReactiveFormsModule, DynamicFormsModule, HttpClientTestingModule], - }).compileComponents(); - }); - beforeEach(() => { - fixture = TestBed.createComponent(AdrGenerateCertificateComponent); - errorService = TestBed.inject(GlobalErrorService); - route = TestBed.inject(ActivatedRoute); - router = TestBed.inject(Router); - store = TestBed.inject(MockStore); - technicalRecordService = TestBed.inject(TechnicalRecordService); - component = fixture.componentInstance; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('navigateBack', () => { - beforeEach(() => { - jest - .spyOn(technicalRecordService, 'techRecord$', 'get') - .mockReturnValue(of({ systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel)); - }); - it('should clear all errors', () => { - jest.spyOn(router, 'navigate').mockImplementation(); - - const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); - - component.navigateBack(); - - expect(clearErrorsSpy).toHaveBeenCalledTimes(1); - }); - - it('should navigate back to the previous page', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - component.navigateBack(); - - expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); - }); - - it('should navigate back on generateADRCertificateSuccess', fakeAsync(() => { - fixture.ngZone?.run(() => { - component.ngOnInit(); - component.form.get('certificateType')?.setValue('PASS'); - - const navigateBackSpy = jest.spyOn(component, 'navigateBack').mockImplementation(); - - component.handleSubmit(); - - actions$.next(generateADRCertificateSuccess({ id: '' })); - tick(); - - expect(navigateBackSpy).toHaveBeenCalled(); - }); - })); - }); - - describe('handleSubmit', () => { - beforeEach(() => { - jest - .spyOn(technicalRecordService, 'techRecord$', 'get') - .mockReturnValue(of({ systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel)); - }); - it('should add an error when the field is not filled out', () => { - const addErrorSpy = jest.spyOn(errorService, 'addError'); - - component.handleSubmit(); - - expect(addErrorSpy).toHaveBeenCalledWith({ error: 'ADR Certificate Type is required', anchorLink: 'certificateType' }); - }); - - it('should dispatch the generateADRCertificate action', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - - component.form.get('certificateType')?.setValue('PASS'); - - component.handleSubmit(); - expect(dispatchSpy).toHaveBeenCalledTimes(2); - expect(dispatchSpy).toHaveBeenLastCalledWith(generateADRCertificate({ systemNumber: '', createdTimestamp: '', certificateType: 'PASS' })); - }); - - it('should dispatch action with default values when systemNumber and createdTimestamp are null', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - - component.form.get('certificateType')?.setValue('PASS'); - component.systemNumber = '123'; - component.createdTimestamp = '2021'; - - component.handleSubmit(); - expect(dispatchSpy).toHaveBeenCalled(); - expect(dispatchSpy).toHaveBeenLastCalledWith( - generateADRCertificate({ systemNumber: '123', createdTimestamp: '2021', certificateType: 'PASS' }), - ); - }); - }); - - describe('certificateTypes', () => { - it('should get correct value when call get functions', () => { - const expectedValue = [ - { label: 'New ADR Certificate', value: 'PASS' }, - { label: 'Replacement ADR Certificate', value: 'REPLACEMENT' }, - ]; - expect(component.width).toBe(10); - expect(component.certificateTypes).toEqual(expectedValue); - }); - }); + let component: AdrGenerateCertificateComponent; + let fixture: ComponentFixture; + const actions$ = new ReplaySubject(); + let errorService: GlobalErrorService; + let route: ActivatedRoute; + let router: Router; + let store: MockStore; + let technicalRecordService: TechnicalRecordService; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AdrGenerateCertificateComponent], + providers: [ + GlobalErrorService, + provideMockActions(() => actions$), + provideMockStore({ initialState: initialAppState }), + { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, + { provide: DynamicFormService, useValue: mockDynamicFormService }, + TechnicalRecordService, + { + provide: UserService, + useValue: { + roles$: of(['TechRecord.Amend']), + }, + }, + ], + imports: [RouterTestingModule, SharedModule, ReactiveFormsModule, DynamicFormsModule, HttpClientTestingModule], + }).compileComponents(); + }); + beforeEach(() => { + fixture = TestBed.createComponent(AdrGenerateCertificateComponent); + errorService = TestBed.inject(GlobalErrorService); + route = TestBed.inject(ActivatedRoute); + router = TestBed.inject(Router); + store = TestBed.inject(MockStore); + technicalRecordService = TestBed.inject(TechnicalRecordService); + component = fixture.componentInstance; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('navigateBack', () => { + beforeEach(() => { + jest + .spyOn(technicalRecordService, 'techRecord$', 'get') + .mockReturnValue(of({ systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel)); + }); + it('should clear all errors', () => { + jest.spyOn(router, 'navigate').mockImplementation(); + + const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); + + component.navigateBack(); + + expect(clearErrorsSpy).toHaveBeenCalledTimes(1); + }); + + it('should navigate back to the previous page', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + component.navigateBack(); + + expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); + }); + + it('should navigate back on generateADRCertificateSuccess', fakeAsync(() => { + fixture.ngZone?.run(() => { + component.ngOnInit(); + component.form.get('certificateType')?.setValue('PASS'); + + const navigateBackSpy = jest.spyOn(component, 'navigateBack').mockImplementation(); + + component.handleSubmit(); + + actions$.next(generateADRCertificateSuccess({ id: '' })); + tick(); + + expect(navigateBackSpy).toHaveBeenCalled(); + }); + })); + }); + + describe('handleSubmit', () => { + beforeEach(() => { + jest + .spyOn(technicalRecordService, 'techRecord$', 'get') + .mockReturnValue(of({ systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel)); + }); + it('should add an error when the field is not filled out', () => { + const addErrorSpy = jest.spyOn(errorService, 'addError'); + + component.handleSubmit(); + + expect(addErrorSpy).toHaveBeenCalledWith({ + error: 'ADR Certificate Type is required', + anchorLink: 'certificateType', + }); + }); + + it('should dispatch the generateADRCertificate action', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + + component.form.get('certificateType')?.setValue('PASS'); + + component.handleSubmit(); + expect(dispatchSpy).toHaveBeenCalledTimes(2); + expect(dispatchSpy).toHaveBeenLastCalledWith( + generateADRCertificate({ systemNumber: '', createdTimestamp: '', certificateType: 'PASS' }) + ); + }); + + it('should dispatch action with default values when systemNumber and createdTimestamp are null', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + + component.form.get('certificateType')?.setValue('PASS'); + component.systemNumber = '123'; + component.createdTimestamp = '2021'; + + component.handleSubmit(); + expect(dispatchSpy).toHaveBeenCalled(); + expect(dispatchSpy).toHaveBeenLastCalledWith( + generateADRCertificate({ systemNumber: '123', createdTimestamp: '2021', certificateType: 'PASS' }) + ); + }); + }); + + describe('certificateTypes', () => { + it('should get correct value when call get functions', () => { + const expectedValue = [ + { label: 'New ADR Certificate', value: 'PASS' }, + { label: 'Replacement ADR Certificate', value: 'REPLACEMENT' }, + ]; + expect(component.width).toBe(10); + expect(component.certificateTypes).toEqual(expectedValue); + }); + }); }); diff --git a/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.ts b/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.ts index 12c729915c..3bfad24248 100644 --- a/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.ts +++ b/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.ts @@ -2,85 +2,91 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { FormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; -import { - CustomFormControl, FormNodeOption, FormNodeTypes, FormNodeWidth, -} from '@forms/services/dynamic-form.types'; -import { UserService } from '@services/user-service/user-service'; import { ADRCertificateTypes } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrCertificateTypes.enum.js'; -import { Subject, takeUntil, take } from 'rxjs'; +import { CustomFormControl, FormNodeOption, FormNodeTypes, FormNodeWidth } from '@forms/services/dynamic-form.types'; +import { Actions, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; +import { UserService } from '@services/user-service/user-service'; import { State } from '@store/index'; import { generateADRCertificate, generateADRCertificateSuccess } from '@store/technical-records'; -import { Actions, ofType } from '@ngrx/effects'; +import { Subject, take, takeUntil } from 'rxjs'; @Component({ - selector: 'app-adr-generate-certificate', - templateUrl: './adr-generate-certificate.component.html', + selector: 'app-adr-generate-certificate', + templateUrl: './adr-generate-certificate.component.html', }) export class AdrGenerateCertificateComponent implements OnInit, OnDestroy { - systemNumber?: string; - createdTimestamp?: string; - - form = new FormGroup({ - certificateType: new CustomFormControl({ - name: 'certificateType', label: 'Select certificate type', type: FormNodeTypes.CONTROL, - }, '', [Validators.required]), - }); + systemNumber?: string; + createdTimestamp?: string; - private destroy$ = new Subject(); + form = new FormGroup({ + certificateType: new CustomFormControl( + { + name: 'certificateType', + label: 'Select certificate type', + type: FormNodeTypes.CONTROL, + }, + '', + [Validators.required] + ), + }); - constructor( - private actions$: Actions, - private globalErrorService: GlobalErrorService, - private route: ActivatedRoute, - private router: Router, - public userService: UserService, - private store: Store, - ) {} + private destroy$ = new Subject(); - ngOnInit(): void { - this.route.params.pipe(takeUntil(this.destroy$)).subscribe((params) => { - this.systemNumber = params['systemNumber']; - this.createdTimestamp = params['createdTimestamp']; - }); - this.actions$.pipe(ofType(generateADRCertificateSuccess), take(1)).subscribe(() => { - this.navigateBack(); - }); - } + constructor( + private actions$: Actions, + private globalErrorService: GlobalErrorService, + private route: ActivatedRoute, + private router: Router, + public userService: UserService, + private store: Store + ) {} - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } + ngOnInit(): void { + this.route.params.pipe(takeUntil(this.destroy$)).subscribe((params) => { + this.systemNumber = params['systemNumber']; + this.createdTimestamp = params['createdTimestamp']; + }); + this.actions$.pipe(ofType(generateADRCertificateSuccess), take(1)).subscribe(() => { + this.navigateBack(); + }); + } - get width(): FormNodeWidth { - return FormNodeWidth.L; - } + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } - get certificateTypes(): Array> { - return [ - { label: 'New ADR Certificate', value: ADRCertificateTypes.PASS }, - { label: 'Replacement ADR Certificate', value: ADRCertificateTypes.REPLACEMENT }, + get width(): FormNodeWidth { + return FormNodeWidth.L; + } - ]; - } + get certificateTypes(): Array> { + return [ + { label: 'New ADR Certificate', value: ADRCertificateTypes.PASS }, + { label: 'Replacement ADR Certificate', value: ADRCertificateTypes.REPLACEMENT }, + ]; + } - navigateBack() { - this.globalErrorService.clearErrors(); - void this.router.navigate(['..'], { relativeTo: this.route }); - } + navigateBack() { + this.globalErrorService.clearErrors(); + void this.router.navigate(['..'], { relativeTo: this.route }); + } - handleSubmit(): void { - this.globalErrorService.clearErrors(); - if (!this.form.value.certificateType) { - return this.globalErrorService.addError({ error: 'ADR Certificate Type is required', anchorLink: 'certificateType' }); - } - this.store.dispatch(generateADRCertificate( - { - systemNumber: this.systemNumber ?? '', - createdTimestamp: this.createdTimestamp ?? '', - certificateType: this.form.value.certificateType, - }, - )); - } + handleSubmit(): void { + this.globalErrorService.clearErrors(); + if (!this.form.value.certificateType) { + return this.globalErrorService.addError({ + error: 'ADR Certificate Type is required', + anchorLink: 'certificateType', + }); + } + this.store.dispatch( + generateADRCertificate({ + systemNumber: this.systemNumber ?? '', + createdTimestamp: this.createdTimestamp ?? '', + certificateType: this.form.value.certificateType, + }) + ); + } } diff --git a/src/app/features/tech-record/components/edit-tech-record-button/edit-tech-record-button.component.spec.ts b/src/app/features/tech-record/components/edit-tech-record-button/edit-tech-record-button.component.spec.ts index 66080fdfa0..1dd1330d5e 100644 --- a/src/app/features/tech-record/components/edit-tech-record-button/edit-tech-record-button.component.spec.ts +++ b/src/app/features/tech-record/components/edit-tech-record-button/edit-tech-record-button.component.spec.ts @@ -1,8 +1,6 @@ import { APP_BASE_HREF } from '@angular/common'; import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { - ComponentFixture, discardPeriodicTasks, fakeAsync, TestBed, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, discardPeriodicTasks, fakeAsync } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; @@ -18,17 +16,17 @@ import { SharedModule } from '@shared/shared.module'; import { initialAppState } from '@store/.'; import { clearError } from '@store/global-error/actions/global-error.actions'; import { updateEditingTechRecordCancel } from '@store/technical-records'; -import { BehaviorSubject, of, ReplaySubject } from 'rxjs'; +import { BehaviorSubject, ReplaySubject, of } from 'rxjs'; import { EditTechRecordButtonComponent } from './edit-tech-record-button.component'; const mockTechRecordService = { - techRecord$: of({ - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_statusCode: StatusCodes.CURRENT, - } as V3TechRecordModel), - clearReasonForCreation: jest.fn(), + techRecord$: of({ + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_statusCode: StatusCodes.CURRENT, + } as V3TechRecordModel), + clearReasonForCreation: jest.fn(), }; let component: EditTechRecordButtonComponent; @@ -36,271 +34,273 @@ let fixture: ComponentFixture; let router: Router; let store: MockStore; let actions$: ReplaySubject; -const mockTechnicalRecordObservable = new BehaviorSubject({ techRecord_statusCode: StatusCodes.CURRENT } as V3TechRecordModel); +const mockTechnicalRecordObservable = new BehaviorSubject({ + techRecord_statusCode: StatusCodes.CURRENT, +} as V3TechRecordModel); const updateMockTechnicalRecord = (techRecord_statusCode: StatusCodes) => - mockTechnicalRecordObservable.next({ techRecord_statusCode } as V3TechRecordModel); + mockTechnicalRecordObservable.next({ techRecord_statusCode } as V3TechRecordModel); const mockRouterService = { - getRouteNestedParam$: () => '1', - getRouteDataProperty$: () => false, + getRouteNestedParam$: () => '1', + getRouteDataProperty$: () => false, }; describe('EditTechRecordButtonComponent', () => { - beforeEach(async () => { - actions$ = new ReplaySubject(); - - jest.clearAllMocks(); - - await TestBed.configureTestingModule({ - declarations: [EditTechRecordButtonComponent], - providers: [ - { provide: RouterService, useValue: mockRouterService }, - GlobalErrorService, - provideMockActions(() => actions$), - provideMockStore({ initialState: initialAppState }), - { provide: APP_BASE_HREF, useValue: '/' }, - { provide: TechnicalRecordService, useValue: mockTechRecordService }, - ], - imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule, SharedModule], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(EditTechRecordButtonComponent); - router = TestBed.inject(Router); - store = TestBed.inject(MockStore); - component = fixture.componentInstance; - - fixture.detectChanges(); - - jest.spyOn(window, 'confirm'); - }); - - describe('component', () => { - it('should create', () => { - expect(component).toBeTruthy(); - }); - }); - - describe('when viewing a tech record', () => { - afterAll(() => { - mockTechRecordService.techRecord$ = of({ - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_statusCode: StatusCodes.CURRENT, - } as unknown as V3TechRecordModel); - }); - it.each([ - [ - 'should be viewable', - true, - { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_statusCode: StatusCodes.PROVISIONAL, - } as V3TechRecordModel, - ], - [ - 'should be viewable', - true, - { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_statusCode: StatusCodes.CURRENT, - } as V3TechRecordModel, - ], - [ - 'should not be viewable', - false, - { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_statusCode: StatusCodes.ARCHIVED, - } as V3TechRecordModel, - ], - ])('edit button %s for %s record', (isViewable: string, expected: boolean, record: V3TechRecordModel) => { - mockTechRecordService.techRecord$ = of(record); - fixture.detectChanges(); - - const button = fixture.debugElement.query(By.css('#edit')); - expect(Boolean(button)).toEqual(expected); - }); - }); - - describe('when user clicks edit button', () => { - it('component should navigate away for current amendments', () => { - mockTechRecordService.techRecord$ = of({ - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_statusCode: StatusCodes.PROVISIONAL, - } as V3TechRecordModel); - const navigateSpy = jest.spyOn(router, 'navigate'); - jest.spyOn(window, 'scrollTo').mockImplementation(() => {}); - - fixture.detectChanges(); - fixture.debugElement.query(By.css('button#edit')).nativeElement.click(); - - expect(navigateSpy).toHaveBeenCalledWith(['notifiable-alteration-needed'], { relativeTo: expect.anything() }); - }); - it('component should navigate away for notifiable alterations', () => { - mockTechRecordService.techRecord$ = of({ - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_statusCode: StatusCodes.CURRENT, - } as V3TechRecordModel); - const navigateSpy = jest.spyOn(router, 'navigate'); - - fixture.detectChanges(); - fixture.debugElement.query(By.css('button#edit')).nativeElement.click(); - - expect(navigateSpy).toHaveBeenCalledWith(['amend-reason'], { relativeTo: expect.anything() }); - }); - }); - - describe('when amending a provisional tech record', () => { - beforeEach(() => { - component.isEditing = true; - }); - describe('and the user submits their changes', () => { - it('component should emit event', fakeAsync(() => { - const sumbitChangeSpy = jest.spyOn(component.submitChange, 'emit'); - - fixture.detectChanges(); - fixture.debugElement.query(By.css('button#submit')).nativeElement.click(); - discardPeriodicTasks(); - - expect(sumbitChangeSpy).toHaveBeenCalledTimes(1); - })); - }); - }); - - describe('when amending a current tech record', () => { - beforeEach(() => { - updateMockTechnicalRecord(StatusCodes.CURRENT); - component.isEditing = true; - }); - describe('and the user submits their changes', () => { - it('component should emit event', fakeAsync(() => { - const sumbitChangeSpy = jest.spyOn(component.submitChange, 'emit'); - - fixture.detectChanges(); - fixture.debugElement.query(By.css('button#submit')).nativeElement.click(); - discardPeriodicTasks(); - - expect(sumbitChangeSpy).toHaveBeenCalledTimes(1); - })); - }); - - describe('and the user cancels their changes', () => { - describe('and the form is dirty', () => { - beforeEach(() => { - component.isDirty = true; - jest.resetAllMocks(); - }); - - it('should prompt user if they wish to cancel', () => { - component.isEditing = true; - jest.spyOn(window, 'confirm').mockImplementation(() => true); - - fixture.detectChanges(); - - fixture.debugElement.query(By.css('button#cancel')).nativeElement.click(); - - expect(window.confirm).toHaveBeenCalledWith('Your changes will not be saved. Are you sure?'); - }); - - describe('and the user cancels cancelling an amendment', () => { - it('should keep user in edit view', fakeAsync(() => { - component.isEditing = true; - jest.spyOn(window, 'confirm').mockImplementation(() => false); - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const cancelSpy = jest.spyOn(component, 'cancel'); - const toggleEditModeSpy = jest.spyOn(component, 'toggleEditMode'); - const navigateSpy = jest.spyOn(router, 'navigate'); - - fixture.detectChanges(); - fixture.debugElement.query(By.css('button#cancel')).nativeElement.click(); - - discardPeriodicTasks(); - - expect(cancelSpy).toHaveBeenCalled(); - expect(toggleEditModeSpy).not.toHaveBeenCalled(); - expect(component.isEditingChange).toBeTruthy(); - expect(window.confirm).toHaveBeenCalledTimes(1); - expect(window.confirm).toHaveBeenCalledWith('Your changes will not be saved. Are you sure?'); - expect(navigateSpy).not.toHaveBeenCalled(); - expect(dispatchSpy).not.toHaveBeenCalled(); - expect(navigateSpy).not.toHaveBeenCalled(); - })); - }); - - describe('and the user confirms cancelling the amendment', () => { - it('should return user back to non-edit view', fakeAsync(() => { - component.isEditing = true; - jest.spyOn(window, 'confirm').mockImplementation(() => true); - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const cancelSpy = jest.spyOn(component, 'cancel'); - const toggleEditModeSpy = jest.spyOn(component, 'toggleEditMode'); - const navigateSpy = jest.spyOn(router, 'navigate'); - - fixture.detectChanges(); - fixture.debugElement.query(By.css('button#cancel')).nativeElement.click(); - - discardPeriodicTasks(); - - expect(navigateSpy).toHaveBeenCalled(); - expect(cancelSpy).toHaveBeenCalled(); - expect(toggleEditModeSpy).toHaveBeenCalled(); - expect(component.isEditing).toBeFalsy(); - expect(window.confirm).toHaveBeenCalledTimes(1); - expect(window.confirm).toHaveBeenCalledWith('Your changes will not be saved. Are you sure?'); - expect(dispatchSpy).toHaveBeenNthCalledWith(1, clearError()); - expect(dispatchSpy).toHaveBeenNthCalledWith(2, updateEditingTechRecordCancel()); - })); - }); - }); - - describe('and the form is not dirty', () => { - beforeEach(() => { - component.isDirty = false; - }); - - it('should not prompt user if they wish to cancel', fakeAsync(() => { - component.isEditing = true; - jest.spyOn(window, 'confirm'); - fixture.detectChanges(); - - fixture.debugElement.query(By.css('#cancel')).nativeElement.click(); - discardPeriodicTasks(); - expect(window.confirm).not.toHaveBeenCalled(); - })); - - it('should return user to non-edit view', fakeAsync(() => { - component.isEditing = true; - jest.spyOn(window, 'confirm'); - const cancelSpy = jest.spyOn(component, 'cancel'); - const toggleSpy = jest.spyOn(component, 'toggleEditMode'); - const dispatchSpy = jest.spyOn(store, 'dispatch'); - - fixture.detectChanges(); - - fixture.debugElement.query(By.css('button#cancel')).nativeElement.click(); - - discardPeriodicTasks(); - - expect(cancelSpy).toHaveBeenCalled(); - expect(toggleSpy).toHaveBeenCalled(); - expect(component.isEditing).toBeFalsy(); - expect(dispatchSpy).toHaveBeenNthCalledWith(1, clearError()); - expect(dispatchSpy).toHaveBeenNthCalledWith(2, updateEditingTechRecordCancel()); - })); - }); - }); - }); + beforeEach(async () => { + actions$ = new ReplaySubject(); + + jest.clearAllMocks(); + + await TestBed.configureTestingModule({ + declarations: [EditTechRecordButtonComponent], + providers: [ + { provide: RouterService, useValue: mockRouterService }, + GlobalErrorService, + provideMockActions(() => actions$), + provideMockStore({ initialState: initialAppState }), + { provide: APP_BASE_HREF, useValue: '/' }, + { provide: TechnicalRecordService, useValue: mockTechRecordService }, + ], + imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule, SharedModule], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(EditTechRecordButtonComponent); + router = TestBed.inject(Router); + store = TestBed.inject(MockStore); + component = fixture.componentInstance; + + fixture.detectChanges(); + + jest.spyOn(window, 'confirm'); + }); + + describe('component', () => { + it('should create', () => { + expect(component).toBeTruthy(); + }); + }); + + describe('when viewing a tech record', () => { + afterAll(() => { + mockTechRecordService.techRecord$ = of({ + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_statusCode: StatusCodes.CURRENT, + } as unknown as V3TechRecordModel); + }); + it.each([ + [ + 'should be viewable', + true, + { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_statusCode: StatusCodes.PROVISIONAL, + } as V3TechRecordModel, + ], + [ + 'should be viewable', + true, + { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_statusCode: StatusCodes.CURRENT, + } as V3TechRecordModel, + ], + [ + 'should not be viewable', + false, + { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_statusCode: StatusCodes.ARCHIVED, + } as V3TechRecordModel, + ], + ])('edit button %s for %s record', (isViewable: string, expected: boolean, record: V3TechRecordModel) => { + mockTechRecordService.techRecord$ = of(record); + fixture.detectChanges(); + + const button = fixture.debugElement.query(By.css('#edit')); + expect(Boolean(button)).toEqual(expected); + }); + }); + + describe('when user clicks edit button', () => { + it('component should navigate away for current amendments', () => { + mockTechRecordService.techRecord$ = of({ + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_statusCode: StatusCodes.PROVISIONAL, + } as V3TechRecordModel); + const navigateSpy = jest.spyOn(router, 'navigate'); + jest.spyOn(window, 'scrollTo').mockImplementation(() => {}); + + fixture.detectChanges(); + fixture.debugElement.query(By.css('button#edit')).nativeElement.click(); + + expect(navigateSpy).toHaveBeenCalledWith(['notifiable-alteration-needed'], { relativeTo: expect.anything() }); + }); + it('component should navigate away for notifiable alterations', () => { + mockTechRecordService.techRecord$ = of({ + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_statusCode: StatusCodes.CURRENT, + } as V3TechRecordModel); + const navigateSpy = jest.spyOn(router, 'navigate'); + + fixture.detectChanges(); + fixture.debugElement.query(By.css('button#edit')).nativeElement.click(); + + expect(navigateSpy).toHaveBeenCalledWith(['amend-reason'], { relativeTo: expect.anything() }); + }); + }); + + describe('when amending a provisional tech record', () => { + beforeEach(() => { + component.isEditing = true; + }); + describe('and the user submits their changes', () => { + it('component should emit event', fakeAsync(() => { + const sumbitChangeSpy = jest.spyOn(component.submitChange, 'emit'); + + fixture.detectChanges(); + fixture.debugElement.query(By.css('button#submit')).nativeElement.click(); + discardPeriodicTasks(); + + expect(sumbitChangeSpy).toHaveBeenCalledTimes(1); + })); + }); + }); + + describe('when amending a current tech record', () => { + beforeEach(() => { + updateMockTechnicalRecord(StatusCodes.CURRENT); + component.isEditing = true; + }); + describe('and the user submits their changes', () => { + it('component should emit event', fakeAsync(() => { + const sumbitChangeSpy = jest.spyOn(component.submitChange, 'emit'); + + fixture.detectChanges(); + fixture.debugElement.query(By.css('button#submit')).nativeElement.click(); + discardPeriodicTasks(); + + expect(sumbitChangeSpy).toHaveBeenCalledTimes(1); + })); + }); + + describe('and the user cancels their changes', () => { + describe('and the form is dirty', () => { + beforeEach(() => { + component.isDirty = true; + jest.resetAllMocks(); + }); + + it('should prompt user if they wish to cancel', () => { + component.isEditing = true; + jest.spyOn(window, 'confirm').mockImplementation(() => true); + + fixture.detectChanges(); + + fixture.debugElement.query(By.css('button#cancel')).nativeElement.click(); + + expect(window.confirm).toHaveBeenCalledWith('Your changes will not be saved. Are you sure?'); + }); + + describe('and the user cancels cancelling an amendment', () => { + it('should keep user in edit view', fakeAsync(() => { + component.isEditing = true; + jest.spyOn(window, 'confirm').mockImplementation(() => false); + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const cancelSpy = jest.spyOn(component, 'cancel'); + const toggleEditModeSpy = jest.spyOn(component, 'toggleEditMode'); + const navigateSpy = jest.spyOn(router, 'navigate'); + + fixture.detectChanges(); + fixture.debugElement.query(By.css('button#cancel')).nativeElement.click(); + + discardPeriodicTasks(); + + expect(cancelSpy).toHaveBeenCalled(); + expect(toggleEditModeSpy).not.toHaveBeenCalled(); + expect(component.isEditingChange).toBeTruthy(); + expect(window.confirm).toHaveBeenCalledTimes(1); + expect(window.confirm).toHaveBeenCalledWith('Your changes will not be saved. Are you sure?'); + expect(navigateSpy).not.toHaveBeenCalled(); + expect(dispatchSpy).not.toHaveBeenCalled(); + expect(navigateSpy).not.toHaveBeenCalled(); + })); + }); + + describe('and the user confirms cancelling the amendment', () => { + it('should return user back to non-edit view', fakeAsync(() => { + component.isEditing = true; + jest.spyOn(window, 'confirm').mockImplementation(() => true); + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const cancelSpy = jest.spyOn(component, 'cancel'); + const toggleEditModeSpy = jest.spyOn(component, 'toggleEditMode'); + const navigateSpy = jest.spyOn(router, 'navigate'); + + fixture.detectChanges(); + fixture.debugElement.query(By.css('button#cancel')).nativeElement.click(); + + discardPeriodicTasks(); + + expect(navigateSpy).toHaveBeenCalled(); + expect(cancelSpy).toHaveBeenCalled(); + expect(toggleEditModeSpy).toHaveBeenCalled(); + expect(component.isEditing).toBeFalsy(); + expect(window.confirm).toHaveBeenCalledTimes(1); + expect(window.confirm).toHaveBeenCalledWith('Your changes will not be saved. Are you sure?'); + expect(dispatchSpy).toHaveBeenNthCalledWith(1, clearError()); + expect(dispatchSpy).toHaveBeenNthCalledWith(2, updateEditingTechRecordCancel()); + })); + }); + }); + + describe('and the form is not dirty', () => { + beforeEach(() => { + component.isDirty = false; + }); + + it('should not prompt user if they wish to cancel', fakeAsync(() => { + component.isEditing = true; + jest.spyOn(window, 'confirm'); + fixture.detectChanges(); + + fixture.debugElement.query(By.css('#cancel')).nativeElement.click(); + discardPeriodicTasks(); + expect(window.confirm).not.toHaveBeenCalled(); + })); + + it('should return user to non-edit view', fakeAsync(() => { + component.isEditing = true; + jest.spyOn(window, 'confirm'); + const cancelSpy = jest.spyOn(component, 'cancel'); + const toggleSpy = jest.spyOn(component, 'toggleEditMode'); + const dispatchSpy = jest.spyOn(store, 'dispatch'); + + fixture.detectChanges(); + + fixture.debugElement.query(By.css('button#cancel')).nativeElement.click(); + + discardPeriodicTasks(); + + expect(cancelSpy).toHaveBeenCalled(); + expect(toggleSpy).toHaveBeenCalled(); + expect(component.isEditing).toBeFalsy(); + expect(dispatchSpy).toHaveBeenNthCalledWith(1, clearError()); + expect(dispatchSpy).toHaveBeenNthCalledWith(2, updateEditingTechRecordCancel()); + })); + }); + }); + }); }); diff --git a/src/app/features/tech-record/components/edit-tech-record-button/edit-tech-record-button.component.ts b/src/app/features/tech-record/components/edit-tech-record-button/edit-tech-record-button.component.ts index ece95dddf0..db7ff99785 100644 --- a/src/app/features/tech-record/components/edit-tech-record-button/edit-tech-record-button.component.ts +++ b/src/app/features/tech-record/components/edit-tech-record-button/edit-tech-record-button.component.ts @@ -1,7 +1,5 @@ import { ViewportScroller } from '@angular/common'; -import { - Component, EventEmitter, Input, OnDestroy, Output, -} from '@angular/core'; +import { Component, EventEmitter, Input, OnDestroy, Output } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { StatusCodes } from '@models/vehicle-tech-record.model'; @@ -9,83 +7,85 @@ import { Store } from '@ngrx/store'; import { RouterService } from '@services/router/router.service'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { clearAllSectionStates, clearScrollPosition, updateEditingTechRecordCancel } from '@store/technical-records'; -import { - Observable, Subject, distinctUntilChanged, map, takeUntil, -} from 'rxjs'; +import { Observable, Subject, distinctUntilChanged, map, takeUntil } from 'rxjs'; @Component({ - selector: 'app-edit-tech-record-button', - templateUrl: './edit-tech-record-button.component.html', + selector: 'app-edit-tech-record-button', + templateUrl: './edit-tech-record-button.component.html', }) export class EditTechRecordButtonComponent implements OnDestroy { - @Input() isEditing = false; - @Input() isDirty = false; - @Input() customId = ''; + @Input() isEditing = false; + @Input() isDirty = false; + @Input() customId = ''; - @Output() isEditingChange = new EventEmitter(); - @Output() submitChange = new EventEmitter(); - destroy$ = new Subject(); + @Output() isEditingChange = new EventEmitter(); + @Output() submitChange = new EventEmitter(); + destroy$ = new Subject(); - constructor( - private errorService: GlobalErrorService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - private technicalRecordService: TechnicalRecordService, - private viewportScroller: ViewportScroller, - private routerService: RouterService, - ) {} + constructor( + private errorService: GlobalErrorService, + private route: ActivatedRoute, + private router: Router, + private store: Store, + private technicalRecordService: TechnicalRecordService, + private viewportScroller: ViewportScroller, + private routerService: RouterService + ) {} - ngOnDestroy(): void { - this.destroy$.next(true); - this.destroy$.complete(); - } + ngOnDestroy(): void { + this.destroy$.next(true); + this.destroy$.complete(); + } - get isArchived$(): Observable { - return this.technicalRecordService.techRecord$.pipe( - map( - (techRecord) => !(techRecord?.techRecord_statusCode === StatusCodes.CURRENT || techRecord?.techRecord_statusCode === StatusCodes.PROVISIONAL), - ), - ); - } + get isArchived$(): Observable { + return this.technicalRecordService.techRecord$.pipe( + map( + (techRecord) => + !( + techRecord?.techRecord_statusCode === StatusCodes.CURRENT || + techRecord?.techRecord_statusCode === StatusCodes.PROVISIONAL + ) + ) + ); + } - checkIfEditableReasonRequired() { - this.technicalRecordService.techRecord$ - .pipe( - map((techRecord) => techRecord?.techRecord_statusCode), - takeUntil(this.destroy$), - distinctUntilChanged(), - ) - .subscribe((statusCode) => { - if (statusCode !== StatusCodes.PROVISIONAL) { - void this.router.navigate(['amend-reason'], { relativeTo: this.route }); - } else { - void this.router.navigate(['notifiable-alteration-needed'], { relativeTo: this.route }); - } - }); - this.technicalRecordService.clearReasonForCreation(); - } + checkIfEditableReasonRequired() { + this.technicalRecordService.techRecord$ + .pipe( + map((techRecord) => techRecord?.techRecord_statusCode), + takeUntil(this.destroy$), + distinctUntilChanged() + ) + .subscribe((statusCode) => { + if (statusCode !== StatusCodes.PROVISIONAL) { + void this.router.navigate(['amend-reason'], { relativeTo: this.route }); + } else { + void this.router.navigate(['notifiable-alteration-needed'], { relativeTo: this.route }); + } + }); + this.technicalRecordService.clearReasonForCreation(); + } - toggleEditMode() { - this.isEditing = !this.isEditing; - this.isEditingChange.emit(this.isEditing); - } + toggleEditMode() { + this.isEditing = !this.isEditing; + this.isEditingChange.emit(this.isEditing); + } - cancel() { - // eslint-disable-next-line no-restricted-globals, no-alert - if (!this.isDirty || confirm('Your changes will not be saved. Are you sure?')) { - this.toggleEditMode(); - this.errorService.clearErrors(); - this.store.dispatch(updateEditingTechRecordCancel()); - this.store.dispatch(clearAllSectionStates()); - this.store.dispatch(clearScrollPosition()); + cancel() { + // eslint-disable-next-line no-restricted-globals, no-alert + if (!this.isDirty || confirm('Your changes will not be saved. Are you sure?')) { + this.toggleEditMode(); + this.errorService.clearErrors(); + this.store.dispatch(updateEditingTechRecordCancel()); + this.store.dispatch(clearAllSectionStates()); + this.store.dispatch(clearScrollPosition()); - void this.router.navigate(['../'], { relativeTo: this.route }); - } - } + void this.router.navigate(['../'], { relativeTo: this.route }); + } + } - submit() { - this.submitChange.emit(); - this.viewportScroller.scrollToPosition([0, 0]); - } + submit() { + this.submitChange.emit(); + this.viewportScroller.scrollToPosition([0, 0]); + } } diff --git a/src/app/features/tech-record/components/tech-record-amend-reason/tech-record-amend-reason.component.spec.ts b/src/app/features/tech-record/components/tech-record-amend-reason/tech-record-amend-reason.component.spec.ts index 7f15c9beec..6e219d412d 100644 --- a/src/app/features/tech-record/components/tech-record-amend-reason/tech-record-amend-reason.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-amend-reason/tech-record-amend-reason.component.spec.ts @@ -9,98 +9,100 @@ import { StoreModule } from '@ngrx/store'; import { TechRecordAmendReasonComponent } from './tech-record-amend-reason.component'; describe('TechRecordAmendReasonComponent', () => { - let component: TechRecordAmendReasonComponent; - let fixture: ComponentFixture; - let route: ActivatedRoute; - let router: Router; + let component: TechRecordAmendReasonComponent; + let fixture: ComponentFixture; + let route: ActivatedRoute; + let router: Router; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TechRecordAmendReasonComponent], - imports: [ - RouterTestingModule.withRoutes([{ path: 'test-reason', component: jest.fn() }]), - DynamicFormsModule, - ReactiveFormsModule, - StoreModule.forRoot({}), - ], - providers: [GlobalErrorService], - }).compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TechRecordAmendReasonComponent], + imports: [ + RouterTestingModule.withRoutes([{ path: 'test-reason', component: jest.fn() }]), + DynamicFormsModule, + ReactiveFormsModule, + StoreModule.forRoot({}), + ], + providers: [GlobalErrorService], + }).compileComponents(); - route = TestBed.inject(ActivatedRoute); - router = TestBed.inject(Router); - }); + route = TestBed.inject(ActivatedRoute); + router = TestBed.inject(Router); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TechRecordAmendReasonComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(TechRecordAmendReasonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - describe('handleSubmit', () => { - let errorsService: GlobalErrorService; + describe('handleSubmit', () => { + let errorsService: GlobalErrorService; - beforeEach(() => { - errorsService = TestBed.inject(GlobalErrorService); - }); + beforeEach(() => { + errorsService = TestBed.inject(GlobalErrorService); + }); - it('should call handleSubmit', () => { - const handleSubmitSpy = jest.spyOn(component, 'handleSubmit').mockImplementation(); + it('should call handleSubmit', () => { + const handleSubmitSpy = jest.spyOn(component, 'handleSubmit').mockImplementation(); - fixture.debugElement.query(By.css('#submit')).nativeElement.click(); + fixture.debugElement.query(By.css('#submit')).nativeElement.click(); - expect(handleSubmitSpy).toHaveBeenCalledTimes(1); - }); + expect(handleSubmitSpy).toHaveBeenCalledTimes(1); + }); - it('should clear errors when the form is valid', () => { - component.form.get('reason')?.setValue('test-reason'); + it('should clear errors when the form is valid', () => { + component.form.get('reason')?.setValue('test-reason'); - const clearErrorsSpy = jest.spyOn(errorsService, 'clearErrors').mockImplementation(); + const clearErrorsSpy = jest.spyOn(errorsService, 'clearErrors').mockImplementation(); - fixture.debugElement.query(By.css('#submit')).nativeElement.click(); + fixture.debugElement.query(By.css('#submit')).nativeElement.click(); - expect(clearErrorsSpy).toHaveBeenCalledTimes(1); - }); + expect(clearErrorsSpy).toHaveBeenCalledTimes(1); + }); - it('should set errors when the form is invalid', () => { - const setErrorsSpy = jest.spyOn(errorsService, 'setErrors').mockImplementation(); + it('should set errors when the form is invalid', () => { + const setErrorsSpy = jest.spyOn(errorsService, 'setErrors').mockImplementation(); - fixture.debugElement.query(By.css('#submit')).nativeElement.click(); + fixture.debugElement.query(By.css('#submit')).nativeElement.click(); - expect(setErrorsSpy).toHaveBeenCalledTimes(1); - expect(setErrorsSpy).toHaveBeenCalledWith([{ anchorLink: 'reasonForAmend', error: 'Reason for amending is required' }]); - }); + expect(setErrorsSpy).toHaveBeenCalledTimes(1); + expect(setErrorsSpy).toHaveBeenCalledWith([ + { anchorLink: 'reasonForAmend', error: 'Reason for amending is required' }, + ]); + }); - it('should navigate when the form is valid and a reason is provided', () => { - component.form.get('reason')?.setValue('test-reason'); + it('should navigate when the form is valid and a reason is provided', () => { + component.form.get('reason')?.setValue('test-reason'); - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(); + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(); - fixture.debugElement.query(By.css('#submit')).nativeElement.click(); + fixture.debugElement.query(By.css('#submit')).nativeElement.click(); - expect(navigateSpy).toHaveBeenCalledTimes(1); - expect(navigateSpy).toHaveBeenCalledWith(['../test-reason'], { relativeTo: route }); - }); + expect(navigateSpy).toHaveBeenCalledTimes(1); + expect(navigateSpy).toHaveBeenCalledWith(['../test-reason'], { relativeTo: route }); + }); - it('should not navigate when the form is invalid', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(); + it('should not navigate when the form is invalid', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(); - fixture.debugElement.query(By.css('#submit')).nativeElement.click(); + fixture.debugElement.query(By.css('#submit')).nativeElement.click(); - expect(navigateSpy).not.toHaveBeenCalled(); - }); + expect(navigateSpy).not.toHaveBeenCalled(); + }); - it('should not navigate when a reason is not provided', () => { - component.form.removeControl('reason'); + it('should not navigate when a reason is not provided', () => { + component.form.removeControl('reason'); - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(); + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(); - fixture.debugElement.query(By.css('#submit')).nativeElement.click(); + fixture.debugElement.query(By.css('#submit')).nativeElement.click(); - expect(navigateSpy).not.toHaveBeenCalled(); - }); - }); + expect(navigateSpy).not.toHaveBeenCalled(); + }); + }); }); diff --git a/src/app/features/tech-record/components/tech-record-amend-reason/tech-record-amend-reason.component.ts b/src/app/features/tech-record/components/tech-record-amend-reason/tech-record-amend-reason.component.ts index 0dae7ac821..4e0c759b60 100644 --- a/src/app/features/tech-record/components/tech-record-amend-reason/tech-record-amend-reason.component.ts +++ b/src/app/features/tech-record/components/tech-record-amend-reason/tech-record-amend-reason.component.ts @@ -3,55 +3,65 @@ import { Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalError } from '@core/components/global-error/global-error.interface'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; -import { - CustomFormControl, CustomFormGroup, FormNodeOption, FormNodeTypes, -} from '@forms/services/dynamic-form.types'; +import { CustomFormControl, CustomFormGroup, FormNodeOption, FormNodeTypes } from '@forms/services/dynamic-form.types'; import { ReasonForEditing } from '@models/vehicle-tech-record.model'; @Component({ - selector: 'app-tech-amend-reason', - templateUrl: './tech-record-amend-reason.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-tech-amend-reason', + templateUrl: './tech-record-amend-reason.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class TechRecordAmendReasonComponent { - reasons: Array> = [ - { label: 'Correcting an error', value: ReasonForEditing.CORRECTING_AN_ERROR, hint: 'Amend the current technical record' }, - { - label: 'Notifiable alteration needed', - value: ReasonForEditing.NOTIFIABLE_ALTERATION_NEEDED, - hint: 'Create a new provisional technical record', - }, - ]; - - form: CustomFormGroup; - - constructor(private errorService: GlobalErrorService, private route: ActivatedRoute, private router: Router) { - this.errorService.clearErrors(); - - this.form = new CustomFormGroup( - { name: 'reasonForAmend', type: FormNodeTypes.GROUP }, - { reason: new CustomFormControl({ name: 'reason', type: FormNodeTypes.CONTROL }, undefined, [Validators.required]) }, - ); - } - - handleSubmit(): void { - const reason: string = this.form.get('reason')?.value; - const errors: GlobalError[] = [ - { - error: 'Reason for amending is required', - anchorLink: 'reasonForAmend', - }, - ]; - - if (this.form.valid) { - this.errorService.clearErrors(); - if (reason) { - void this.router.navigate([`../${reason}`], { relativeTo: this.route }); - } - - return; - } - - this.errorService.setErrors(errors); - } + reasons: Array> = [ + { + label: 'Correcting an error', + value: ReasonForEditing.CORRECTING_AN_ERROR, + hint: 'Amend the current technical record', + }, + { + label: 'Notifiable alteration needed', + value: ReasonForEditing.NOTIFIABLE_ALTERATION_NEEDED, + hint: 'Create a new provisional technical record', + }, + ]; + + form: CustomFormGroup; + + constructor( + private errorService: GlobalErrorService, + private route: ActivatedRoute, + private router: Router + ) { + this.errorService.clearErrors(); + + this.form = new CustomFormGroup( + { name: 'reasonForAmend', type: FormNodeTypes.GROUP }, + { + reason: new CustomFormControl({ name: 'reason', type: FormNodeTypes.CONTROL }, undefined, [ + Validators.required, + ]), + } + ); + } + + handleSubmit(): void { + const reason: string = this.form.get('reason')?.value; + const errors: GlobalError[] = [ + { + error: 'Reason for amending is required', + anchorLink: 'reasonForAmend', + }, + ]; + + if (this.form.valid) { + this.errorService.clearErrors(); + if (reason) { + void this.router.navigate([`../${reason}`], { relativeTo: this.route }); + } + + return; + } + + this.errorService.setErrors(errors); + } } diff --git a/src/app/features/tech-record/components/tech-record-amend-vin/tech-record-amend-vin.component.spec.ts b/src/app/features/tech-record/components/tech-record-amend-vin/tech-record-amend-vin.component.spec.ts index 8328405d89..c07c9b74bc 100644 --- a/src/app/features/tech-record/components/tech-record-amend-vin/tech-record-amend-vin.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-amend-vin/tech-record-amend-vin.component.spec.ts @@ -1,6 +1,4 @@ -import { - ComponentFixture, fakeAsync, TestBed, tick, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; import { ActivatedRoute, ActivatedRouteSnapshot, Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; @@ -17,112 +15,118 @@ import { SharedModule } from '@shared/shared.module'; import { initialAppState } from '@store/index'; import { selectRouteNestedParams } from '@store/router/selectors/router.selectors'; import { amendVin, amendVinSuccess } from '@store/technical-records'; -import { of, ReplaySubject } from 'rxjs'; +import { ReplaySubject, of } from 'rxjs'; import { AmendVinComponent } from './tech-record-amend-vin.component'; const mockTechRecordService = { - editableTechRecord$: of({}), - selectedVehicleTechRecord$: of({}), - viewableTechRecord$: jest.fn(), - updateEditingTechRecord: jest.fn(), - isUnique: jest.fn(), - getVehicleTypeWithSmallTrl: jest.fn(), - validateVinForUpdate: jest.fn().mockReturnValue(of(null)), + editableTechRecord$: of({}), + selectedVehicleTechRecord$: of({}), + viewableTechRecord$: jest.fn(), + updateEditingTechRecord: jest.fn(), + isUnique: jest.fn(), + getVehicleTypeWithSmallTrl: jest.fn(), + validateVinForUpdate: jest.fn().mockReturnValue(of(null)), }; const mockDynamicFormService = { - createForm: jest.fn(), + createForm: jest.fn(), }; describe('TechRecordChangeVinComponent', () => { - const actions$ = new ReplaySubject(); - let component: AmendVinComponent; - let errorService: GlobalErrorService; - let expectedTechRecord = {} as V3TechRecordModel; - let fixture: ComponentFixture; - let route: ActivatedRoute; - let router: Router; - let store: MockStore; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AmendVinComponent], - providers: [ - GlobalErrorService, - provideMockActions(() => actions$), - provideMockStore({ initialState: initialAppState }), - { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]), snapshot: new ActivatedRouteSnapshot() } }, - { provide: DynamicFormService, useValue: mockDynamicFormService }, - { provide: TechnicalRecordService, useValue: mockTechRecordService }, - ], - imports: [RouterTestingModule, SharedModule, ReactiveFormsModule, DynamicFormsModule], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(AmendVinComponent); - errorService = TestBed.inject(GlobalErrorService); - route = TestBed.inject(ActivatedRoute); - router = TestBed.inject(Router); - store = TestBed.inject(MockStore); - component = fixture.componentInstance; - component.form.controls['vin'].clearAsyncValidators(); - component.form.controls['vin'].setAsyncValidators(mockTechRecordService.validateVinForUpdate.bind(this)); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('handleSubmit', () => { - beforeEach(() => { - expectedTechRecord = { systemNumber: 'foo', createdTimestamp: 'bar', newVin: 'testVin' } as unknown as TechRecordType<'put'>; - component.techRecord = expectedTechRecord; - }); - it('should dispatch the amendVin action with the new vin', () => { - const createdTimestamp = '2022'; - const systemNumber = '123456'; - const newVin = 'myNewVin'; - store.overrideSelector(selectRouteNestedParams, { createdTimestamp, systemNumber }); - const dispatchSpy = jest.spyOn(store, 'dispatch'); - - component.form.controls['vin'].setValue('myNewVin'); - - component.handleSubmit(); - - expect(dispatchSpy).toHaveBeenCalledWith(amendVin({ newVin, systemNumber, createdTimestamp })); - }); - }); - - describe('navigateBack', () => { - it('should clear all errors', () => { - jest.spyOn(router, 'navigate').mockImplementation(); - - const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); - - component.navigateBack(); - - expect(clearErrorsSpy).toHaveBeenCalledTimes(1); - }); - - it('should navigate back to the previous page', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - component.navigateBack(); - - expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); - }); - - it('should navigate away amendVinSuccess', fakeAsync(() => { - const navigateSpy = jest.spyOn(router, 'navigate'); - jest.spyOn(router, 'navigate').mockImplementation(); - - actions$.next( - amendVinSuccess({ vehicleTechRecord: { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'> }), - ); - tick(); - - expect(navigateSpy).toHaveBeenCalled(); - })); - }); + const actions$ = new ReplaySubject(); + let component: AmendVinComponent; + let errorService: GlobalErrorService; + let expectedTechRecord = {} as V3TechRecordModel; + let fixture: ComponentFixture; + let route: ActivatedRoute; + let router: Router; + let store: MockStore; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AmendVinComponent], + providers: [ + GlobalErrorService, + provideMockActions(() => actions$), + provideMockStore({ initialState: initialAppState }), + { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]), snapshot: new ActivatedRouteSnapshot() } }, + { provide: DynamicFormService, useValue: mockDynamicFormService }, + { provide: TechnicalRecordService, useValue: mockTechRecordService }, + ], + imports: [RouterTestingModule, SharedModule, ReactiveFormsModule, DynamicFormsModule], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AmendVinComponent); + errorService = TestBed.inject(GlobalErrorService); + route = TestBed.inject(ActivatedRoute); + router = TestBed.inject(Router); + store = TestBed.inject(MockStore); + component = fixture.componentInstance; + component.form.controls['vin'].clearAsyncValidators(); + component.form.controls['vin'].setAsyncValidators(mockTechRecordService.validateVinForUpdate.bind(this)); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('handleSubmit', () => { + beforeEach(() => { + expectedTechRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + newVin: 'testVin', + } as unknown as TechRecordType<'put'>; + component.techRecord = expectedTechRecord; + }); + it('should dispatch the amendVin action with the new vin', () => { + const createdTimestamp = '2022'; + const systemNumber = '123456'; + const newVin = 'myNewVin'; + store.overrideSelector(selectRouteNestedParams, { createdTimestamp, systemNumber }); + const dispatchSpy = jest.spyOn(store, 'dispatch'); + + component.form.controls['vin'].setValue('myNewVin'); + + component.handleSubmit(); + + expect(dispatchSpy).toHaveBeenCalledWith(amendVin({ newVin, systemNumber, createdTimestamp })); + }); + }); + + describe('navigateBack', () => { + it('should clear all errors', () => { + jest.spyOn(router, 'navigate').mockImplementation(); + + const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); + + component.navigateBack(); + + expect(clearErrorsSpy).toHaveBeenCalledTimes(1); + }); + + it('should navigate back to the previous page', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + component.navigateBack(); + + expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); + }); + + it('should navigate away amendVinSuccess', fakeAsync(() => { + const navigateSpy = jest.spyOn(router, 'navigate'); + jest.spyOn(router, 'navigate').mockImplementation(); + + actions$.next( + amendVinSuccess({ + vehicleTechRecord: { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>, + }) + ); + tick(); + + expect(navigateSpy).toHaveBeenCalled(); + })); + }); }); diff --git a/src/app/features/tech-record/components/tech-record-amend-vin/tech-record-amend-vin.component.ts b/src/app/features/tech-record/components/tech-record-amend-vin/tech-record-amend-vin.component.ts index d8dc24693c..62dfa64f23 100644 --- a/src/app/features/tech-record/components/tech-record-amend-vin/tech-record-amend-vin.component.ts +++ b/src/app/features/tech-record/components/tech-record-amend-vin/tech-record-amend-vin.component.ts @@ -14,139 +14,143 @@ import { RouterService } from '@services/router/router.service'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { State } from '@store/index'; import { amendVin, amendVinSuccess } from '@store/technical-records'; -import { - Subject, take, takeUntil, withLatestFrom, -} from 'rxjs'; +import { Subject, take, takeUntil, withLatestFrom } from 'rxjs'; @Component({ - selector: 'app-change-amend-vin', - templateUrl: './tech-record-amend-vin.component.html', + selector: 'app-change-amend-vin', + templateUrl: './tech-record-amend-vin.component.html', }) export class AmendVinComponent implements OnDestroy, OnInit { - techRecord?: V3TechRecordModel; - form!: FormGroup; - private destroy$ = new Subject(); - - constructor( - private actions$: Actions, - private globalErrorService: GlobalErrorService, - private route: ActivatedRoute, - private router: Router, - private technicalRecordService: TechnicalRecordService, - private routerService: RouterService, - private store: Store, - ) { - this.initForm(); - this.handleAmendVinSuccess(); - } - - ngOnInit(): void { - this.subscribeToTechRecordUpdates(); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - get width(): FormNodeWidth { - return FormNodeWidth.L; - } - - get vehicleType(): VehicleTypes | undefined { - return this.techRecord ? this.technicalRecordService.getVehicleTypeWithSmallTrl(this.techRecord) : undefined; - } - - get makeAndModel(): string | undefined { - return this.techRecord ? this.technicalRecordService.getMakeAndModel(this.techRecord) : undefined; - } - - get currentVrm(): string | undefined { - return this.techRecord?.techRecord_vehicleType !== 'trl' ? this.techRecord?.primaryVrm ?? '' : undefined; - } - - isFormValid(): boolean { - const errors: GlobalError[] = []; - DynamicFormService.validate(this.form, errors); - this.globalErrorService.setErrors(errors); - - if (this.form.value.vin === this.techRecord?.vin) { - this.globalErrorService.addError({ error: 'You must provide a new VIN', anchorLink: 'newVin' }); - return false; - } - - return this.form.valid; - } - - navigateBack(): void { - this.globalErrorService.clearErrors(); - void this.router.navigate(['..'], { relativeTo: this.route }); - } - - handleSubmit(): void { - if (this.shouldUpdateTechRecord()) { - this.updateTechRecord(); - } - } - - private initForm(): void { - this.form = new FormGroup({ - vin: new CustomFormControl( - { - name: 'input-vin', - label: 'Vin', - type: FormNodeTypes.CONTROL, - }, - '', - [ - CustomValidators.alphanumeric(), - Validators.minLength(3), - Validators.maxLength(21), - Validators.required, - CustomValidators.validateVinCharacters(), - ], - [this.technicalRecordService.validateVinForUpdate(this.techRecord?.vin)], - ), - }); - } - - private handleAmendVinSuccess(): void { - this.actions$.pipe(ofType(amendVinSuccess), takeUntil(this.destroy$)).subscribe(({ vehicleTechRecord }) => { - void this.router.navigate([`/tech-records/${vehicleTechRecord.systemNumber}/${vehicleTechRecord.createdTimestamp}`]); - }); - } - - private subscribeToTechRecordUpdates(): void { - this.technicalRecordService.techRecord$.pipe(takeUntil(this.destroy$)).subscribe((record) => { - if (record?.techRecord_statusCode === 'archived' || !record) { - this.navigateBack(); - } else { - this.techRecord = record; - } - }); - } - - private shouldUpdateTechRecord(): boolean { - return this.isFormValid() || (this.form.status === 'PENDING' && this.form.errors === null); - } - - private updateTechRecord(): void { - const record = { ...this.techRecord } as TechRecordType<'put'>; - record.vin = this.form.value.vin; - - this.technicalRecordService.updateEditingTechRecord({ - ...record, - techRecord_reasonForCreation: 'Vin changed', - }); - - this.routerService - .getRouteNestedParam$('systemNumber') - .pipe(take(1), takeUntil(this.destroy$), withLatestFrom(this.routerService.getRouteNestedParam$('createdTimestamp'))) - .subscribe(([systemNumber, createdTimestamp]) => { - if (systemNumber && createdTimestamp) { - const newVin = this.form.value.vin; - this.store.dispatch(amendVin({ newVin, systemNumber, createdTimestamp })); - } - }); - } + techRecord?: V3TechRecordModel; + form!: FormGroup; + private destroy$ = new Subject(); + + constructor( + private actions$: Actions, + private globalErrorService: GlobalErrorService, + private route: ActivatedRoute, + private router: Router, + private technicalRecordService: TechnicalRecordService, + private routerService: RouterService, + private store: Store + ) { + this.initForm(); + this.handleAmendVinSuccess(); + } + + ngOnInit(): void { + this.subscribeToTechRecordUpdates(); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + get width(): FormNodeWidth { + return FormNodeWidth.L; + } + + get vehicleType(): VehicleTypes | undefined { + return this.techRecord ? this.technicalRecordService.getVehicleTypeWithSmallTrl(this.techRecord) : undefined; + } + + get makeAndModel(): string | undefined { + return this.techRecord ? this.technicalRecordService.getMakeAndModel(this.techRecord) : undefined; + } + + get currentVrm(): string | undefined { + return this.techRecord?.techRecord_vehicleType !== 'trl' ? this.techRecord?.primaryVrm ?? '' : undefined; + } + + isFormValid(): boolean { + const errors: GlobalError[] = []; + DynamicFormService.validate(this.form, errors); + this.globalErrorService.setErrors(errors); + + if (this.form.value.vin === this.techRecord?.vin) { + this.globalErrorService.addError({ error: 'You must provide a new VIN', anchorLink: 'newVin' }); + return false; + } + + return this.form.valid; + } + + navigateBack(): void { + this.globalErrorService.clearErrors(); + void this.router.navigate(['..'], { relativeTo: this.route }); + } + + handleSubmit(): void { + if (this.shouldUpdateTechRecord()) { + this.updateTechRecord(); + } + } + + private initForm(): void { + this.form = new FormGroup({ + vin: new CustomFormControl( + { + name: 'input-vin', + label: 'Vin', + type: FormNodeTypes.CONTROL, + }, + '', + [ + CustomValidators.alphanumeric(), + Validators.minLength(3), + Validators.maxLength(21), + Validators.required, + CustomValidators.validateVinCharacters(), + ], + [this.technicalRecordService.validateVinForUpdate(this.techRecord?.vin)] + ), + }); + } + + private handleAmendVinSuccess(): void { + this.actions$.pipe(ofType(amendVinSuccess), takeUntil(this.destroy$)).subscribe(({ vehicleTechRecord }) => { + void this.router.navigate([ + `/tech-records/${vehicleTechRecord.systemNumber}/${vehicleTechRecord.createdTimestamp}`, + ]); + }); + } + + private subscribeToTechRecordUpdates(): void { + this.technicalRecordService.techRecord$.pipe(takeUntil(this.destroy$)).subscribe((record) => { + if (record?.techRecord_statusCode === 'archived' || !record) { + this.navigateBack(); + } else { + this.techRecord = record; + } + }); + } + + private shouldUpdateTechRecord(): boolean { + return this.isFormValid() || (this.form.status === 'PENDING' && this.form.errors === null); + } + + private updateTechRecord(): void { + const record = { ...this.techRecord } as TechRecordType<'put'>; + record.vin = this.form.value.vin; + + this.technicalRecordService.updateEditingTechRecord({ + ...record, + techRecord_reasonForCreation: 'Vin changed', + }); + + this.routerService + .getRouteNestedParam$('systemNumber') + .pipe( + take(1), + takeUntil(this.destroy$), + withLatestFrom(this.routerService.getRouteNestedParam$('createdTimestamp')) + ) + .subscribe(([systemNumber, createdTimestamp]) => { + if (systemNumber && createdTimestamp) { + const newVin = this.form.value.vin; + this.store.dispatch(amendVin({ newVin, systemNumber, createdTimestamp })); + } + }); + } } diff --git a/src/app/features/tech-record/components/tech-record-amend-vrm-reason/tech-record-amend-vrm-reason.component.spec.ts b/src/app/features/tech-record/components/tech-record-amend-vrm-reason/tech-record-amend-vrm-reason.component.spec.ts index cbe521e7ba..10719b606a 100644 --- a/src/app/features/tech-record/components/tech-record-amend-vrm-reason/tech-record-amend-vrm-reason.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-amend-vrm-reason/tech-record-amend-vrm-reason.component.spec.ts @@ -1,7 +1,5 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { - ComponentFixture, TestBed, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; import { ActivatedRoute, ActivatedRouteSnapshot, Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; @@ -18,68 +16,70 @@ import { ReplaySubject, of } from 'rxjs'; import { AmendVrmReasonComponent } from './tech-record-amend-vrm-reason.component'; const mockDynamicFormService = { - createForm: jest.fn(), + createForm: jest.fn(), }; describe('TechRecordChangeVrmComponent', () => { - const actions$ = new ReplaySubject(); - let component: AmendVrmReasonComponent; - let errorService: GlobalErrorService; - let fixture: ComponentFixture; - let router: Router; + const actions$ = new ReplaySubject(); + let component: AmendVrmReasonComponent; + let errorService: GlobalErrorService; + let fixture: ComponentFixture; + let router: Router; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AmendVrmReasonComponent], - providers: [ - GlobalErrorService, - provideMockActions(() => actions$), - provideMockStore({ initialState: initialAppState }), - { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]), snapshot: new ActivatedRouteSnapshot() } }, - { provide: DynamicFormService, useValue: mockDynamicFormService }, - TechnicalRecordService, - ], - imports: [RouterTestingModule, SharedModule, ReactiveFormsModule, DynamicFormsModule, HttpClientTestingModule], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AmendVrmReasonComponent], + providers: [ + GlobalErrorService, + provideMockActions(() => actions$), + provideMockStore({ initialState: initialAppState }), + { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]), snapshot: new ActivatedRouteSnapshot() } }, + { provide: DynamicFormService, useValue: mockDynamicFormService }, + TechnicalRecordService, + ], + imports: [RouterTestingModule, SharedModule, ReactiveFormsModule, DynamicFormsModule, HttpClientTestingModule], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(AmendVrmReasonComponent); - errorService = TestBed.inject(GlobalErrorService); - router = TestBed.inject(Router); - component = fixture.componentInstance; - }); + beforeEach(() => { + fixture = TestBed.createComponent(AmendVrmReasonComponent); + errorService = TestBed.inject(GlobalErrorService); + router = TestBed.inject(Router); + component = fixture.componentInstance; + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); - describe('errors', () => { - it('should add an error when the reason for amending is not selected', () => { - const addErrorSpy = jest.spyOn(errorService, 'setErrors'); + it('should create', () => { + expect(component).toBeTruthy(); + }); + describe('errors', () => { + it('should add an error when the reason for amending is not selected', () => { + const addErrorSpy = jest.spyOn(errorService, 'setErrors'); - component.submit(); + component.submit(); - expect(addErrorSpy).toHaveBeenCalledWith([{ error: 'Reason for change is required', anchorLink: 'is-cherished-transfer' }]); - }); - }); - describe('submit', () => { - it('should navigate to correct-error', () => { - fixture.ngZone?.run(() => { - const navigationSpy = jest.spyOn(router, 'navigate'); - component.form.controls['isCherishedTransfer'].setValue('correcting-error'); - component.submit(); + expect(addErrorSpy).toHaveBeenCalledWith([ + { error: 'Reason for change is required', anchorLink: 'is-cherished-transfer' }, + ]); + }); + }); + describe('submit', () => { + it('should navigate to correct-error', () => { + fixture.ngZone?.run(() => { + const navigationSpy = jest.spyOn(router, 'navigate'); + component.form.controls['isCherishedTransfer'].setValue('correcting-error'); + component.submit(); - expect(navigationSpy).toHaveBeenCalledWith(['correcting-error'], { relativeTo: expect.anything() }); - }); - }); - it('should navigate to cherished-transfer', () => { - fixture.ngZone?.run(() => { - const navigationSpy = jest.spyOn(router, 'navigate'); - component.form.controls['isCherishedTransfer'].setValue('cherished-transfer'); - component.submit(); + expect(navigationSpy).toHaveBeenCalledWith(['correcting-error'], { relativeTo: expect.anything() }); + }); + }); + it('should navigate to cherished-transfer', () => { + fixture.ngZone?.run(() => { + const navigationSpy = jest.spyOn(router, 'navigate'); + component.form.controls['isCherishedTransfer'].setValue('cherished-transfer'); + component.submit(); - expect(navigationSpy).toHaveBeenCalledWith(['cherished-transfer'], { relativeTo: expect.anything() }); - }); - }); - }); + expect(navigationSpy).toHaveBeenCalledWith(['cherished-transfer'], { relativeTo: expect.anything() }); + }); + }); + }); }); diff --git a/src/app/features/tech-record/components/tech-record-amend-vrm-reason/tech-record-amend-vrm-reason.component.ts b/src/app/features/tech-record/components/tech-record-amend-vrm-reason/tech-record-amend-vrm-reason.component.ts index e2510c0a79..1cc889cb7c 100644 --- a/src/app/features/tech-record/components/tech-record-amend-vrm-reason/tech-record-amend-vrm-reason.component.ts +++ b/src/app/features/tech-record/components/tech-record-amend-vrm-reason/tech-record-amend-vrm-reason.component.ts @@ -4,90 +4,88 @@ import { ActivatedRoute, Router } from '@angular/router'; import { GlobalError } from '@core/components/global-error/global-error.interface'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; -import { - CustomFormControl, FormNodeOption, FormNodeTypes, FormNodeWidth, -} from '@forms/services/dynamic-form.types'; +import { CustomFormControl, FormNodeOption, FormNodeTypes, FormNodeWidth } from '@forms/services/dynamic-form.types'; import { VehicleTypes, VehiclesOtherThan } from '@models/vehicle-tech-record.model'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { Subject, take, takeUntil } from 'rxjs'; @Component({ - selector: 'app-amend-vrm-reason', - templateUrl: './tech-record-amend-vrm-reason.component.html', - styleUrls: ['./tech-record-amend-vrm-reason.component.scss'], + selector: 'app-amend-vrm-reason', + templateUrl: './tech-record-amend-vrm-reason.component.html', + styleUrls: ['./tech-record-amend-vrm-reason.component.scss'], }) export class AmendVrmReasonComponent implements OnDestroy, OnInit { - techRecord?: VehiclesOtherThan<'trl'>; - makeAndModel?: string; - - form = new FormGroup({ - isCherishedTransfer: new CustomFormControl( - { name: 'is-cherished-transfer', label: 'Reason for change', type: FormNodeTypes.CONTROL }, - undefined, - [Validators.required], - ), - }); - - private destroy$ = new Subject(); - - constructor( - public dfs: DynamicFormService, - private globalErrorService: GlobalErrorService, - private route: ActivatedRoute, - private router: Router, - private technicalRecordService: TechnicalRecordService, - ) {} - - ngOnInit(): void { - this.technicalRecordService.techRecord$.pipe(take(1), takeUntil(this.destroy$)).subscribe((record) => { - if (record?.techRecord_statusCode === 'archived' || !record) { - return this.navigateBack(); - } - this.techRecord = record as VehiclesOtherThan<'trl'>; - this.makeAndModel = this.technicalRecordService.getMakeAndModel(record); - }); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - get reasons(): Array> { - return [ - { label: 'Cherished transfer', value: 'cherished-transfer', hint: 'Current VRM will be archived' }, - { label: 'Correcting an error', value: 'correcting-error', hint: 'Current VRM will not be archived' }, - ]; - } - - get width(): FormNodeWidth { - return FormNodeWidth.L; - } - - get vehicleType(): VehicleTypes | undefined { - return this.techRecord ? this.technicalRecordService.getVehicleTypeWithSmallTrl(this.techRecord) : undefined; - } - - navigateBack() { - this.globalErrorService.clearErrors(); - void this.router.navigate(['..'], { relativeTo: this.route }); - } - - submit(): void { - if (!this.isFormValid) { - return; - } - - void this.router.navigate([this.form.controls['isCherishedTransfer'].value], { relativeTo: this.route }); - } - - get isFormValid(): boolean { - const errors: GlobalError[] = []; - - DynamicFormService.validate(this.form, errors); - - this.globalErrorService.setErrors(errors); - - return this.form.valid; - } + techRecord?: VehiclesOtherThan<'trl'>; + makeAndModel?: string; + + form = new FormGroup({ + isCherishedTransfer: new CustomFormControl( + { name: 'is-cherished-transfer', label: 'Reason for change', type: FormNodeTypes.CONTROL }, + undefined, + [Validators.required] + ), + }); + + private destroy$ = new Subject(); + + constructor( + public dfs: DynamicFormService, + private globalErrorService: GlobalErrorService, + private route: ActivatedRoute, + private router: Router, + private technicalRecordService: TechnicalRecordService + ) {} + + ngOnInit(): void { + this.technicalRecordService.techRecord$.pipe(take(1), takeUntil(this.destroy$)).subscribe((record) => { + if (record?.techRecord_statusCode === 'archived' || !record) { + return this.navigateBack(); + } + this.techRecord = record as VehiclesOtherThan<'trl'>; + this.makeAndModel = this.technicalRecordService.getMakeAndModel(record); + }); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + get reasons(): Array> { + return [ + { label: 'Cherished transfer', value: 'cherished-transfer', hint: 'Current VRM will be archived' }, + { label: 'Correcting an error', value: 'correcting-error', hint: 'Current VRM will not be archived' }, + ]; + } + + get width(): FormNodeWidth { + return FormNodeWidth.L; + } + + get vehicleType(): VehicleTypes | undefined { + return this.techRecord ? this.technicalRecordService.getVehicleTypeWithSmallTrl(this.techRecord) : undefined; + } + + navigateBack() { + this.globalErrorService.clearErrors(); + void this.router.navigate(['..'], { relativeTo: this.route }); + } + + submit(): void { + if (!this.isFormValid) { + return; + } + + void this.router.navigate([this.form.controls['isCherishedTransfer'].value], { relativeTo: this.route }); + } + + get isFormValid(): boolean { + const errors: GlobalError[] = []; + + DynamicFormService.validate(this.form, errors); + + this.globalErrorService.setErrors(errors); + + return this.form.valid; + } } diff --git a/src/app/features/tech-record/components/tech-record-amend-vrm/tech-record-amend-vrm.component.spec.ts b/src/app/features/tech-record/components/tech-record-amend-vrm/tech-record-amend-vrm.component.spec.ts index 962cf5989f..0f25609fce 100644 --- a/src/app/features/tech-record/components/tech-record-amend-vrm/tech-record-amend-vrm.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-amend-vrm/tech-record-amend-vrm.component.spec.ts @@ -1,4 +1,4 @@ -import { ComponentFixture, fakeAsync, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; import { ActivatedRoute, ActivatedRouteSnapshot, Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; @@ -12,191 +12,211 @@ import { Action } from '@ngrx/store'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { SharedModule } from '@shared/shared.module'; -import { initialAppState, State } from '@store/index'; +import { State, initialAppState } from '@store/index'; import { selectRouteData } from '@store/router/selectors/router.selectors'; import { amendVrm, amendVrmSuccess } from '@store/technical-records'; -import { of, ReplaySubject } from 'rxjs'; +import { ReplaySubject, of } from 'rxjs'; import { AmendVrmComponent } from './tech-record-amend-vrm.component'; const mockTechRecordService = { - techRecord$: of({}), - get viewableTechRecord$() { - return of({ - systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin', primaryVrm: 'TESTVRM', - }); - }, - updateEditingTechRecord: jest.fn(), - validateVrmDoesNotExist: jest.fn(), - validateVrmForCherishedTransfer: jest.fn(), - checkVrmNotActive: jest.fn(), - getVehicleTypeWithSmallTrl: jest.fn(), + techRecord$: of({}), + get viewableTechRecord$() { + return of({ + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + primaryVrm: 'TESTVRM', + }); + }, + updateEditingTechRecord: jest.fn(), + validateVrmDoesNotExist: jest.fn(), + validateVrmForCherishedTransfer: jest.fn(), + checkVrmNotActive: jest.fn(), + getVehicleTypeWithSmallTrl: jest.fn(), }; const mockDynamicFormService = { - createForm: jest.fn(), + createForm: jest.fn(), }; describe('TechRecordChangeVrmComponent', () => { - const actions$ = new ReplaySubject(); - let component: AmendVrmComponent; - let errorService: GlobalErrorService; - let fixture: ComponentFixture; - let route: ActivatedRoute; - let router: Router; - let store: MockStore; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AmendVrmComponent], - providers: [ - GlobalErrorService, - provideMockActions(() => actions$), - provideMockStore({ initialState: initialAppState }), - { provide: ActivatedRoute, useValue: { params: of([{ id: 1, reason: 'correcting-error' }]), snapshot: new ActivatedRouteSnapshot() } }, - { provide: DynamicFormService, useValue: mockDynamicFormService }, - { provide: TechnicalRecordService, useValue: mockTechRecordService }, - ], - imports: [RouterTestingModule, SharedModule, ReactiveFormsModule], - }).compileComponents(); - }); - beforeEach(() => { - fixture = TestBed.createComponent(AmendVrmComponent); - errorService = TestBed.inject(GlobalErrorService); - route = TestBed.inject(ActivatedRoute); - router = TestBed.inject(Router); - store = TestBed.inject(MockStore); - component = fixture.componentInstance; - component.cherishedTransferForm.controls['currentVrm'].clearAsyncValidators(); - component.cherishedTransferForm.controls['currentVrm'].setAsyncValidators(mockTechRecordService.validateVrmForCherishedTransfer.bind(this)); - component.cherishedTransferForm.controls['thirdMark'].clearAsyncValidators(); - component.cherishedTransferForm.controls['thirdMark'].setAsyncValidators(mockTechRecordService.validateVrmDoesNotExist.bind(this)); - component.correctingAnErrorForm.controls['newVrm'].clearAsyncValidators(); - component.correctingAnErrorForm.controls['newVrm'].setAsyncValidators(mockTechRecordService.validateVrmDoesNotExist.bind(this)); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('navigateBack', () => { - it('should clear all errors', () => { - jest.spyOn(router, 'navigate').mockImplementation(); - - const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); - - component.navigateBack(); - - expect(clearErrorsSpy).toHaveBeenCalledTimes(1); - }); - - it('should navigate back to the previous page', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - component.navigateBack(); - - expect(navigateSpy).toHaveBeenCalledWith(['../../'], { relativeTo: route }); - }); - - it('should navigate to a new record on amendVrmSuccess', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - store.overrideSelector(selectRouteData, { data: { isEditing: true } }); - component.ngOnInit(); - - actions$.next(amendVrmSuccess({ vehicleTechRecord: mockVehicleTechnicalRecord('psv') as TechRecordType<'get'> })); - - expect(navigateSpy).toHaveBeenCalled(); - }); - }); - - describe('handleSubmit', () => { - beforeEach(() => { - component.techRecord = mockVehicleTechnicalRecord('psv') as VehiclesOtherThan<'trl'>; - jest.resetAllMocks(); - jest.resetModules(); - }); - - it('should add an error when the vrm field is not filled out', () => { - const addErrorSpy = jest.spyOn(errorService, 'setErrors'); - - component.handleSubmit(); - - expect(addErrorSpy).toHaveBeenCalledWith([{ anchorLink: 'new-Vrm', error: 'New VRM is required' }]); - }); - - it('should not dispatch an action if isFormValid returns false', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - - component.handleSubmit(); - - expect(dispatchSpy).not.toHaveBeenCalledWith( - amendVrm({ - newVrm: '', - cherishedTransfer: false, - thirdMark: '', - systemNumber: 'PSV', - createdTimestamp: 'now', - }), - ); - }); - it('should dispatch the amendVrm action', fakeAsync(() => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - mockTechRecordService.validateVrmDoesNotExist.mockReturnValue(of(null)); - component.correctingAnErrorForm.controls['newVrm'].setValue('TESTVRM1'); - - component.handleSubmit(); - - expect(dispatchSpy).toHaveBeenCalledWith( - amendVrm({ - newVrm: 'TESTVRM1', cherishedTransfer: false, systemNumber: 'PSV', createdTimestamp: 'now', thirdMark: undefined, - }), - ); - })); - it('should dispatch the action with the correct information', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - mockTechRecordService.validateVrmDoesNotExist.mockReturnValue(of(null)); - mockTechRecordService.validateVrmForCherishedTransfer.mockReturnValue(of(null)); - component.cherishedTransferForm.controls['currentVrm'].setValue('TESTVRM1'); - component.cherishedTransferForm.controls['thirdMark'].setValue('3MARK'); - component.isCherishedTransfer = true; - - component.handleSubmit(); - - expect(dispatchSpy).toHaveBeenCalledWith( - amendVrm({ - newVrm: 'TESTVRM1', cherishedTransfer: true, systemNumber: 'PSV', createdTimestamp: 'now', thirdMark: '3MARK', - }), - ); - }); - }); - - describe('showWarning', () => { - it('should return true if the vehicle type is a psv', () => { - component.techRecord = { techRecord_vehicleType: 'psv' } as VehiclesOtherThan<'trl'>; - mockTechRecordService.getVehicleTypeWithSmallTrl.mockReturnValue('psv'); - - expect(component.showWarning).toBe(true); - }); - - it('should return true if the vehicle type is a hgv', () => { - component.techRecord = { techRecord_vehicleType: 'hgv' } as VehiclesOtherThan<'trl'>; - mockTechRecordService.getVehicleTypeWithSmallTrl.mockReturnValue('hgv'); - - expect(component.showWarning).toBe(true); - }); - - it('should return false if the vehicle type is not a psv or hgv', () => { - component.techRecord = { techRecord_vehicleType: 'lgv' } as VehiclesOtherThan<'trl'>; - mockTechRecordService.getVehicleTypeWithSmallTrl.mockReturnValue('lgv'); - - expect(component.showWarning).toBe(false); - }); - - it('should default to false if the vehicle type is not present', () => { - component.techRecord = undefined; - mockTechRecordService.getVehicleTypeWithSmallTrl.mockReturnValue(undefined); - - expect(component.showWarning).toBe(false); - }); - }); + const actions$ = new ReplaySubject(); + let component: AmendVrmComponent; + let errorService: GlobalErrorService; + let fixture: ComponentFixture; + let route: ActivatedRoute; + let router: Router; + let store: MockStore; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AmendVrmComponent], + providers: [ + GlobalErrorService, + provideMockActions(() => actions$), + provideMockStore({ initialState: initialAppState }), + { + provide: ActivatedRoute, + useValue: { params: of([{ id: 1, reason: 'correcting-error' }]), snapshot: new ActivatedRouteSnapshot() }, + }, + { provide: DynamicFormService, useValue: mockDynamicFormService }, + { provide: TechnicalRecordService, useValue: mockTechRecordService }, + ], + imports: [RouterTestingModule, SharedModule, ReactiveFormsModule], + }).compileComponents(); + }); + beforeEach(() => { + fixture = TestBed.createComponent(AmendVrmComponent); + errorService = TestBed.inject(GlobalErrorService); + route = TestBed.inject(ActivatedRoute); + router = TestBed.inject(Router); + store = TestBed.inject(MockStore); + component = fixture.componentInstance; + component.cherishedTransferForm.controls['currentVrm'].clearAsyncValidators(); + component.cherishedTransferForm.controls['currentVrm'].setAsyncValidators( + mockTechRecordService.validateVrmForCherishedTransfer.bind(this) + ); + component.cherishedTransferForm.controls['thirdMark'].clearAsyncValidators(); + component.cherishedTransferForm.controls['thirdMark'].setAsyncValidators( + mockTechRecordService.validateVrmDoesNotExist.bind(this) + ); + component.correctingAnErrorForm.controls['newVrm'].clearAsyncValidators(); + component.correctingAnErrorForm.controls['newVrm'].setAsyncValidators( + mockTechRecordService.validateVrmDoesNotExist.bind(this) + ); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('navigateBack', () => { + it('should clear all errors', () => { + jest.spyOn(router, 'navigate').mockImplementation(); + + const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); + + component.navigateBack(); + + expect(clearErrorsSpy).toHaveBeenCalledTimes(1); + }); + + it('should navigate back to the previous page', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + component.navigateBack(); + + expect(navigateSpy).toHaveBeenCalledWith(['../../'], { relativeTo: route }); + }); + + it('should navigate to a new record on amendVrmSuccess', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + store.overrideSelector(selectRouteData, { data: { isEditing: true } }); + component.ngOnInit(); + + actions$.next(amendVrmSuccess({ vehicleTechRecord: mockVehicleTechnicalRecord('psv') as TechRecordType<'get'> })); + + expect(navigateSpy).toHaveBeenCalled(); + }); + }); + + describe('handleSubmit', () => { + beforeEach(() => { + component.techRecord = mockVehicleTechnicalRecord('psv') as VehiclesOtherThan<'trl'>; + jest.resetAllMocks(); + jest.resetModules(); + }); + + it('should add an error when the vrm field is not filled out', () => { + const addErrorSpy = jest.spyOn(errorService, 'setErrors'); + + component.handleSubmit(); + + expect(addErrorSpy).toHaveBeenCalledWith([{ anchorLink: 'new-Vrm', error: 'New VRM is required' }]); + }); + + it('should not dispatch an action if isFormValid returns false', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + + component.handleSubmit(); + + expect(dispatchSpy).not.toHaveBeenCalledWith( + amendVrm({ + newVrm: '', + cherishedTransfer: false, + thirdMark: '', + systemNumber: 'PSV', + createdTimestamp: 'now', + }) + ); + }); + it('should dispatch the amendVrm action', fakeAsync(() => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + mockTechRecordService.validateVrmDoesNotExist.mockReturnValue(of(null)); + component.correctingAnErrorForm.controls['newVrm'].setValue('TESTVRM1'); + + component.handleSubmit(); + + expect(dispatchSpy).toHaveBeenCalledWith( + amendVrm({ + newVrm: 'TESTVRM1', + cherishedTransfer: false, + systemNumber: 'PSV', + createdTimestamp: 'now', + thirdMark: undefined, + }) + ); + })); + it('should dispatch the action with the correct information', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + mockTechRecordService.validateVrmDoesNotExist.mockReturnValue(of(null)); + mockTechRecordService.validateVrmForCherishedTransfer.mockReturnValue(of(null)); + component.cherishedTransferForm.controls['currentVrm'].setValue('TESTVRM1'); + component.cherishedTransferForm.controls['thirdMark'].setValue('3MARK'); + component.isCherishedTransfer = true; + + component.handleSubmit(); + + expect(dispatchSpy).toHaveBeenCalledWith( + amendVrm({ + newVrm: 'TESTVRM1', + cherishedTransfer: true, + systemNumber: 'PSV', + createdTimestamp: 'now', + thirdMark: '3MARK', + }) + ); + }); + }); + + describe('showWarning', () => { + it('should return true if the vehicle type is a psv', () => { + component.techRecord = { techRecord_vehicleType: 'psv' } as VehiclesOtherThan<'trl'>; + mockTechRecordService.getVehicleTypeWithSmallTrl.mockReturnValue('psv'); + + expect(component.showWarning).toBe(true); + }); + + it('should return true if the vehicle type is a hgv', () => { + component.techRecord = { techRecord_vehicleType: 'hgv' } as VehiclesOtherThan<'trl'>; + mockTechRecordService.getVehicleTypeWithSmallTrl.mockReturnValue('hgv'); + + expect(component.showWarning).toBe(true); + }); + + it('should return false if the vehicle type is not a psv or hgv', () => { + component.techRecord = { techRecord_vehicleType: 'lgv' } as VehiclesOtherThan<'trl'>; + mockTechRecordService.getVehicleTypeWithSmallTrl.mockReturnValue('lgv'); + + expect(component.showWarning).toBe(false); + }); + + it('should default to false if the vehicle type is not present', () => { + component.techRecord = undefined; + mockTechRecordService.getVehicleTypeWithSmallTrl.mockReturnValue(undefined); + + expect(component.showWarning).toBe(false); + }); + }); }); diff --git a/src/app/features/tech-record/components/tech-record-amend-vrm/tech-record-amend-vrm.component.ts b/src/app/features/tech-record/components/tech-record-amend-vrm/tech-record-amend-vrm.component.ts index 90cf3ceed4..cc2baedfa3 100644 --- a/src/app/features/tech-record/components/tech-record-amend-vrm/tech-record-amend-vrm.component.ts +++ b/src/app/features/tech-record/components/tech-record-amend-vrm/tech-record-amend-vrm.component.ts @@ -1,6 +1,4 @@ -import { - Component, EventEmitter, OnDestroy, OnInit, Output, QueryList, ViewChildren, -} from '@angular/core'; +import { Component, EventEmitter, OnDestroy, OnInit, Output, QueryList, ViewChildren } from '@angular/core'; import { FormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalError } from '@core/components/global-error/global-error.interface'; @@ -19,161 +17,179 @@ import { TechnicalRecordServiceState } from '@store/technical-records/reducers/t import { Subject, take, takeUntil } from 'rxjs'; @Component({ - selector: 'app-change-amend-vrm', - templateUrl: './tech-record-amend-vrm.component.html', - styleUrls: ['./tech-record-amend-vrm.component.scss'], + selector: 'app-change-amend-vrm', + templateUrl: './tech-record-amend-vrm.component.html', + styleUrls: ['./tech-record-amend-vrm.component.scss'], }) export class AmendVrmComponent implements OnDestroy, OnInit { - techRecord?: VehiclesOtherThan<'trl'>; - makeAndModel?: string; - isCherishedTransfer = false; - systemNumber?: string; - createdTimestamp?: string; - formValidity = false; - width: FormNodeWidth = FormNodeWidth.L; - - cherishedTransferForm = new FormGroup({ - currentVrm: new CustomFormControl( - { - name: 'current-Vrm', - label: 'Current VRM', - type: FormNodeTypes.CONTROL, - }, - '', - [Validators.required, CustomValidators.alphanumeric(), CustomValidators.notZNumber, Validators.minLength(3), Validators.maxLength(9)], - this.technicalRecordService.validateVrmForCherishedTransfer(), - ), - previousVrm: new CustomFormControl({ - name: 'previous-Vrm', - label: 'Previous VRM', - type: FormNodeTypes.CONTROL, - disabled: true, - }), - thirdMark: new CustomFormControl( - { - name: 'third-Mark', - label: 'Third Mark', - type: FormNodeTypes.CONTROL, - }, - undefined, - [CustomValidators.alphanumeric(), CustomValidators.notZNumber, Validators.minLength(3), Validators.maxLength(9)], - ), - }); - correctingAnErrorForm = new FormGroup({ - newVrm: new CustomFormControl( - { - name: 'new-Vrm', - label: 'New VRM', - type: FormNodeTypes.CONTROL, - }, - '', - [Validators.required, CustomValidators.alphanumeric(), CustomValidators.notZNumber, Validators.minLength(3), Validators.maxLength(9)], - ), - }); - - @Output() isFormDirty = new EventEmitter(); - @Output() isFormInvalid = new EventEmitter(); - - @ViewChildren(DynamicFormGroupComponent) sections!: QueryList; - - private destroy$ = new Subject(); - - constructor( - private actions$: Actions, - public dfs: DynamicFormService, - private globalErrorService: GlobalErrorService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - private technicalRecordService: TechnicalRecordService, - ) {} - - ngOnInit(): void { - this.route.params.pipe(takeUntil(this.destroy$)).subscribe((params) => { - this.systemNumber = params['systemNumber']; - this.createdTimestamp = params['createdTimestamp']; - this.isCherishedTransfer = params['reason'] === 'cherished-transfer'; - }); - this.technicalRecordService.techRecord$.pipe(take(1), takeUntil(this.destroy$)).subscribe((record) => { - if (record?.techRecord_statusCode === 'archived' || !record) { - return this.navigateBack(); - } - this.techRecord = record as VehiclesOtherThan<'trl'>; - this.makeAndModel = this.technicalRecordService.getMakeAndModel(record); - }); - - this.actions$.pipe(ofType(amendVrmSuccess), takeUntil(this.destroy$)).subscribe(({ vehicleTechRecord }) => { - void this.router.navigate(['/tech-records', `${vehicleTechRecord.systemNumber}`, `${vehicleTechRecord.createdTimestamp}`]); - }); - - this.cherishedTransferForm.controls['previousVrm'].setValue(this.techRecord?.primaryVrm ?? ''); - this.cherishedTransferForm.controls['previousVrm'].disable(); - this.cherishedTransferForm.controls['thirdMark'].setAsyncValidators( - this.technicalRecordService.validateVrmDoesNotExist(this.techRecord?.primaryVrm ?? ''), - ); - this.correctingAnErrorForm.controls['newVrm'].setAsyncValidators( - this.technicalRecordService.validateVrmDoesNotExist(this.techRecord?.primaryVrm ?? ''), - ); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - get vehicleType(): VehicleTypes | undefined { - return this.techRecord ? this.technicalRecordService.getVehicleTypeWithSmallTrl(this.techRecord) : undefined; - } - - navigateBack() { - this.globalErrorService.clearErrors(); - void this.router.navigate(['../../'], { relativeTo: this.route }); - } - - handleFormChange() { - if (this.isCherishedTransfer) { - this.cherishedTransferForm.get('currentVrm')?.updateValueAndValidity(); - } - } - - handleSubmit(): void { - if (!this.isFormValid()) { - return; - } - - this.store.dispatch( - amendVrm({ - newVrm: this.isCherishedTransfer ? this.cherishedTransferForm.value.currentVrm : this.correctingAnErrorForm.value.newVrm, - cherishedTransfer: this.isCherishedTransfer, - thirdMark: this.isCherishedTransfer ? this.cherishedTransferForm.value.thirdMark : undefined, - systemNumber: (this.techRecord as TechRecordType<'get'>)?.systemNumber, - createdTimestamp: (this.techRecord as TechRecordType<'get'>)?.createdTimestamp, - }), - ); - } - - isFormValid(): boolean { - this.globalErrorService.clearErrors(); - - const errors: GlobalError[] = []; - - if (this.isCherishedTransfer) { - DynamicFormService.validate(this.cherishedTransferForm, errors, false); - } else { - DynamicFormService.validate(this.correctingAnErrorForm, errors, false); - } - - if (errors?.length > 0) { - this.globalErrorService.setErrors(errors); - return false; - } - return true; - } - - get showWarning(): boolean { - if (this.vehicleType) { - return this.vehicleType === 'psv' || this.vehicleType === 'hgv'; - } - return false; - } + techRecord?: VehiclesOtherThan<'trl'>; + makeAndModel?: string; + isCherishedTransfer = false; + systemNumber?: string; + createdTimestamp?: string; + formValidity = false; + width: FormNodeWidth = FormNodeWidth.L; + + cherishedTransferForm = new FormGroup({ + currentVrm: new CustomFormControl( + { + name: 'current-Vrm', + label: 'Current VRM', + type: FormNodeTypes.CONTROL, + }, + '', + [ + Validators.required, + CustomValidators.alphanumeric(), + CustomValidators.notZNumber, + Validators.minLength(3), + Validators.maxLength(9), + ], + this.technicalRecordService.validateVrmForCherishedTransfer() + ), + previousVrm: new CustomFormControl({ + name: 'previous-Vrm', + label: 'Previous VRM', + type: FormNodeTypes.CONTROL, + disabled: true, + }), + thirdMark: new CustomFormControl( + { + name: 'third-Mark', + label: 'Third Mark', + type: FormNodeTypes.CONTROL, + }, + undefined, + [CustomValidators.alphanumeric(), CustomValidators.notZNumber, Validators.minLength(3), Validators.maxLength(9)] + ), + }); + correctingAnErrorForm = new FormGroup({ + newVrm: new CustomFormControl( + { + name: 'new-Vrm', + label: 'New VRM', + type: FormNodeTypes.CONTROL, + }, + '', + [ + Validators.required, + CustomValidators.alphanumeric(), + CustomValidators.notZNumber, + Validators.minLength(3), + Validators.maxLength(9), + ] + ), + }); + + @Output() isFormDirty = new EventEmitter(); + @Output() isFormInvalid = new EventEmitter(); + + @ViewChildren(DynamicFormGroupComponent) sections!: QueryList; + + private destroy$ = new Subject(); + + constructor( + private actions$: Actions, + public dfs: DynamicFormService, + private globalErrorService: GlobalErrorService, + private route: ActivatedRoute, + private router: Router, + private store: Store, + private technicalRecordService: TechnicalRecordService + ) {} + + ngOnInit(): void { + this.route.params.pipe(takeUntil(this.destroy$)).subscribe((params) => { + this.systemNumber = params['systemNumber']; + this.createdTimestamp = params['createdTimestamp']; + this.isCherishedTransfer = params['reason'] === 'cherished-transfer'; + }); + this.technicalRecordService.techRecord$.pipe(take(1), takeUntil(this.destroy$)).subscribe((record) => { + if (record?.techRecord_statusCode === 'archived' || !record) { + return this.navigateBack(); + } + this.techRecord = record as VehiclesOtherThan<'trl'>; + this.makeAndModel = this.technicalRecordService.getMakeAndModel(record); + }); + + this.actions$.pipe(ofType(amendVrmSuccess), takeUntil(this.destroy$)).subscribe(({ vehicleTechRecord }) => { + void this.router.navigate([ + '/tech-records', + `${vehicleTechRecord.systemNumber}`, + `${vehicleTechRecord.createdTimestamp}`, + ]); + }); + + this.cherishedTransferForm.controls['previousVrm'].setValue(this.techRecord?.primaryVrm ?? ''); + this.cherishedTransferForm.controls['previousVrm'].disable(); + this.cherishedTransferForm.controls['thirdMark'].setAsyncValidators( + this.technicalRecordService.validateVrmDoesNotExist(this.techRecord?.primaryVrm ?? '') + ); + this.correctingAnErrorForm.controls['newVrm'].setAsyncValidators( + this.technicalRecordService.validateVrmDoesNotExist(this.techRecord?.primaryVrm ?? '') + ); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + get vehicleType(): VehicleTypes | undefined { + return this.techRecord ? this.technicalRecordService.getVehicleTypeWithSmallTrl(this.techRecord) : undefined; + } + + navigateBack() { + this.globalErrorService.clearErrors(); + void this.router.navigate(['../../'], { relativeTo: this.route }); + } + + handleFormChange() { + if (this.isCherishedTransfer) { + this.cherishedTransferForm.get('currentVrm')?.updateValueAndValidity(); + } + } + + handleSubmit(): void { + if (!this.isFormValid()) { + return; + } + + this.store.dispatch( + amendVrm({ + newVrm: this.isCherishedTransfer + ? this.cherishedTransferForm.value.currentVrm + : this.correctingAnErrorForm.value.newVrm, + cherishedTransfer: this.isCherishedTransfer, + thirdMark: this.isCherishedTransfer ? this.cherishedTransferForm.value.thirdMark : undefined, + systemNumber: (this.techRecord as TechRecordType<'get'>)?.systemNumber, + createdTimestamp: (this.techRecord as TechRecordType<'get'>)?.createdTimestamp, + }) + ); + } + + isFormValid(): boolean { + this.globalErrorService.clearErrors(); + + const errors: GlobalError[] = []; + + if (this.isCherishedTransfer) { + DynamicFormService.validate(this.cherishedTransferForm, errors, false); + } else { + DynamicFormService.validate(this.correctingAnErrorForm, errors, false); + } + + if (errors?.length > 0) { + this.globalErrorService.setErrors(errors); + return false; + } + return true; + } + + get showWarning(): boolean { + if (this.vehicleType) { + return this.vehicleType === 'psv' || this.vehicleType === 'hgv'; + } + return false; + } } diff --git a/src/app/features/tech-record/components/tech-record-change-status/tech-record-change-status.component.spec.ts b/src/app/features/tech-record/components/tech-record-change-status/tech-record-change-status.component.spec.ts index 4804d30568..ef212aac05 100644 --- a/src/app/features/tech-record/components/tech-record-change-status/tech-record-change-status.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-change-status/tech-record-change-status.component.spec.ts @@ -16,37 +16,44 @@ import { TechRecordTitleComponent } from '../tech-record-title/tech-record-title import { TechRecordChangeStatusComponent } from './tech-record-change-status.component'; describe('TechRecordChangeStatusComponent', () => { - let actions$: ReplaySubject; - let component: TechRecordChangeStatusComponent; - let fixture: ComponentFixture; + let actions$: ReplaySubject; + let component: TechRecordChangeStatusComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - actions$ = new ReplaySubject(); + beforeEach(async () => { + actions$ = new ReplaySubject(); - await TestBed.configureTestingModule({ - declarations: [TechRecordChangeStatusComponent, TechRecordTitleComponent], - imports: [DynamicFormsModule, HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule, SharedModule, StoreModule.forRoot({})], - providers: [ - provideMockActions(() => actions$), - provideMockStore({ initialState: initialAppState }), - { provide: APP_BASE_HREF, useValue: '/' }, - { - provide: UserService, - useValue: { - roles$: of([Roles.TechRecordArchive]), - }, - }, - ], - }).compileComponents(); - }); + await TestBed.configureTestingModule({ + declarations: [TechRecordChangeStatusComponent, TechRecordTitleComponent], + imports: [ + DynamicFormsModule, + HttpClientTestingModule, + ReactiveFormsModule, + RouterTestingModule, + SharedModule, + StoreModule.forRoot({}), + ], + providers: [ + provideMockActions(() => actions$), + provideMockStore({ initialState: initialAppState }), + { provide: APP_BASE_HREF, useValue: '/' }, + { + provide: UserService, + useValue: { + roles$: of([Roles.TechRecordArchive]), + }, + }, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TechRecordChangeStatusComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(TechRecordChangeStatusComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/features/tech-record/components/tech-record-change-status/tech-record-change-status.component.ts b/src/app/features/tech-record/components/tech-record-change-status/tech-record-change-status.component.ts index f8e1a38a1d..89aa6a1752 100644 --- a/src/app/features/tech-record/components/tech-record-change-status/tech-record-change-status.component.ts +++ b/src/app/features/tech-record/components/tech-record-change-status/tech-record-change-status.component.ts @@ -9,103 +9,117 @@ import { Store } from '@ngrx/store'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { State } from '@store/index'; import { - archiveTechRecord, archiveTechRecordSuccess, promoteTechRecord, promoteTechRecordSuccess, + archiveTechRecord, + archiveTechRecordSuccess, + promoteTechRecord, + promoteTechRecordSuccess, } from '@store/technical-records'; import { Subject, takeUntil } from 'rxjs'; @Component({ - selector: 'app-tech-record-change-status', - templateUrl: './tech-record-change-status.component.html', + selector: 'app-tech-record-change-status', + templateUrl: './tech-record-change-status.component.html', }) export class TechRecordChangeStatusComponent implements OnInit, OnDestroy { - techRecord: TechRecordType<'get'> | undefined; - - form: CustomFormGroup; - - isPromotion = false; - - destroy$ = new Subject(); - - constructor( - private actions$: Actions, - private errorService: GlobalErrorService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - private technicalRecordService: TechnicalRecordService, - ) { - this.form = new CustomFormGroup( - { name: 'reasonForPromotion', type: FormNodeTypes.GROUP }, - { reason: new CustomFormControl({ name: 'reason', type: FormNodeTypes.CONTROL }, undefined, [Validators.required]) }, - ); - } - - ngOnInit(): void { - this.technicalRecordService.techRecord$.pipe(takeUntil(this.destroy$)).subscribe((record) => { - this.techRecord = record as TechRecordType<'get'>; - }); - - this.actions$.pipe(ofType(promoteTechRecordSuccess, archiveTechRecordSuccess), takeUntil(this.destroy$)).subscribe(({ vehicleTechRecord }) => { - void this.router.navigate([`/tech-records/${vehicleTechRecord.systemNumber}/${vehicleTechRecord.createdTimestamp}`]); - - this.technicalRecordService.clearEditingTechRecord(); - }); - - this.route.queryParamMap.pipe(takeUntil(this.destroy$)).subscribe((params) => { - this.isPromotion = params.get('to') === 'current'; - }); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - get label(): string { - return `Reason for ${this.isPromotion ? 'promotion' : 'archiving'}`; - } - - get buttonLabel(): string { - return this.isPromotion ? 'Promote' : 'Archive'; - } - - navigateBack(relativePath = '..'): void { - void this.router.navigate([relativePath], { relativeTo: this.route }); - } - - handleSubmit(form: { reason: string }): void { - if (!this.techRecord) { - return; - } - - if (this.form.valid) { - this.errorService.clearErrors(); - } else { - this.errorService.setErrors([ - { error: `Reason for ${this.isPromotion ? 'promotion' : 'archiving'} is required`, anchorLink: 'reasonForAmend' }, - ]); - } - - if (!this.form.valid || !form.reason) { - return; - } - - if (this.isPromotion) { - this.store.dispatch( - promoteTechRecord({ - systemNumber: this.techRecord.systemNumber, - createdTimestamp: this.techRecord.createdTimestamp, - reasonForPromoting: this.form.value.reason, - }), - ); - } else { - this.store.dispatch( - archiveTechRecord({ - systemNumber: this.techRecord.systemNumber, - createdTimestamp: this.techRecord.createdTimestamp, - reasonForArchiving: this.form.value.reason, - }), - ); - } - } + techRecord: TechRecordType<'get'> | undefined; + + form: CustomFormGroup; + + isPromotion = false; + + destroy$ = new Subject(); + + constructor( + private actions$: Actions, + private errorService: GlobalErrorService, + private route: ActivatedRoute, + private router: Router, + private store: Store, + private technicalRecordService: TechnicalRecordService + ) { + this.form = new CustomFormGroup( + { name: 'reasonForPromotion', type: FormNodeTypes.GROUP }, + { + reason: new CustomFormControl({ name: 'reason', type: FormNodeTypes.CONTROL }, undefined, [ + Validators.required, + ]), + } + ); + } + + ngOnInit(): void { + this.technicalRecordService.techRecord$.pipe(takeUntil(this.destroy$)).subscribe((record) => { + this.techRecord = record as TechRecordType<'get'>; + }); + + this.actions$ + .pipe(ofType(promoteTechRecordSuccess, archiveTechRecordSuccess), takeUntil(this.destroy$)) + .subscribe(({ vehicleTechRecord }) => { + void this.router.navigate([ + `/tech-records/${vehicleTechRecord.systemNumber}/${vehicleTechRecord.createdTimestamp}`, + ]); + + this.technicalRecordService.clearEditingTechRecord(); + }); + + this.route.queryParamMap.pipe(takeUntil(this.destroy$)).subscribe((params) => { + this.isPromotion = params.get('to') === 'current'; + }); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + get label(): string { + return `Reason for ${this.isPromotion ? 'promotion' : 'archiving'}`; + } + + get buttonLabel(): string { + return this.isPromotion ? 'Promote' : 'Archive'; + } + + navigateBack(relativePath = '..'): void { + void this.router.navigate([relativePath], { relativeTo: this.route }); + } + + handleSubmit(form: { reason: string }): void { + if (!this.techRecord) { + return; + } + + if (this.form.valid) { + this.errorService.clearErrors(); + } else { + this.errorService.setErrors([ + { + error: `Reason for ${this.isPromotion ? 'promotion' : 'archiving'} is required`, + anchorLink: 'reasonForAmend', + }, + ]); + } + + if (!this.form.valid || !form.reason) { + return; + } + + if (this.isPromotion) { + this.store.dispatch( + promoteTechRecord({ + systemNumber: this.techRecord.systemNumber, + createdTimestamp: this.techRecord.createdTimestamp, + reasonForPromoting: this.form.value.reason, + }) + ); + } else { + this.store.dispatch( + archiveTechRecord({ + systemNumber: this.techRecord.systemNumber, + createdTimestamp: this.techRecord.createdTimestamp, + reasonForArchiving: this.form.value.reason, + }) + ); + } + } } diff --git a/src/app/features/tech-record/components/tech-record-change-type/tech-record-change-type.component.spec.ts b/src/app/features/tech-record/components/tech-record-change-type/tech-record-change-type.component.spec.ts index 5accfa10b7..c3294cb4b5 100644 --- a/src/app/features/tech-record/components/tech-record-change-type/tech-record-change-type.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-change-type/tech-record-change-type.component.spec.ts @@ -21,150 +21,157 @@ import { ChangeVehicleTypeComponent } from './tech-record-change-type.component' const mockGetVehicleType = jest.fn(); const mockTechRecordService = { - get techRecord$() { - return of({}); - }, - getMakeAndModel: jest.fn(), - clearReasonForCreation: jest.fn(), - getVehicleTypeWithSmallTrl: mockGetVehicleType, + get techRecord$() { + return of({}); + }, + getMakeAndModel: jest.fn(), + clearReasonForCreation: jest.fn(), + getVehicleTypeWithSmallTrl: mockGetVehicleType, }; const mockDynamicFormService = { - createForm: jest.fn(), + createForm: jest.fn(), }; describe('TechRecordChangeTypeComponent', () => { - const actions$ = new ReplaySubject(); - let component: ChangeVehicleTypeComponent; - let errorService: GlobalErrorService; - let expectedTechRecord = {} as V3TechRecordModel; - let fixture: ComponentFixture; - let route: ActivatedRoute; - let router: Router; - let store: MockStore; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ChangeVehicleTypeComponent], - providers: [ - GlobalErrorService, - provideMockActions(() => actions$), - provideMockStore({ initialState: initialAppState }), - { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, - { provide: DynamicFormService, useValue: mockDynamicFormService }, - { provide: TechnicalRecordService, useValue: mockTechRecordService }, - ], - imports: [DynamicFormsModule, RouterTestingModule, SharedModule, FixNavigationTriggeredOutsideAngularZoneNgModule], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ChangeVehicleTypeComponent); - errorService = TestBed.inject(GlobalErrorService); - route = TestBed.inject(ActivatedRoute); - router = TestBed.inject(Router); - store = TestBed.inject(MockStore); - component = fixture.componentInstance; - expectedTechRecord = { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_vehicleType: VehicleTypes.PSV, - techRecord_chassisMake: 'test-make', - techRecord_chassisModel: 'test-model', - } as V3TechRecordModel; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('makeAndModel', () => { - it('should should return the make and model', () => { - const techRecord = expectedTechRecord as TechRecordType<'psv'>; - const expectedMakeModel = `${techRecord.techRecord_chassisMake} - ${techRecord.techRecord_chassisModel}`; - - jest.spyOn(mockTechRecordService, 'getMakeAndModel').mockReturnValueOnce(expectedMakeModel); - - component.techRecord = expectedTechRecord; - component.ngOnInit(); - - expect(component.makeAndModel).toBe(expectedMakeModel); - }); - - it('should return an empty string when the current record is null', () => { - delete component.techRecord; - component.ngOnInit(); - - expect(component.makeAndModel).toBeUndefined(); - }); - }); - - describe('vehicleTypeOptions', () => { - it('should return all types except for the current one', () => { - component.techRecord = expectedTechRecord; - mockGetVehicleType.mockReturnValue('psv'); - const expectedOptions = getOptionsFromEnumAcronym(VehicleTypes).filter((type) => type.value !== VehicleTypes.PSV); - expect(component.vehicleTypeOptions).toStrictEqual(expectedOptions); - }); - }); - - describe('navigateBack', () => { - it('should clear all errors', () => { - jest.spyOn(router, 'navigate').mockImplementation(); - - const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); - - component.navigateBack(); - - expect(clearErrorsSpy).toHaveBeenCalledTimes(1); - }); - - it('should navigate back to the previous page', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - component.navigateBack(); - - expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); - }); - }); - - describe('handleSubmit', () => { - it('should add an error when no vehicle type is selected', () => { - const setErrorsSpy = jest.spyOn(errorService, 'setErrors'); - - component.handleSubmit(null as unknown as VehicleTypes); - - expect(setErrorsSpy).toHaveBeenCalledWith([{ error: 'You must provide a new vehicle type', anchorLink: 'selectedVehicleType' }]); - }); - - it('should dispatch the changeVehicleType action', () => { - jest.spyOn(router, 'navigate').mockImplementation(); + const actions$ = new ReplaySubject(); + let component: ChangeVehicleTypeComponent; + let errorService: GlobalErrorService; + let expectedTechRecord = {} as V3TechRecordModel; + let fixture: ComponentFixture; + let route: ActivatedRoute; + let router: Router; + let store: MockStore; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ChangeVehicleTypeComponent], + providers: [ + GlobalErrorService, + provideMockActions(() => actions$), + provideMockStore({ initialState: initialAppState }), + { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, + { provide: DynamicFormService, useValue: mockDynamicFormService }, + { provide: TechnicalRecordService, useValue: mockTechRecordService }, + ], + imports: [ + DynamicFormsModule, + RouterTestingModule, + SharedModule, + FixNavigationTriggeredOutsideAngularZoneNgModule, + ], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ChangeVehicleTypeComponent); + errorService = TestBed.inject(GlobalErrorService); + route = TestBed.inject(ActivatedRoute); + router = TestBed.inject(Router); + store = TestBed.inject(MockStore); + component = fixture.componentInstance; + expectedTechRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_vehicleType: VehicleTypes.PSV, + techRecord_chassisMake: 'test-make', + techRecord_chassisModel: 'test-model', + } as V3TechRecordModel; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('makeAndModel', () => { + it('should should return the make and model', () => { + const techRecord = expectedTechRecord as TechRecordType<'psv'>; + const expectedMakeModel = `${techRecord.techRecord_chassisMake} - ${techRecord.techRecord_chassisModel}`; + + jest.spyOn(mockTechRecordService, 'getMakeAndModel').mockReturnValueOnce(expectedMakeModel); + + component.techRecord = expectedTechRecord; + component.ngOnInit(); + + expect(component.makeAndModel).toBe(expectedMakeModel); + }); + + it('should return an empty string when the current record is null', () => { + delete component.techRecord; + component.ngOnInit(); + + expect(component.makeAndModel).toBeUndefined(); + }); + }); + + describe('vehicleTypeOptions', () => { + it('should return all types except for the current one', () => { + component.techRecord = expectedTechRecord; + mockGetVehicleType.mockReturnValue('psv'); + const expectedOptions = getOptionsFromEnumAcronym(VehicleTypes).filter((type) => type.value !== VehicleTypes.PSV); + expect(component.vehicleTypeOptions).toStrictEqual(expectedOptions); + }); + }); + + describe('navigateBack', () => { + it('should clear all errors', () => { + jest.spyOn(router, 'navigate').mockImplementation(); + + const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); + + component.navigateBack(); + + expect(clearErrorsSpy).toHaveBeenCalledTimes(1); + }); + + it('should navigate back to the previous page', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + component.navigateBack(); + + expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); + }); + }); + + describe('handleSubmit', () => { + it('should add an error when no vehicle type is selected', () => { + const setErrorsSpy = jest.spyOn(errorService, 'setErrors'); + + component.handleSubmit(null as unknown as VehicleTypes); + + expect(setErrorsSpy).toHaveBeenCalledWith([ + { error: 'You must provide a new vehicle type', anchorLink: 'selectedVehicleType' }, + ]); + }); + + it('should dispatch the changeVehicleType action', () => { + jest.spyOn(router, 'navigate').mockImplementation(); + + const dispatchSpy = jest.spyOn(store, 'dispatch'); + + component.handleSubmit(VehicleTypes.PSV); - const dispatchSpy = jest.spyOn(store, 'dispatch'); + expect(dispatchSpy).toHaveBeenCalledWith(changeVehicleType({ techRecord_vehicleType: VehicleTypes.PSV })); + }); - component.handleSubmit(VehicleTypes.PSV); + it('should call clearReasonForCreation', () => { + jest.spyOn(router, 'navigate').mockImplementation(); - expect(dispatchSpy).toHaveBeenCalledWith(changeVehicleType({ techRecord_vehicleType: VehicleTypes.PSV })); - }); + const clearReasonForCreationSpy = jest.spyOn(mockTechRecordService, 'clearReasonForCreation'); - it('should call clearReasonForCreation', () => { - jest.spyOn(router, 'navigate').mockImplementation(); + jest.resetAllMocks(); + component.handleSubmit(VehicleTypes.PSV); - const clearReasonForCreationSpy = jest.spyOn(mockTechRecordService, 'clearReasonForCreation'); + expect(clearReasonForCreationSpy).toHaveBeenCalledTimes(1); + }); - jest.resetAllMocks(); - component.handleSubmit(VehicleTypes.PSV); + it('navigate to the editing page', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - expect(clearReasonForCreationSpy).toHaveBeenCalledTimes(1); - }); + component.handleSubmit(VehicleTypes.PSV); - it('navigate to the editing page', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - component.handleSubmit(VehicleTypes.PSV); - - expect(navigateSpy).toHaveBeenCalledWith(['../amend-reason'], { relativeTo: route }); - }); - }); + expect(navigateSpy).toHaveBeenCalledWith(['../amend-reason'], { relativeTo: route }); + }); + }); }); diff --git a/src/app/features/tech-record/components/tech-record-change-type/tech-record-change-type.component.ts b/src/app/features/tech-record/components/tech-record-change-type/tech-record-change-type.component.ts index 44afdd9cd1..373e44d106 100644 --- a/src/app/features/tech-record/components/tech-record-change-type/tech-record-change-type.component.ts +++ b/src/app/features/tech-record/components/tech-record-change-type/tech-record-change-type.component.ts @@ -8,9 +8,7 @@ import { MultiOptions } from '@forms/models/options.model'; import { CustomFormControl, FormNodeTypes } from '@forms/services/dynamic-form.types'; import { getOptionsFromEnumAcronym } from '@forms/utils/enum-map'; -import { - StatusCodes, V3TechRecordModel, VehicleTypes, -} from '@models/vehicle-tech-record.model'; +import { StatusCodes, V3TechRecordModel, VehicleTypes } from '@models/vehicle-tech-record.model'; import { Store } from '@ngrx/store'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { changeVehicleType } from '@store/technical-records'; @@ -18,86 +16,93 @@ import { TechnicalRecordServiceState } from '@store/technical-records/reducers/t import { take } from 'rxjs'; @Component({ - selector: 'app-change-vehicle-type', - templateUrl: './tech-record-change-type.component.html', - styleUrls: ['./tech-record-change-type.component.scss'], + selector: 'app-change-vehicle-type', + templateUrl: './tech-record-change-type.component.html', + styleUrls: ['./tech-record-change-type.component.scss'], }) export class ChangeVehicleTypeComponent implements OnInit { - techRecord?: V3TechRecordModel; - makeAndModel?: string; - - form: FormGroup = new FormGroup({ - selectVehicleType: new CustomFormControl( - { name: 'change-vehicle-type-select', label: 'Select a new vehicle type', type: FormNodeTypes.CONTROL }, - '', - [Validators.required], - ), - }); - - constructor( - private globalErrorService: GlobalErrorService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - private technicalRecordService: TechnicalRecordService, - ) {} - - ngOnInit(): void { - this.globalErrorService.clearErrors(); - this.technicalRecordService.techRecord$.pipe(take(1)).subscribe((techRecord) => { - if (!techRecord) { - this.navigateBack(); - } else { - this.techRecord = techRecord; - } - }); - - if (this.techRecord) { - this.makeAndModel = this.technicalRecordService.getMakeAndModel(this.techRecord); - } - } - - get vehicleType(): VehicleTypes | undefined { - return this.techRecord ? this.technicalRecordService.getVehicleTypeWithSmallTrl(this.techRecord) : undefined; - } - - get vehicleTypeOptions(): MultiOptions { - return getOptionsFromEnumAcronym(VehicleTypes).filter((type) => type.value !== this.vehicleType); - } - - get currentVrm() { - return this.techRecord?.techRecord_vehicleType !== 'trl' ? this.techRecord?.primaryVrm : undefined; - } - - navigateBack() { - this.globalErrorService.clearErrors(); - void this.router.navigate(['..'], { relativeTo: this.route }); - } - - handleSubmit(selectedVehicleType: VehicleTypes): void { - if (!selectedVehicleType) { - return this.globalErrorService.setErrors([{ error: 'You must provide a new vehicle type', anchorLink: 'selectedVehicleType' }]); - } - - if ( - selectedVehicleType === VehicleTypes.TRL - && ((this.techRecord as TechRecordTypeByVehicle<'trl'>)?.techRecord_euVehicleCategory === EUVehicleCategory.O1 - || (this.techRecord as TechRecordTypeByVehicle<'trl'>)?.techRecord_euVehicleCategory === EUVehicleCategory.O2) - ) { - return this.globalErrorService.setErrors([{ - error: 'You cannot change vehicle type to TRL when EU vehicle category is set to \'O1\' or \'O2\'', - anchorLink: 'selectedVehicleType', - }]); - } - - this.store.dispatch(changeVehicleType({ techRecord_vehicleType: selectedVehicleType })); - - this.technicalRecordService.clearReasonForCreation(); - - this.globalErrorService.clearErrors(); - - const routeSuffix = this.techRecord?.techRecord_statusCode !== StatusCodes.PROVISIONAL ? 'amend-reason' : 'notifiable-alteration-needed'; - - void this.router.navigate([`../${routeSuffix}`], { relativeTo: this.route }); - } + techRecord?: V3TechRecordModel; + makeAndModel?: string; + + form: FormGroup = new FormGroup({ + selectVehicleType: new CustomFormControl( + { name: 'change-vehicle-type-select', label: 'Select a new vehicle type', type: FormNodeTypes.CONTROL }, + '', + [Validators.required] + ), + }); + + constructor( + private globalErrorService: GlobalErrorService, + private route: ActivatedRoute, + private router: Router, + private store: Store, + private technicalRecordService: TechnicalRecordService + ) {} + + ngOnInit(): void { + this.globalErrorService.clearErrors(); + this.technicalRecordService.techRecord$.pipe(take(1)).subscribe((techRecord) => { + if (!techRecord) { + this.navigateBack(); + } else { + this.techRecord = techRecord; + } + }); + + if (this.techRecord) { + this.makeAndModel = this.technicalRecordService.getMakeAndModel(this.techRecord); + } + } + + get vehicleType(): VehicleTypes | undefined { + return this.techRecord ? this.technicalRecordService.getVehicleTypeWithSmallTrl(this.techRecord) : undefined; + } + + get vehicleTypeOptions(): MultiOptions { + return getOptionsFromEnumAcronym(VehicleTypes).filter((type) => type.value !== this.vehicleType); + } + + get currentVrm() { + return this.techRecord?.techRecord_vehicleType !== 'trl' ? this.techRecord?.primaryVrm : undefined; + } + + navigateBack() { + this.globalErrorService.clearErrors(); + void this.router.navigate(['..'], { relativeTo: this.route }); + } + + handleSubmit(selectedVehicleType: VehicleTypes): void { + if (!selectedVehicleType) { + return this.globalErrorService.setErrors([ + { error: 'You must provide a new vehicle type', anchorLink: 'selectedVehicleType' }, + ]); + } + + if ( + selectedVehicleType === VehicleTypes.TRL && + ((this.techRecord as TechRecordTypeByVehicle<'trl'>)?.techRecord_euVehicleCategory === EUVehicleCategory.O1 || + (this.techRecord as TechRecordTypeByVehicle<'trl'>)?.techRecord_euVehicleCategory === EUVehicleCategory.O2) + ) { + return this.globalErrorService.setErrors([ + { + error: "You cannot change vehicle type to TRL when EU vehicle category is set to 'O1' or 'O2'", + anchorLink: 'selectedVehicleType', + }, + ]); + } + + this.store.dispatch(changeVehicleType({ techRecord_vehicleType: selectedVehicleType })); + + this.technicalRecordService.clearReasonForCreation(); + + this.globalErrorService.clearErrors(); + + const routeSuffix = + this.techRecord?.techRecord_statusCode !== StatusCodes.PROVISIONAL + ? 'amend-reason' + : 'notifiable-alteration-needed'; + + void this.router.navigate([`../${routeSuffix}`], { relativeTo: this.route }); + } } diff --git a/src/app/features/tech-record/components/tech-record-change-visibility/tech-record-change-visibility.component.spec.ts b/src/app/features/tech-record/components/tech-record-change-visibility/tech-record-change-visibility.component.spec.ts index 32aedacf5c..316e40c076 100644 --- a/src/app/features/tech-record/components/tech-record-change-visibility/tech-record-change-visibility.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-change-visibility/tech-record-change-visibility.component.spec.ts @@ -17,36 +17,42 @@ import { TechRecordTitleComponent } from '../tech-record-title/tech-record-title import { TechRecordChangeVisibilityComponent } from './tech-record-change-visibility.component'; describe('TechRecordHoldComponent', () => { - let actions$: ReplaySubject; - let component: TechRecordChangeVisibilityComponent; - let fixture: ComponentFixture; + let actions$: ReplaySubject; + let component: TechRecordChangeVisibilityComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TechRecordChangeVisibilityComponent, TechRecordTitleComponent], - imports: [DynamicFormsModule, HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule, SharedModule, StoreModule.forRoot({})], - providers: [ - provideMockActions(() => actions$), - provideMockStore({ initialState: initialAppState }), - { provide: APP_BASE_HREF, useValue: '/' }, - { - provide: UserService, - useValue: { - roles$: of([Roles.TechRecordArchive]), - }, - }, - ], - }).compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TechRecordChangeVisibilityComponent, TechRecordTitleComponent], + imports: [ + DynamicFormsModule, + HttpClientTestingModule, + ReactiveFormsModule, + RouterTestingModule, + SharedModule, + StoreModule.forRoot({}), + ], + providers: [ + provideMockActions(() => actions$), + provideMockStore({ initialState: initialAppState }), + { provide: APP_BASE_HREF, useValue: '/' }, + { + provide: UserService, + useValue: { + roles$: of([Roles.TechRecordArchive]), + }, + }, + ], + }).compileComponents(); + }); - }); + beforeEach(() => { + fixture = TestBed.createComponent(TechRecordChangeVisibilityComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TechRecordChangeVisibilityComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/features/tech-record/components/tech-record-change-visibility/tech-record-change-visibility.component.ts b/src/app/features/tech-record/components/tech-record-change-visibility/tech-record-change-visibility.component.ts index 79bdbf5f4a..5981efd8dd 100644 --- a/src/app/features/tech-record/components/tech-record-change-visibility/tech-record-change-visibility.component.ts +++ b/src/app/features/tech-record/components/tech-record-change-visibility/tech-record-change-visibility.component.ts @@ -12,100 +12,109 @@ import { TechnicalRecordService } from '@services/technical-record/technical-rec import { State } from '@store/index'; import { techRecord, updateTechRecord, updateTechRecordSuccess } from '@store/technical-records'; import cloneDeep from 'lodash.clonedeep'; -import { - Subject, skipWhile, take, takeUntil, withLatestFrom, -} from 'rxjs'; +import { Subject, skipWhile, take, takeUntil, withLatestFrom } from 'rxjs'; @Component({ - selector: 'app-tech-record-change-visibility', - templateUrl: './tech-record-change-visibility.component.html', - styleUrls: ['./tech-record-change-visibility.component.scss'], + selector: 'app-tech-record-change-visibility', + templateUrl: './tech-record-change-visibility.component.html', + styleUrls: ['./tech-record-change-visibility.component.scss'], }) export class TechRecordChangeVisibilityComponent implements OnInit, OnDestroy { - techRecord?: V3TechRecordModel; + techRecord?: V3TechRecordModel; - form: CustomFormGroup; - private destroy$ = new Subject(); + form: CustomFormGroup; + private destroy$ = new Subject(); - constructor( - private actions$: Actions, - private errorService: GlobalErrorService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - private technicalRecordService: TechnicalRecordService, - private routerService: RouterService, - ) { - this.form = new CustomFormGroup( - { name: 'reasonForChangingVisibility', type: FormNodeTypes.GROUP }, - { reason: new CustomFormControl({ name: 'reason', type: FormNodeTypes.CONTROL }, undefined, [Validators.required]) }, - ); - this.actions$.pipe(ofType(updateTechRecordSuccess), takeUntil(this.destroy$)).subscribe(({ vehicleTechRecord }) => { - void this.router.navigate([`/tech-records/${vehicleTechRecord.systemNumber}/${vehicleTechRecord.createdTimestamp}`]); - }); - } + constructor( + private actions$: Actions, + private errorService: GlobalErrorService, + private route: ActivatedRoute, + private router: Router, + private store: Store, + private technicalRecordService: TechnicalRecordService, + private routerService: RouterService + ) { + this.form = new CustomFormGroup( + { name: 'reasonForChangingVisibility', type: FormNodeTypes.GROUP }, + { + reason: new CustomFormControl({ name: 'reason', type: FormNodeTypes.CONTROL }, undefined, [ + Validators.required, + ]), + } + ); + this.actions$.pipe(ofType(updateTechRecordSuccess), takeUntil(this.destroy$)).subscribe(({ vehicleTechRecord }) => { + void this.router.navigate([ + `/tech-records/${vehicleTechRecord.systemNumber}/${vehicleTechRecord.createdTimestamp}`, + ]); + }); + } - get title(): string { - return `${this.techRecord?.techRecord_hiddenInVta ? 'Show' : 'Hide'} record in VTA`; - } + get title(): string { + return `${this.techRecord?.techRecord_hiddenInVta ? 'Show' : 'Hide'} record in VTA`; + } - get buttonLabel(): string { - return `${this.techRecord?.techRecord_hiddenInVta ? 'Show' : 'Hide'} record`; - } + get buttonLabel(): string { + return `${this.techRecord?.techRecord_hiddenInVta ? 'Show' : 'Hide'} record`; + } - ngOnInit(): void { - this.store - .select(techRecord) - .pipe(take(1)) - .subscribe((record) => { - this.techRecord = record; - }); - } + ngOnInit(): void { + this.store + .select(techRecord) + .pipe(take(1)) + .subscribe((record) => { + this.techRecord = record; + }); + } - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } - goBack(): void { - void this.router.navigate(['..'], { relativeTo: this.route }); - } + goBack(): void { + void this.router.navigate(['..'], { relativeTo: this.route }); + } - handleSubmit(form: { reason: string }): void { - if (this.form.valid) { - this.errorService.clearErrors(); - } else { - this.errorService.setErrors([ - { - error: `Reason for ${this.techRecord?.techRecord_hiddenInVta ? 'showing' : 'hiding'} is required`, - anchorLink: 'reasonForChangingVisibility', - }, - ]); - } + handleSubmit(form: { reason: string }): void { + if (this.form.valid) { + this.errorService.clearErrors(); + } else { + this.errorService.setErrors([ + { + error: `Reason for ${this.techRecord?.techRecord_hiddenInVta ? 'showing' : 'hiding'} is required`, + anchorLink: 'reasonForChangingVisibility', + }, + ]); + } - if (!this.form.valid || !form.reason) { - return; - } + if (!this.form.valid || !form.reason) { + return; + } - const updatedTechRecord: TechRecordType<'put'> = { - ...cloneDeep(this.techRecord as TechRecordType<'put'>), - techRecord_reasonForCreation: form.reason, - techRecord_hiddenInVta: !this.techRecord?.techRecord_hiddenInVta, - }; + const updatedTechRecord: TechRecordType<'put'> = { + ...cloneDeep(this.techRecord as TechRecordType<'put'>), + techRecord_reasonForCreation: form.reason, + techRecord_hiddenInVta: !this.techRecord?.techRecord_hiddenInVta, + }; - this.technicalRecordService.updateEditingTechRecord(updatedTechRecord); + this.technicalRecordService.updateEditingTechRecord(updatedTechRecord); - this.technicalRecordService.techRecord$ - .pipe( - takeUntil(this.destroy$), - skipWhile((technicalRecord) => technicalRecord?.techRecord_hiddenInVta !== this.techRecord?.techRecord_hiddenInVta), - withLatestFrom(this.routerService.getRouteNestedParam$('systemNumber'), this.routerService.getRouteNestedParam$('createdTimestamp')), - take(1), - ) - .subscribe(([, systemNumber, createdTimestamp]) => { - if (systemNumber && createdTimestamp) { - this.store.dispatch(updateTechRecord({ systemNumber, createdTimestamp })); - } - }); - } + this.technicalRecordService.techRecord$ + .pipe( + takeUntil(this.destroy$), + skipWhile( + (technicalRecord) => technicalRecord?.techRecord_hiddenInVta !== this.techRecord?.techRecord_hiddenInVta + ), + withLatestFrom( + this.routerService.getRouteNestedParam$('systemNumber'), + this.routerService.getRouteNestedParam$('createdTimestamp') + ), + take(1) + ) + .subscribe(([, systemNumber, createdTimestamp]) => { + if (systemNumber && createdTimestamp) { + this.store.dispatch(updateTechRecord({ systemNumber, createdTimestamp })); + } + }); + } } diff --git a/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.spec.ts b/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.spec.ts index 6568ebf897..708979f9da 100644 --- a/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.spec.ts @@ -1,95 +1,95 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { DynamicFormsModule } from '@forms/dynamic-forms.module'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { ActivatedRoute, Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; -import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; +import { GlobalErrorService } from '@core/components/global-error/global-error.service'; +import { DynamicFormsModule } from '@forms/dynamic-forms.module'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; +import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { initialAppState } from '@store/index'; -import { ActivatedRoute, Router } from '@angular/router'; import { of } from 'rxjs'; -import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { TechRecordEditAdditionalExaminerNoteComponent } from './tech-record-edit-additional-examiner-note.component'; const mockTechRecordService = { - techRecord$: jest.fn(), + techRecord$: jest.fn(), }; describe('TechRecordEditAdditionalExaminerNoteComponent', () => { - let fixture: ComponentFixture; - let component: TechRecordEditAdditionalExaminerNoteComponent; - let router: Router; - let errorService: GlobalErrorService; - let route: ActivatedRoute; - let store: MockStore; + let fixture: ComponentFixture; + let component: TechRecordEditAdditionalExaminerNoteComponent; + let router: Router; + let errorService: GlobalErrorService; + let route: ActivatedRoute; + let store: MockStore; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TechRecordEditAdditionalExaminerNoteComponent], - imports: [DynamicFormsModule, FormsModule, ReactiveFormsModule, RouterTestingModule], - providers: [ - { provide: TechnicalRecordService, useValue: mockTechRecordService }, - provideMockStore({ initialState: initialAppState }), - { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, - ], - }).compileComponents(); - fixture = TestBed.createComponent(TechRecordEditAdditionalExaminerNoteComponent); - component = fixture.componentInstance; - router = TestBed.inject(Router); - errorService = TestBed.inject(GlobalErrorService); - route = TestBed.inject(ActivatedRoute); - store = TestBed.inject(MockStore); - }); - it('should create', () => { - expect(component).toBeTruthy(); - }); - describe('ngOnInit', () => { - it('should call all initialisation functions', () => { - const examinerNoteSpy = jest.spyOn(component, 'getExaminerNote').mockReturnValue(); - const techRecordSpy = jest.spyOn(component, 'getTechRecord').mockReturnValue(); - const formSpy = jest.spyOn(component, 'setupForm').mockReturnValue(); - component.ngOnInit(); - expect(examinerNoteSpy).toHaveBeenCalled(); - expect(formSpy).toHaveBeenCalled(); - expect(techRecordSpy).toHaveBeenCalled(); - }); - }); - describe('navigateBack', () => { - it('should clear all errors', () => { - jest.spyOn(router, 'navigate').mockImplementation(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TechRecordEditAdditionalExaminerNoteComponent], + imports: [DynamicFormsModule, FormsModule, ReactiveFormsModule, RouterTestingModule], + providers: [ + { provide: TechnicalRecordService, useValue: mockTechRecordService }, + provideMockStore({ initialState: initialAppState }), + { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(TechRecordEditAdditionalExaminerNoteComponent); + component = fixture.componentInstance; + router = TestBed.inject(Router); + errorService = TestBed.inject(GlobalErrorService); + route = TestBed.inject(ActivatedRoute); + store = TestBed.inject(MockStore); + }); + it('should create', () => { + expect(component).toBeTruthy(); + }); + describe('ngOnInit', () => { + it('should call all initialisation functions', () => { + const examinerNoteSpy = jest.spyOn(component, 'getExaminerNote').mockReturnValue(); + const techRecordSpy = jest.spyOn(component, 'getTechRecord').mockReturnValue(); + const formSpy = jest.spyOn(component, 'setupForm').mockReturnValue(); + component.ngOnInit(); + expect(examinerNoteSpy).toHaveBeenCalled(); + expect(formSpy).toHaveBeenCalled(); + expect(techRecordSpy).toHaveBeenCalled(); + }); + }); + describe('navigateBack', () => { + it('should clear all errors', () => { + jest.spyOn(router, 'navigate').mockImplementation(); - const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); + const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); - component.navigateBack(); + component.navigateBack(); - expect(clearErrorsSpy).toHaveBeenCalledTimes(1); - }); + expect(clearErrorsSpy).toHaveBeenCalledTimes(1); + }); - it('should navigate back to the previous page', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + it('should navigate back to the previous page', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - component.navigateBack(); + component.navigateBack(); - expect(navigateSpy).toHaveBeenCalledWith(['../../'], { relativeTo: route }); - }); - }); - describe('handleSubmit', () => { - it('should not dispatch an action if the notes are the same', () => { - const storeSpy = jest.spyOn(store, 'dispatch'); - const navigateBackSpy = jest.spyOn(component, 'navigateBack').mockReturnValue(); - component.originalExaminerNote = 'foobar'; - component.editedExaminerNote = 'foobar'; - component.handleSubmit(); - expect(storeSpy).not.toHaveBeenCalled(); - expect(navigateBackSpy).toHaveBeenCalled(); - }); + expect(navigateSpy).toHaveBeenCalledWith(['../../'], { relativeTo: route }); + }); + }); + describe('handleSubmit', () => { + it('should not dispatch an action if the notes are the same', () => { + const storeSpy = jest.spyOn(store, 'dispatch'); + const navigateBackSpy = jest.spyOn(component, 'navigateBack').mockReturnValue(); + component.originalExaminerNote = 'foobar'; + component.editedExaminerNote = 'foobar'; + component.handleSubmit(); + expect(storeSpy).not.toHaveBeenCalled(); + expect(navigateBackSpy).toHaveBeenCalled(); + }); - it('should dispatch an action if the notes are not the same', () => { - const storeSpy = jest.spyOn(store, 'dispatch'); - const navigateBackSpy = jest.spyOn(component, 'navigateBack').mockReturnValue(); - component.originalExaminerNote = 'foo'; - component.editedExaminerNote = 'bar'; - component.handleSubmit(); - expect(storeSpy).toHaveBeenCalled(); - expect(navigateBackSpy).toHaveBeenCalled(); - }); - }); + it('should dispatch an action if the notes are not the same', () => { + const storeSpy = jest.spyOn(store, 'dispatch'); + const navigateBackSpy = jest.spyOn(component, 'navigateBack').mockReturnValue(); + component.originalExaminerNote = 'foo'; + component.editedExaminerNote = 'bar'; + component.handleSubmit(); + expect(storeSpy).toHaveBeenCalled(); + expect(navigateBackSpy).toHaveBeenCalled(); + }); + }); }); diff --git a/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.ts b/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.ts index 11e117cea6..4ac33b1d16 100644 --- a/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.ts +++ b/src/app/features/tech-record/components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component.ts @@ -1,108 +1,107 @@ import { Component, OnInit } from '@angular/core'; +import { FormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; -import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; -import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; -import { ReplaySubject, take, takeUntil } from 'rxjs'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; -import { - CustomFormControl, - FormNodeEditTypes, - FormNodeTypes, - FormNodeWidth, -} from '@forms/services/dynamic-form.types'; -import { FormGroup, Validators } from '@angular/forms'; +import { AdditionalExaminerNotes } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/hgv/complete'; +import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; +import { CustomFormControl, FormNodeEditTypes, FormNodeTypes, FormNodeWidth } from '@forms/services/dynamic-form.types'; import { Store } from '@ngrx/store'; +import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { State } from '@store/index'; import { updateExistingADRAdditionalExaminerNote } from '@store/technical-records'; -import { AdditionalExaminerNotes } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/hgv/complete'; +import { ReplaySubject, take, takeUntil } from 'rxjs'; @Component({ - selector: 'tech-record-edit-additional-examiner-note', - templateUrl: './tech-record-edit-additional-examiner-note.component.html', - styleUrls: ['./tech-record-edit-additional-examiner-note.component.scss'], + selector: 'tech-record-edit-additional-examiner-note', + templateUrl: './tech-record-edit-additional-examiner-note.component.html', + styleUrls: ['./tech-record-edit-additional-examiner-note.component.scss'], }) export class TechRecordEditAdditionalExaminerNoteComponent implements OnInit { - currentTechRecord!: TechRecordType<'hgv' | 'trl' | 'lgv'>; - examinerNoteIndex!: number; - editedExaminerNote: string = ''; - originalExaminerNote: string = ''; - examinerNoteObj!: AdditionalExaminerNotes; - destroy$ = new ReplaySubject(1); - form!: FormGroup; - formControl!: CustomFormControl; - - constructor( - private router: Router, - private route: ActivatedRoute, - private technicalRecordService: TechnicalRecordService, - private globalErrorService: GlobalErrorService, - private store: Store, - ) { } + currentTechRecord!: TechRecordType<'hgv' | 'trl' | 'lgv'>; + examinerNoteIndex!: number; + editedExaminerNote = ''; + originalExaminerNote = ''; + examinerNoteObj!: AdditionalExaminerNotes; + destroy$ = new ReplaySubject(1); + form!: FormGroup; + formControl!: CustomFormControl; - ngOnInit() { - this.getTechRecord(); - this.getExaminerNote(); - this.setupForm(); - } + constructor( + private router: Router, + private route: ActivatedRoute, + private technicalRecordService: TechnicalRecordService, + private globalErrorService: GlobalErrorService, + private store: Store + ) {} - getTechRecord() { - this.technicalRecordService.techRecord$.pipe(takeUntil(this.destroy$)).subscribe((currentTechRecord) => { - this.currentTechRecord = currentTechRecord as TechRecordType<'hgv' | 'lgv' | 'trl'>; - }); - } + ngOnInit() { + this.getTechRecord(); + this.getExaminerNote(); + this.setupForm(); + } - getExaminerNote() { - this.route.params.pipe(take(1)).subscribe((params) => { - this.examinerNoteIndex = params['examinerNoteIndex']; - }); - const additionalExaminerNotes = this.currentTechRecord?.techRecord_adrDetails_additionalExaminerNotes; - if (additionalExaminerNotes) { - const examinerNote = additionalExaminerNotes[this.examinerNoteIndex].note; - if (examinerNote) { - this.examinerNoteObj = additionalExaminerNotes[this.examinerNoteIndex]; - this.originalExaminerNote = examinerNote; - this.editedExaminerNote = examinerNote; - } - } - } + getTechRecord() { + this.technicalRecordService.techRecord$.pipe(takeUntil(this.destroy$)).subscribe((currentTechRecord) => { + this.currentTechRecord = currentTechRecord as TechRecordType<'hgv' | 'lgv' | 'trl'>; + }); + } - setupForm() { - this.formControl = new CustomFormControl({ - name: 'additionalExaminerNote', type: FormNodeTypes.CONTROL, - }, '', [Validators.required]); - this.form = new FormGroup({ - additionalExaminerNote: this.formControl, - }); - this.formControl.patchValue(this.editedExaminerNote); - } + getExaminerNote() { + this.route.params.pipe(take(1)).subscribe((params) => { + this.examinerNoteIndex = params['examinerNoteIndex']; + }); + const additionalExaminerNotes = this.currentTechRecord?.techRecord_adrDetails_additionalExaminerNotes; + if (additionalExaminerNotes) { + const examinerNote = additionalExaminerNotes[this.examinerNoteIndex].note; + if (examinerNote) { + this.examinerNoteObj = additionalExaminerNotes[this.examinerNoteIndex]; + this.originalExaminerNote = examinerNote; + this.editedExaminerNote = examinerNote; + } + } + } - navigateBack() { - this.globalErrorService.clearErrors(); - void this.router.navigate(['../../'], { relativeTo: this.route }); - } + setupForm() { + this.formControl = new CustomFormControl( + { + name: 'additionalExaminerNote', + type: FormNodeTypes.CONTROL, + }, + '', + [Validators.required] + ); + this.form = new FormGroup({ + additionalExaminerNote: this.formControl, + }); + this.formControl.patchValue(this.editedExaminerNote); + } - handleSubmit(): void { - if (this.originalExaminerNote !== this.editedExaminerNote) { - this.store.dispatch( - updateExistingADRAdditionalExaminerNote({ - examinerNoteIndex: this.examinerNoteIndex, - additionalExaminerNote: this.editedExaminerNote, - }), - ); - } - this.navigateBack(); - } + navigateBack() { + this.globalErrorService.clearErrors(); + void this.router.navigate(['../../'], { relativeTo: this.route }); + } - ngOnChanges(examinerNote: string) { - this.editedExaminerNote = examinerNote; - } + handleSubmit(): void { + if (this.originalExaminerNote !== this.editedExaminerNote) { + this.store.dispatch( + updateExistingADRAdditionalExaminerNote({ + examinerNoteIndex: this.examinerNoteIndex, + additionalExaminerNote: this.editedExaminerNote, + }) + ); + } + this.navigateBack(); + } - get editTypes(): typeof FormNodeEditTypes { - return FormNodeEditTypes; - } + ngOnChanges(examinerNote: string) { + this.editedExaminerNote = examinerNote; + } - get width(): typeof FormNodeWidth { - return FormNodeWidth; - } + get editTypes(): typeof FormNodeEditTypes { + return FormNodeEditTypes; + } + get width(): typeof FormNodeWidth { + return FormNodeWidth; + } } diff --git a/src/app/features/tech-record/components/tech-record-generate-letter/tech-record-generate-letter.component.spec.ts b/src/app/features/tech-record/components/tech-record-generate-letter/tech-record-generate-letter.component.spec.ts index 7c26c510b7..a93992cbfc 100644 --- a/src/app/features/tech-record/components/tech-record-generate-letter/tech-record-generate-letter.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-generate-letter/tech-record-generate-letter.component.spec.ts @@ -21,137 +21,143 @@ import { ReplaySubject, of } from 'rxjs'; import { GenerateLetterComponent } from './tech-record-generate-letter.component'; const mockTechRecordService = { - get techRecord$() { - return of(mockVehicleTechnicalRecord('trl')); - }, - updateEditingTechRecord: jest.fn(), - isUnique: jest.fn(), + get techRecord$() { + return of(mockVehicleTechnicalRecord('trl')); + }, + updateEditingTechRecord: jest.fn(), + isUnique: jest.fn(), }; const mockDynamicFormService = { - createForm: jest.fn(), + createForm: jest.fn(), }; describe('TechRecordGenerateLetterComponent', () => { - const actions$ = new ReplaySubject(); - let component: GenerateLetterComponent; - let errorService: GlobalErrorService; - let expectedVehicle = {} as TechRecordType<'trl'>; - let fixture: ComponentFixture; - let route: ActivatedRoute; - let router: Router; - let store: MockStore; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [GenerateLetterComponent], - providers: [ - GlobalErrorService, - provideMockActions(() => actions$), - provideMockStore({ initialState: initialAppState }), - { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, - { provide: DynamicFormService, useValue: mockDynamicFormService }, - { provide: TechnicalRecordService, useValue: mockTechRecordService }, - { - provide: UserService, - useValue: { - roles$: of(['TechRecord.Amend']), - }, - }, - ], - imports: [RouterTestingModule, SharedModule, ReactiveFormsModule, DynamicFormsModule, FixNavigationTriggeredOutsideAngularZoneNgModule], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(GenerateLetterComponent); - errorService = TestBed.inject(GlobalErrorService); - route = TestBed.inject(ActivatedRoute); - router = TestBed.inject(Router); - store = TestBed.inject(MockStore); - component = fixture.componentInstance; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('navigateBack', () => { - it('should clear all errors', () => { - jest.spyOn(router, 'navigate').mockImplementation(); - - const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); - - component.navigateBack(); - - expect(clearErrorsSpy).toHaveBeenCalledTimes(1); - }); - - it('should navigate back to the previous page', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - component.navigateBack(); - - expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); - }); - - it('should navigate back on generateLetterSuccess', () => { - const navigateBackSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - component.ngOnInit(); - - actions$.next(generateLetterSuccess()); - - expect(navigateBackSpy).toHaveBeenCalled(); - }); - }); - - describe('handleSubmit', () => { - beforeEach(() => { - expectedVehicle = mockVehicleTechnicalRecord('trl') as TechRecordType<'trl'>; - }); - - it('should add an error when the field is not filled out', () => { - const addErrorSpy = jest.spyOn(errorService, 'addError'); - - component.handleSubmit(); - - expect(addErrorSpy).toHaveBeenCalledWith({ error: 'Letter type is required', anchorLink: 'letterType' }); - }); - - describe('it should dispatch the generateLetter action with the correct paragraphIds', () => { - it('should dispatch with id 3 on acceptance', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.techRecord = expectedVehicle; - component.techRecord.techRecord_approvalType = ApprovalType.UKNI_WVTA; - - component.form.get('letterType')?.setValue('trailer acceptance'); - component.handleSubmit(); - - expect(dispatchSpy).toHaveBeenCalledWith(generateLetter({ letterType: 'trailer acceptance', paragraphId: 3 })); - }); - - it('should dispatch with id 4 on rejection', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.techRecord = expectedVehicle; - component.techRecord.techRecord_approvalType = ApprovalType.GB_WVTA; - - component.form.get('letterType')?.setValue('trailer rejection'); - component.handleSubmit(); - - expect(dispatchSpy).toHaveBeenCalledWith(generateLetter({ letterType: 'trailer rejection', paragraphId: 4 })); - }); - - it('should dispatch with id 6 on acceptance', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.techRecord = expectedVehicle; - component.techRecord.techRecord_approvalType = ApprovalType.GB_WVTA; - - component.form.get('letterType')?.setValue('trailer acceptance'); - component.handleSubmit(); + const actions$ = new ReplaySubject(); + let component: GenerateLetterComponent; + let errorService: GlobalErrorService; + let expectedVehicle = {} as TechRecordType<'trl'>; + let fixture: ComponentFixture; + let route: ActivatedRoute; + let router: Router; + let store: MockStore; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [GenerateLetterComponent], + providers: [ + GlobalErrorService, + provideMockActions(() => actions$), + provideMockStore({ initialState: initialAppState }), + { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, + { provide: DynamicFormService, useValue: mockDynamicFormService }, + { provide: TechnicalRecordService, useValue: mockTechRecordService }, + { + provide: UserService, + useValue: { + roles$: of(['TechRecord.Amend']), + }, + }, + ], + imports: [ + RouterTestingModule, + SharedModule, + ReactiveFormsModule, + DynamicFormsModule, + FixNavigationTriggeredOutsideAngularZoneNgModule, + ], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(GenerateLetterComponent); + errorService = TestBed.inject(GlobalErrorService); + route = TestBed.inject(ActivatedRoute); + router = TestBed.inject(Router); + store = TestBed.inject(MockStore); + component = fixture.componentInstance; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('navigateBack', () => { + it('should clear all errors', () => { + jest.spyOn(router, 'navigate').mockImplementation(); + + const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); + + component.navigateBack(); + + expect(clearErrorsSpy).toHaveBeenCalledTimes(1); + }); + + it('should navigate back to the previous page', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + component.navigateBack(); + + expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); + }); + + it('should navigate back on generateLetterSuccess', () => { + const navigateBackSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + component.ngOnInit(); + + actions$.next(generateLetterSuccess()); + + expect(navigateBackSpy).toHaveBeenCalled(); + }); + }); + + describe('handleSubmit', () => { + beforeEach(() => { + expectedVehicle = mockVehicleTechnicalRecord('trl') as TechRecordType<'trl'>; + }); + + it('should add an error when the field is not filled out', () => { + const addErrorSpy = jest.spyOn(errorService, 'addError'); + + component.handleSubmit(); + + expect(addErrorSpy).toHaveBeenCalledWith({ error: 'Letter type is required', anchorLink: 'letterType' }); + }); + + describe('it should dispatch the generateLetter action with the correct paragraphIds', () => { + it('should dispatch with id 3 on acceptance', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.techRecord = expectedVehicle; + component.techRecord.techRecord_approvalType = ApprovalType.UKNI_WVTA; + + component.form.get('letterType')?.setValue('trailer acceptance'); + component.handleSubmit(); + + expect(dispatchSpy).toHaveBeenCalledWith(generateLetter({ letterType: 'trailer acceptance', paragraphId: 3 })); + }); + + it('should dispatch with id 4 on rejection', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.techRecord = expectedVehicle; + component.techRecord.techRecord_approvalType = ApprovalType.GB_WVTA; + + component.form.get('letterType')?.setValue('trailer rejection'); + component.handleSubmit(); + + expect(dispatchSpy).toHaveBeenCalledWith(generateLetter({ letterType: 'trailer rejection', paragraphId: 4 })); + }); + + it('should dispatch with id 6 on acceptance', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.techRecord = expectedVehicle; + component.techRecord.techRecord_approvalType = ApprovalType.GB_WVTA; + + component.form.get('letterType')?.setValue('trailer acceptance'); + component.handleSubmit(); - expect(dispatchSpy).toHaveBeenCalledWith(generateLetter({ letterType: 'trailer acceptance', paragraphId: 6 })); - }); - }); - }); + expect(dispatchSpy).toHaveBeenCalledWith(generateLetter({ letterType: 'trailer acceptance', paragraphId: 6 })); + }); + }); + }); }); diff --git a/src/app/features/tech-record/components/tech-record-generate-letter/tech-record-generate-letter.component.ts b/src/app/features/tech-record/components/tech-record-generate-letter/tech-record-generate-letter.component.ts index 69480b088b..0161005f92 100644 --- a/src/app/features/tech-record/components/tech-record-generate-letter/tech-record-generate-letter.component.ts +++ b/src/app/features/tech-record/components/tech-record-generate-letter/tech-record-generate-letter.component.ts @@ -5,9 +5,7 @@ import { GlobalErrorService } from '@core/components/global-error/global-error.s import { ApprovalType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/approvalType.enum.js'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; -import { - CustomFormControl, FormNodeOption, FormNodeTypes, FormNodeWidth, -} from '@forms/services/dynamic-form.types'; +import { CustomFormControl, FormNodeOption, FormNodeTypes, FormNodeWidth } from '@forms/services/dynamic-form.types'; import { LETTER_TYPES } from '@forms/templates/general/letter-types'; import { StatusCodes, V3TechRecordModel } from '@models/vehicle-tech-record.model'; import { Actions, ofType } from '@ngrx/effects'; @@ -19,84 +17,87 @@ import { TechnicalRecordServiceState } from '@store/technical-records/reducers/t import { take } from 'rxjs'; @Component({ - selector: 'app-generate-letter', - templateUrl: './tech-record-generate-letter.component.html', - styleUrls: ['./tech-record-generate-letter.component.scss'], + selector: 'app-generate-letter', + templateUrl: './tech-record-generate-letter.component.html', + styleUrls: ['./tech-record-generate-letter.component.scss'], }) export class GenerateLetterComponent implements OnInit { - techRecord?: V3TechRecordModel; - form = new FormGroup({ - letterType: new CustomFormControl({ name: 'letterType', label: 'Type of letter to generate', type: FormNodeTypes.CONTROL }, '', [ - Validators.required, - ]), - }); - width: FormNodeWidth = FormNodeWidth.L; + techRecord?: V3TechRecordModel; + form = new FormGroup({ + letterType: new CustomFormControl( + { name: 'letterType', label: 'Type of letter to generate', type: FormNodeTypes.CONTROL }, + '', + [Validators.required] + ), + }); + width: FormNodeWidth = FormNodeWidth.L; - paragraphMap = new Map([ - [ApprovalType.GB_WVTA, 6], - [ApprovalType.UKNI_WVTA, 3], - [ApprovalType.EU_WVTA_PRE_23, 3], - [ApprovalType.EU_WVTA_23_ON, 7], - [ApprovalType.QNIG, 3], - [ApprovalType.PROV_GB_WVTA, 3], - [ApprovalType.SMALL_SERIES_NKS, 3], - [ApprovalType.SMALL_SERIES_NKSXX, 3], - [ApprovalType.IVA_VCA, 3], - [ApprovalType.IVA_DVSA_NI, 3], - ]); + paragraphMap = new Map([ + [ApprovalType.GB_WVTA, 6], + [ApprovalType.UKNI_WVTA, 3], + [ApprovalType.EU_WVTA_PRE_23, 3], + [ApprovalType.EU_WVTA_23_ON, 7], + [ApprovalType.QNIG, 3], + [ApprovalType.PROV_GB_WVTA, 3], + [ApprovalType.SMALL_SERIES_NKS, 3], + [ApprovalType.SMALL_SERIES_NKSXX, 3], + [ApprovalType.IVA_VCA, 3], + [ApprovalType.IVA_DVSA_NI, 3], + ]); - constructor( - private actions$: Actions, - public dfs: DynamicFormService, - private globalErrorService: GlobalErrorService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - private technicalRecordService: TechnicalRecordService, - public userService: UserService, - ) {} + constructor( + private actions$: Actions, + public dfs: DynamicFormService, + private globalErrorService: GlobalErrorService, + private route: ActivatedRoute, + private router: Router, + private store: Store, + private technicalRecordService: TechnicalRecordService, + public userService: UserService + ) {} - ngOnInit(): void { - this.technicalRecordService.techRecord$.pipe(take(1)).subscribe((techRecord) => { - this.techRecord = techRecord; - }); - this.actions$.pipe(ofType(generateLetterSuccess), take(1)).subscribe(() => this.navigateBack()); - } + ngOnInit(): void { + this.technicalRecordService.techRecord$.pipe(take(1)).subscribe((techRecord) => { + this.techRecord = techRecord; + }); + this.actions$.pipe(ofType(generateLetterSuccess), take(1)).subscribe(() => this.navigateBack()); + } - get reasons(): Array> { - if (this.techRecord?.techRecord_statusCode === StatusCodes.PROVISIONAL) { - return [ - { label: 'Trailer rejected', value: LETTER_TYPES[1].value }, - ]; - } - return [ - { label: 'Trailer accepted', value: LETTER_TYPES[0].value }, - { label: 'Trailer rejected', value: LETTER_TYPES[1].value }, - ]; - } + get reasons(): Array> { + if (this.techRecord?.techRecord_statusCode === StatusCodes.PROVISIONAL) { + return [{ label: 'Trailer rejected', value: LETTER_TYPES[1].value }]; + } + return [ + { label: 'Trailer accepted', value: LETTER_TYPES[0].value }, + { label: 'Trailer rejected', value: LETTER_TYPES[1].value }, + ]; + } - get emailAddress(): string | undefined { - return this.techRecord?.techRecord_vehicleType === 'trl' ? this.techRecord?.techRecord_applicantDetails_emailAddress ?? '' : undefined; - } + get emailAddress(): string | undefined { + return this.techRecord?.techRecord_vehicleType === 'trl' + ? this.techRecord?.techRecord_applicantDetails_emailAddress ?? '' + : undefined; + } - navigateBack() { - this.globalErrorService.clearErrors(); - void this.router.navigate(['..'], { relativeTo: this.route }); - } + navigateBack() { + this.globalErrorService.clearErrors(); + void this.router.navigate(['..'], { relativeTo: this.route }); + } - handleSubmit(): void { - this.globalErrorService.clearErrors(); - if (this.form.value.letterType === '') { - return this.globalErrorService.addError({ error: 'Letter type is required', anchorLink: 'letterType' }); - } - if (!this.techRecord) { - return this.globalErrorService.addError({ error: 'Could not retrieve current technical record' }); - } + handleSubmit(): void { + this.globalErrorService.clearErrors(); + if (this.form.value.letterType === '') { + return this.globalErrorService.addError({ error: 'Letter type is required', anchorLink: 'letterType' }); + } + if (!this.techRecord) { + return this.globalErrorService.addError({ error: 'Could not retrieve current technical record' }); + } - const paragraphId = this.form.value.letterType === 'trailer acceptance' - ? this.paragraphMap.get((this.techRecord as TechRecordType<'trl'>).techRecord_approvalType as ApprovalType) - : 4; + const paragraphId = + this.form.value.letterType === 'trailer acceptance' + ? this.paragraphMap.get((this.techRecord as TechRecordType<'trl'>).techRecord_approvalType as ApprovalType) + : 4; - this.store.dispatch(generateLetter({ letterType: this.form.value.letterType, paragraphId: paragraphId ?? 4 })); - } + this.store.dispatch(generateLetter({ letterType: this.form.value.letterType, paragraphId: paragraphId ?? 4 })); + } } diff --git a/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.spec.ts b/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.spec.ts index 69ebe19da4..f1de33b1b0 100644 --- a/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.spec.ts @@ -1,7 +1,5 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { - ComponentFixture, fakeAsync, TestBed, tick, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; @@ -17,121 +15,124 @@ import { UserService } from '@services/user-service/user-service'; import { SharedModule } from '@shared/shared.module'; import { initialAppState } from '@store/index'; import { generatePlate, generatePlateSuccess } from '@store/technical-records'; -import { of, ReplaySubject } from 'rxjs'; +import { ReplaySubject, of } from 'rxjs'; import { GeneratePlateComponent } from './tech-record-generate-plate.component'; const mockDynamicFormService = { - createForm: jest.fn(), + createForm: jest.fn(), }; describe('TechRecordGeneratePlateComponent', () => { - const actions$ = new ReplaySubject(); - let component: GeneratePlateComponent; - let errorService: GlobalErrorService; - let fixture: ComponentFixture; - let route: ActivatedRoute; - let router: Router; - let store: MockStore; - let technicalRecordService: TechnicalRecordService; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [GeneratePlateComponent], - providers: [ - GlobalErrorService, - provideMockActions(() => actions$), - provideMockStore({ initialState: initialAppState }), - { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, - { provide: DynamicFormService, useValue: mockDynamicFormService }, - TechnicalRecordService, - { - provide: UserService, - useValue: { - roles$: of(['TechRecord.Amend']), - }, - }, - ], - imports: [RouterTestingModule, SharedModule, ReactiveFormsModule, DynamicFormsModule, HttpClientTestingModule], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(GeneratePlateComponent); - errorService = TestBed.inject(GlobalErrorService); - route = TestBed.inject(ActivatedRoute); - router = TestBed.inject(Router); - store = TestBed.inject(MockStore); - technicalRecordService = TestBed.inject(TechnicalRecordService); - component = fixture.componentInstance; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('navigateBack', () => { - beforeEach(() => { - jest - .spyOn(technicalRecordService, 'techRecord$', 'get') - .mockReturnValue(of({ systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel)); - }); - it('should clear all errors', () => { - jest.spyOn(router, 'navigate').mockImplementation(); - - const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); - - component.navigateBack(); - - expect(clearErrorsSpy).toHaveBeenCalledTimes(1); - }); - - it('should navigate back to the previous page', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - component.navigateBack(); - - expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); - }); - - it('should navigate back on generatePlateSuccess', fakeAsync(() => { - fixture.ngZone?.run(() => { - component.ngOnInit(); - component.form.get('reason')?.setValue('Provisional'); - - const navigateBackSpy = jest.spyOn(component, 'navigateBack').mockImplementation(); - - component.handleSubmit(); - - actions$.next(generatePlateSuccess()); - tick(); - - expect(navigateBackSpy).toHaveBeenCalled(); - }); - })); - }); - - describe('handleSubmit', () => { - beforeEach(() => { - jest - .spyOn(technicalRecordService, 'techRecord$', 'get') - .mockReturnValue(of({ systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel)); - }); - it('should add an error when the field is not filled out', () => { - const addErrorSpy = jest.spyOn(errorService, 'addError'); - - component.handleSubmit(); - - expect(addErrorSpy).toHaveBeenCalledWith({ error: 'Reason for generating plate is required', anchorLink: 'reason' }); - }); - - it('should dispatch the generatePlate action', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - - component.form.get('reason')?.setValue('Provisional'); - - component.handleSubmit(); - - expect(dispatchSpy).toHaveBeenCalledWith(generatePlate({ reason: 'Provisional' })); - }); - }); + const actions$ = new ReplaySubject(); + let component: GeneratePlateComponent; + let errorService: GlobalErrorService; + let fixture: ComponentFixture; + let route: ActivatedRoute; + let router: Router; + let store: MockStore; + let technicalRecordService: TechnicalRecordService; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [GeneratePlateComponent], + providers: [ + GlobalErrorService, + provideMockActions(() => actions$), + provideMockStore({ initialState: initialAppState }), + { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, + { provide: DynamicFormService, useValue: mockDynamicFormService }, + TechnicalRecordService, + { + provide: UserService, + useValue: { + roles$: of(['TechRecord.Amend']), + }, + }, + ], + imports: [RouterTestingModule, SharedModule, ReactiveFormsModule, DynamicFormsModule, HttpClientTestingModule], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(GeneratePlateComponent); + errorService = TestBed.inject(GlobalErrorService); + route = TestBed.inject(ActivatedRoute); + router = TestBed.inject(Router); + store = TestBed.inject(MockStore); + technicalRecordService = TestBed.inject(TechnicalRecordService); + component = fixture.componentInstance; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('navigateBack', () => { + beforeEach(() => { + jest + .spyOn(technicalRecordService, 'techRecord$', 'get') + .mockReturnValue(of({ systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel)); + }); + it('should clear all errors', () => { + jest.spyOn(router, 'navigate').mockImplementation(); + + const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); + + component.navigateBack(); + + expect(clearErrorsSpy).toHaveBeenCalledTimes(1); + }); + + it('should navigate back to the previous page', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + component.navigateBack(); + + expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); + }); + + it('should navigate back on generatePlateSuccess', fakeAsync(() => { + fixture.ngZone?.run(() => { + component.ngOnInit(); + component.form.get('reason')?.setValue('Provisional'); + + const navigateBackSpy = jest.spyOn(component, 'navigateBack').mockImplementation(); + + component.handleSubmit(); + + actions$.next(generatePlateSuccess()); + tick(); + + expect(navigateBackSpy).toHaveBeenCalled(); + }); + })); + }); + + describe('handleSubmit', () => { + beforeEach(() => { + jest + .spyOn(technicalRecordService, 'techRecord$', 'get') + .mockReturnValue(of({ systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel)); + }); + it('should add an error when the field is not filled out', () => { + const addErrorSpy = jest.spyOn(errorService, 'addError'); + + component.handleSubmit(); + + expect(addErrorSpy).toHaveBeenCalledWith({ + error: 'Reason for generating plate is required', + anchorLink: 'reason', + }); + }); + + it('should dispatch the generatePlate action', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + + component.form.get('reason')?.setValue('Provisional'); + + component.handleSubmit(); + + expect(dispatchSpy).toHaveBeenCalledWith(generatePlate({ reason: 'Provisional' })); + }); + }); }); diff --git a/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.ts b/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.ts index d1b87ba890..d329add78c 100644 --- a/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.ts +++ b/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.ts @@ -3,91 +3,97 @@ import { FormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { PlatesInner } from '@api/vehicle'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; -import { - CustomFormControl, FormNodeOption, FormNodeTypes, FormNodeWidth, -} from '@forms/services/dynamic-form.types'; +import { CustomFormControl, FormNodeOption, FormNodeTypes, FormNodeWidth } from '@forms/services/dynamic-form.types'; import { Actions, ofType } from '@ngrx/effects'; import { Store, select } from '@ngrx/store'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { UserService } from '@services/user-service/user-service'; import { State } from '@store/index'; import { - cannotGeneratePlate, generatePlate, generatePlateSuccess, getCanGeneratePlate, + cannotGeneratePlate, + generatePlate, + generatePlateSuccess, + getCanGeneratePlate, } from '@store/technical-records'; -import { - Observable, map, take, tap, -} from 'rxjs'; +import { Observable, map, take, tap } from 'rxjs'; @Component({ - selector: 'app-generate-plate', - templateUrl: './tech-record-generate-plate.component.html', - styleUrls: ['./tech-record-generate-plate.component.scss'], + selector: 'app-generate-plate', + templateUrl: './tech-record-generate-plate.component.html', + styleUrls: ['./tech-record-generate-plate.component.scss'], }) export class GeneratePlateComponent implements OnInit { - form = new FormGroup({ - reason: new CustomFormControl({ name: 'reason', label: 'Reason for generating plate', type: FormNodeTypes.CONTROL }, '', [Validators.required]), - }); + form = new FormGroup({ + reason: new CustomFormControl( + { name: 'reason', label: 'Reason for generating plate', type: FormNodeTypes.CONTROL }, + '', + [Validators.required] + ), + }); - emailAddress$?: Observable; + emailAddress$?: Observable; - constructor( - private actions$: Actions, - private globalErrorService: GlobalErrorService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - public userService: UserService, - private technicalRecordService: TechnicalRecordService, - ) {} + constructor( + private actions$: Actions, + private globalErrorService: GlobalErrorService, + private route: ActivatedRoute, + private router: Router, + private store: Store, + public userService: UserService, + private technicalRecordService: TechnicalRecordService + ) {} - ngOnInit(): void { - this.actions$.pipe(ofType(generatePlateSuccess), take(1)).subscribe(() => { - this.navigateBack(); - }); - this.store.pipe(select(getCanGeneratePlate), take(1)).subscribe((canGeneratePlate) => { - if (!canGeneratePlate) { - this.navigateBack(); - } - }); - this.emailAddress$ = this.technicalRecordService.techRecord$.pipe( - tap((record) => { - if (record?.techRecord_vehicleType !== 'hgv' && record?.techRecord_vehicleType !== 'trl') this.navigateBack(); - }), - map((record) => { - if (record?.techRecord_vehicleType !== 'hgv' && record?.techRecord_vehicleType !== 'trl') { - return undefined; - } - return record?.techRecord_applicantDetails_emailAddress; - }), - ); - } + ngOnInit(): void { + this.actions$.pipe(ofType(generatePlateSuccess), take(1)).subscribe(() => { + this.navigateBack(); + }); + this.store.pipe(select(getCanGeneratePlate), take(1)).subscribe((canGeneratePlate) => { + if (!canGeneratePlate) { + this.navigateBack(); + } + }); + this.emailAddress$ = this.technicalRecordService.techRecord$.pipe( + tap((record) => { + if (record?.techRecord_vehicleType !== 'hgv' && record?.techRecord_vehicleType !== 'trl') this.navigateBack(); + }), + map((record) => { + if (record?.techRecord_vehicleType !== 'hgv' && record?.techRecord_vehicleType !== 'trl') { + return undefined; + } + return record?.techRecord_applicantDetails_emailAddress; + }) + ); + } - get width(): FormNodeWidth { - return FormNodeWidth.L; - } + get width(): FormNodeWidth { + return FormNodeWidth.L; + } - get reasons(): Array> { - return [ - { label: 'Free replacement', value: PlatesInner.PlateReasonForIssueEnum.FreeReplacement }, - { label: 'Replacement', value: PlatesInner.PlateReasonForIssueEnum.Replacement }, - { label: 'Destroyed', value: PlatesInner.PlateReasonForIssueEnum.Destroyed }, - { label: 'Provisional', value: PlatesInner.PlateReasonForIssueEnum.Provisional }, - { label: 'Original', value: PlatesInner.PlateReasonForIssueEnum.Original }, - { label: 'Manual', value: PlatesInner.PlateReasonForIssueEnum.Manual }, - ]; - } + get reasons(): Array> { + return [ + { label: 'Free replacement', value: PlatesInner.PlateReasonForIssueEnum.FreeReplacement }, + { label: 'Replacement', value: PlatesInner.PlateReasonForIssueEnum.Replacement }, + { label: 'Destroyed', value: PlatesInner.PlateReasonForIssueEnum.Destroyed }, + { label: 'Provisional', value: PlatesInner.PlateReasonForIssueEnum.Provisional }, + { label: 'Original', value: PlatesInner.PlateReasonForIssueEnum.Original }, + { label: 'Manual', value: PlatesInner.PlateReasonForIssueEnum.Manual }, + ]; + } - navigateBack() { - this.globalErrorService.clearErrors(); - void this.router.navigate(['..'], { relativeTo: this.route }); - } + navigateBack() { + this.globalErrorService.clearErrors(); + void this.router.navigate(['..'], { relativeTo: this.route }); + } - handleSubmit(): void { - this.globalErrorService.clearErrors(); - if (!this.form.value.reason) { - return this.globalErrorService.addError({ error: 'Reason for generating plate is required', anchorLink: 'reason' }); - } - this.store.dispatch(generatePlate({ reason: this.form.value.reason })); - this.store.dispatch(cannotGeneratePlate()); - } + handleSubmit(): void { + this.globalErrorService.clearErrors(); + if (!this.form.value.reason) { + return this.globalErrorService.addError({ + error: 'Reason for generating plate is required', + anchorLink: 'reason', + }); + } + this.store.dispatch(generatePlate({ reason: this.form.value.reason })); + this.store.dispatch(cannotGeneratePlate()); + } } diff --git a/src/app/features/tech-record/components/tech-record-history/tech-record-history.component.spec.ts b/src/app/features/tech-record/components/tech-record-history/tech-record-history.component.spec.ts index 2f3cdb7d9f..e2ce5f0833 100644 --- a/src/app/features/tech-record/components/tech-record-history/tech-record-history.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-history/tech-record-history.component.spec.ts @@ -9,24 +9,24 @@ import { initialAppState } from '@store/index'; import { TechRecordHistoryComponent } from './tech-record-history.component'; describe('TechRecordHistoryComponent', () => { - let component: TechRecordHistoryComponent; - let fixture: ComponentFixture; + let component: TechRecordHistoryComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TechRecordHistoryComponent], - imports: [HttpClientTestingModule, RouterTestingModule, SharedModule], - providers: [TechnicalRecordService, provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TechRecordHistoryComponent], + imports: [HttpClientTestingModule, RouterTestingModule, SharedModule], + providers: [TechnicalRecordService, provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TechRecordHistoryComponent); - component = fixture.componentInstance; - component.currentTechRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel; - fixture.detectChanges(); - }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(TechRecordHistoryComponent); + component = fixture.componentInstance; + component.currentTechRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel; + fixture.detectChanges(); + }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/features/tech-record/components/tech-record-history/tech-record-history.component.ts b/src/app/features/tech-record/components/tech-record-history/tech-record-history.component.ts index af9b4dabc3..ab6448133a 100644 --- a/src/app/features/tech-record/components/tech-record-history/tech-record-history.component.ts +++ b/src/app/features/tech-record/components/tech-record-history/tech-record-history.component.ts @@ -1,6 +1,4 @@ -import { - ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, -} from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; import { V3TechRecordModel } from '@models/vehicle-tech-record.model'; @@ -9,56 +7,61 @@ import { getBySystemNumber, selectTechRecordHistory } from '@store/technical-rec import { Observable, map } from 'rxjs'; @Component({ - selector: 'app-tech-record-history', - templateUrl: './tech-record-history.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, - styleUrls: ['./tech-record-history.component.scss'], + selector: 'app-tech-record-history', + templateUrl: './tech-record-history.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + styleUrls: ['./tech-record-history.component.scss'], }) export class TechRecordHistoryComponent implements OnInit { - @Input() currentTechRecord?: V3TechRecordModel; + @Input() currentTechRecord?: V3TechRecordModel; - pageStart?: number; - pageEnd?: number; + pageStart?: number; + pageEnd?: number; - constructor(private cdr: ChangeDetectorRef, private store: Store) {} + constructor( + private cdr: ChangeDetectorRef, + private store: Store + ) {} - ngOnInit(): void { - if (this.currentTechRecord) { - this.store.dispatch(getBySystemNumber({ systemNumber: (this.currentTechRecord as TechRecordType<'get'>)?.systemNumber })); - } - } + ngOnInit(): void { + if (this.currentTechRecord) { + this.store.dispatch( + getBySystemNumber({ systemNumber: (this.currentTechRecord as TechRecordType<'get'>)?.systemNumber }) + ); + } + } - get techRecordHistory$() { - return this.store.select(selectTechRecordHistory); - } + get techRecordHistory$() { + return this.store.select(selectTechRecordHistory); + } - get techRecordHistoryPage$(): Observable { - return this.techRecordHistory$?.pipe(map((records) => records?.slice(this.pageStart, this.pageEnd) ?? [])); - } + get techRecordHistoryPage$(): Observable { + return this.techRecordHistory$?.pipe(map((records) => records?.slice(this.pageStart, this.pageEnd) ?? [])); + } - get numberOfRecords$(): Observable { - return this.techRecordHistory$?.pipe(map((records) => records?.length ?? 0)); - } + get numberOfRecords$(): Observable { + return this.techRecordHistory$?.pipe(map((records) => records?.length ?? 0)); + } - convertToUnix(date: Date): number { - return new Date(date).getTime(); - } + convertToUnix(date: Date): number { + return new Date(date).getTime(); + } - handlePaginationChange({ start, end }: { start: number; end: number }) { - this.pageStart = start; - this.pageEnd = end; - this.cdr.detectChanges(); - } + handlePaginationChange({ start, end }: { start: number; end: number }) { + this.pageStart = start; + this.pageEnd = end; + this.cdr.detectChanges(); + } - trackByFn(i: number, tr: TechRecordSearchSchema) { - return tr.createdTimestamp; - } + trackByFn(i: number, tr: TechRecordSearchSchema) { + return tr.createdTimestamp; + } - summaryLinkUrl(searchResult: TechRecordSearchSchema) { - return `/tech-records/${searchResult.systemNumber}/${searchResult.createdTimestamp}`; - } + summaryLinkUrl(searchResult: TechRecordSearchSchema) { + return `/tech-records/${searchResult.systemNumber}/${searchResult.createdTimestamp}`; + } - get currentTimeStamp() { - return (this.currentTechRecord as TechRecordType<'get'>).createdTimestamp; - } + get currentTimeStamp() { + return (this.currentTechRecord as TechRecordType<'get'>).createdTimestamp; + } } diff --git a/src/app/features/tech-record/components/tech-record-search-tyres/tech-record-search-tyres.component.spec.ts b/src/app/features/tech-record/components/tech-record-search-tyres/tech-record-search-tyres.component.spec.ts index df6d8a2d23..f3a8ec16db 100644 --- a/src/app/features/tech-record/components/tech-record-search-tyres/tech-record-search-tyres.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-search-tyres/tech-record-search-tyres.component.spec.ts @@ -1,7 +1,5 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { - ComponentFixture, TestBed, fakeAsync, tick, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { ActivatedRoute, Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { GlobalError } from '@core/components/global-error/global-error.interface'; @@ -24,236 +22,250 @@ import { Observable, ReplaySubject, of } from 'rxjs'; import { TechRecordSearchTyresComponent } from './tech-record-search-tyres.component'; const mockGlobalErrorService = { - addError: jest.fn(), - clearErrors: jest.fn(), + addError: jest.fn(), + clearErrors: jest.fn(), }; const mockTechRecordService = { - get techRecord$() { - return of({}); - }, + get techRecord$() { + return of({}); + }, }; const mockReferenceDataService = { - addSearchInformation: jest.fn(), - getTyreSearchReturn$: jest.fn(), - getTyreSearchCriteria$: jest.fn(), - loadReferenceDataByKeySearch: jest.fn(), - loadTyreReferenceDataByKeySearch: jest.fn(), - loadReferenceData: jest.fn(), + addSearchInformation: jest.fn(), + getTyreSearchReturn$: jest.fn(), + getTyreSearchCriteria$: jest.fn(), + loadReferenceDataByKeySearch: jest.fn(), + loadTyreReferenceDataByKeySearch: jest.fn(), + loadReferenceData: jest.fn(), }; const mockDynamicFormService = { - createForm: jest.fn(), + createForm: jest.fn(), }; describe('TechRecordSearchTyresComponent', () => { - let component: TechRecordSearchTyresComponent; - let fixture: ComponentFixture; - const actions$ = new ReplaySubject(); - let router: Router; - let route: ActivatedRoute; - let store: MockStore; + let component: TechRecordSearchTyresComponent; + let fixture: ComponentFixture; + const actions$ = new ReplaySubject(); + let router: Router; + let route: ActivatedRoute; + let store: MockStore; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TechRecordSearchTyresComponent], - imports: [DynamicFormsModule, RouterTestingModule, SharedModule, HttpClientTestingModule, FixNavigationTriggeredOutsideAngularZoneNgModule], - providers: [ - provideMockActions(() => actions$), - provideMockStore({ initialState: initialAppState }), - { provide: ReferenceDataService, useValue: mockReferenceDataService }, - { provide: TechnicalRecordService, useValue: mockTechRecordService }, - { provide: DynamicFormService, useValue: mockDynamicFormService }, - { provide: GlobalErrorService, useValue: mockGlobalErrorService }, - ], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TechRecordSearchTyresComponent], + imports: [ + DynamicFormsModule, + RouterTestingModule, + SharedModule, + HttpClientTestingModule, + FixNavigationTriggeredOutsideAngularZoneNgModule, + ], + providers: [ + provideMockActions(() => actions$), + provideMockStore({ initialState: initialAppState }), + { provide: ReferenceDataService, useValue: mockReferenceDataService }, + { provide: TechnicalRecordService, useValue: mockTechRecordService }, + { provide: DynamicFormService, useValue: mockDynamicFormService }, + { provide: GlobalErrorService, useValue: mockGlobalErrorService }, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TechRecordSearchTyresComponent); - router = TestBed.inject(Router); - route = TestBed.inject(ActivatedRoute); - store = TestBed.inject(MockStore); - component = fixture.componentInstance; - }); + beforeEach(() => { + fixture = TestBed.createComponent(TechRecordSearchTyresComponent); + router = TestBed.inject(Router); + route = TestBed.inject(ActivatedRoute); + store = TestBed.inject(MockStore); + component = fixture.componentInstance; + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); - it('should return roles', () => { - const { roles } = component; - expect(roles).toBe(Roles); - }); - it('should return errors', () => { - const expectedError: GlobalError = { error: 'Error message', anchorLink: 'expected' }; - const expectedResult = component.getErrorByName([expectedError], expectedError.anchorLink ?? ''); - expect(expectedResult).toBe(expectedError); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); + it('should return roles', () => { + const { roles } = component; + expect(roles).toBe(Roles); + }); + it('should return errors', () => { + const expectedError: GlobalError = { error: 'Error message', anchorLink: 'expected' }; + const expectedResult = component.getErrorByName([expectedError], expectedError.anchorLink ?? ''); + expect(expectedResult).toBe(expectedError); + }); - describe('handleSearch', () => { - it('should set search results to an empty array before populating data', () => { - component.handleSearch('', ''); - expect(component.searchResults).toStrictEqual([]); - }); - it('should call add error in global error service when term is empty', () => { - const filter = 'code'; - component.handleSearch('', filter); - expect(mockGlobalErrorService.addError).toHaveBeenCalled(); - }); - it('should call add error in global error service when filter is empty', () => { - const term = '103'; - component.handleSearch(term, ''); - expect(mockGlobalErrorService.addError).toHaveBeenCalled(); - }); - it('should call correct endpoint if filter === code', () => { - const filter = 'code'; - const term = '103'; - component.handleSearch(filter, term); - expect(mockReferenceDataService.loadReferenceDataByKeySearch).toHaveBeenCalledWith(ReferenceDataResourceType.Tyres, term); - }); - it('should call correct endpoint if filter === plyrating', () => { - const filter = 'plyrating'; - const term = '103'; - component.handleSearch(filter, term); - expect(mockReferenceDataService.loadTyreReferenceDataByKeySearch).toHaveBeenCalledWith(filter, term); - }); - it('should call correct endpoint if filter === singleload', () => { - const filter = 'singleload'; - const term = '103'; - component.handleSearch(filter, term); - expect(mockReferenceDataService.loadTyreReferenceDataByKeySearch).toHaveBeenCalledWith(filter, term); - }); - it('should call correct endpoint if filter === doubleload', () => { - const filter = 'doubleload'; - const term = '103'; - component.handleSearch(filter, term); - expect(mockReferenceDataService.loadTyreReferenceDataByKeySearch).toHaveBeenCalledWith(filter, term); - }); - it('should navigate and populate the search results on success action', fakeAsync(() => { - const navigateSpy = jest.spyOn(router, 'navigate'); - const mockTyreSearchReturn = ['foo', 'bar']; + describe('handleSearch', () => { + it('should set search results to an empty array before populating data', () => { + component.handleSearch('', ''); + expect(component.searchResults).toStrictEqual([]); + }); + it('should call add error in global error service when term is empty', () => { + const filter = 'code'; + component.handleSearch('', filter); + expect(mockGlobalErrorService.addError).toHaveBeenCalled(); + }); + it('should call add error in global error service when filter is empty', () => { + const term = '103'; + component.handleSearch(term, ''); + expect(mockGlobalErrorService.addError).toHaveBeenCalled(); + }); + it('should call correct endpoint if filter === code', () => { + const filter = 'code'; + const term = '103'; + component.handleSearch(filter, term); + expect(mockReferenceDataService.loadReferenceDataByKeySearch).toHaveBeenCalledWith( + ReferenceDataResourceType.Tyres, + term + ); + }); + it('should call correct endpoint if filter === plyrating', () => { + const filter = 'plyrating'; + const term = '103'; + component.handleSearch(filter, term); + expect(mockReferenceDataService.loadTyreReferenceDataByKeySearch).toHaveBeenCalledWith(filter, term); + }); + it('should call correct endpoint if filter === singleload', () => { + const filter = 'singleload'; + const term = '103'; + component.handleSearch(filter, term); + expect(mockReferenceDataService.loadTyreReferenceDataByKeySearch).toHaveBeenCalledWith(filter, term); + }); + it('should call correct endpoint if filter === doubleload', () => { + const filter = 'doubleload'; + const term = '103'; + component.handleSearch(filter, term); + expect(mockReferenceDataService.loadTyreReferenceDataByKeySearch).toHaveBeenCalledWith(filter, term); + }); + it('should navigate and populate the search results on success action', fakeAsync(() => { + const navigateSpy = jest.spyOn(router, 'navigate'); + const mockTyreSearchReturn = ['foo', 'bar']; - jest.spyOn(store, 'select').mockReturnValue(of(mockTyreSearchReturn)); - component.handleSearch('foo', 'bar'); + jest.spyOn(store, 'select').mockReturnValue(of(mockTyreSearchReturn)); + component.handleSearch('foo', 'bar'); - expect(mockReferenceDataService.loadTyreReferenceDataByKeySearch).toHaveBeenCalledWith('foo', 'bar'); - actions$.next(fetchReferenceDataByKeySearchSuccess); + expect(mockReferenceDataService.loadTyreReferenceDataByKeySearch).toHaveBeenCalledWith('foo', 'bar'); + actions$.next(fetchReferenceDataByKeySearchSuccess); - tick(); + tick(); - expect(navigateSpy).toHaveBeenCalledWith(['.'], { relativeTo: route, queryParams: { 'search-results-page': 1 } }); - expect(component.searchResults).toEqual(mockTyreSearchReturn); - })); + expect(navigateSpy).toHaveBeenCalledWith(['.'], { relativeTo: route, queryParams: { 'search-results-page': 1 } }); + expect(component.searchResults).toEqual(mockTyreSearchReturn); + })); - const testCases = [ - { filter: '', term: 'foo' }, - { filter: 'foo', term: '' }, - { filter: '', term: '' }, - ]; + const testCases = [ + { filter: '', term: 'foo' }, + { filter: 'foo', term: '' }, + { filter: '', term: '' }, + ]; - it.each(testCases)('should return early if the search information has not been provided', ({ filter, term }) => { - jest.resetAllMocks(); - const refDataServiceSpy = jest.spyOn(mockReferenceDataService, 'addSearchInformation'); - const errorServiceSpy = jest.spyOn(mockGlobalErrorService, 'addError'); - component.handleSearch(filter, term); - expect(refDataServiceSpy).not.toHaveBeenCalled(); - expect(errorServiceSpy).toHaveBeenCalledWith({ error: expect.stringContaining(term ? 'filter' : 'criteria'), anchorLink: 'term' }); - }); - }); + it.each(testCases)('should return early if the search information has not been provided', ({ filter, term }) => { + jest.resetAllMocks(); + const refDataServiceSpy = jest.spyOn(mockReferenceDataService, 'addSearchInformation'); + const errorServiceSpy = jest.spyOn(mockGlobalErrorService, 'addError'); + component.handleSearch(filter, term); + expect(refDataServiceSpy).not.toHaveBeenCalled(); + expect(errorServiceSpy).toHaveBeenCalledWith({ + error: expect.stringContaining(term ? 'filter' : 'criteria'), + anchorLink: 'term', + }); + }); + }); - describe('handleSelectTyreData', () => { - it('should have a truthy value for vehicle tech record', () => { - const tyre: ReferenceDataTyre = { - code: '103', - loadIndexSingleLoad: '0', - tyreSize: '0', - dateTimeStamp: '0', - userId: '0', - loadIndexTwinLoad: '0', - plyRating: '18', - resourceType: ReferenceDataResourceType.Tyres, - resourceKey: '103', - }; - component.handleAddTyreToRecord(tyre); - expect(mockTechRecordService.techRecord$).toBeTruthy(); - }); - it('should clear global errors', () => { - const tyre: ReferenceDataTyre = { - code: '103', - loadIndexSingleLoad: '0', - tyreSize: '0', - dateTimeStamp: '0', - userId: '0', - loadIndexTwinLoad: '0', - plyRating: '18', - resourceType: ReferenceDataResourceType.Tyres, - resourceKey: '103', - }; - component.handleAddTyreToRecord(tyre); - expect(mockGlobalErrorService.clearErrors).toHaveBeenCalled(); - }); - }); + describe('handleSelectTyreData', () => { + it('should have a truthy value for vehicle tech record', () => { + const tyre: ReferenceDataTyre = { + code: '103', + loadIndexSingleLoad: '0', + tyreSize: '0', + dateTimeStamp: '0', + userId: '0', + loadIndexTwinLoad: '0', + plyRating: '18', + resourceType: ReferenceDataResourceType.Tyres, + resourceKey: '103', + }; + component.handleAddTyreToRecord(tyre); + expect(mockTechRecordService.techRecord$).toBeTruthy(); + }); + it('should clear global errors', () => { + const tyre: ReferenceDataTyre = { + code: '103', + loadIndexSingleLoad: '0', + tyreSize: '0', + dateTimeStamp: '0', + userId: '0', + loadIndexTwinLoad: '0', + plyRating: '18', + resourceType: ReferenceDataResourceType.Tyres, + resourceKey: '103', + }; + component.handleAddTyreToRecord(tyre); + expect(mockGlobalErrorService.clearErrors).toHaveBeenCalled(); + }); + }); - describe('The cancel function', () => { - it('should clear global errors', () => { - component.cancel(); - expect(mockGlobalErrorService.clearErrors).toHaveBeenCalled(); - }); - }); + describe('The cancel function', () => { + it('should clear global errors', () => { + component.cancel(); + expect(mockGlobalErrorService.clearErrors).toHaveBeenCalled(); + }); + }); - describe('Getters', () => { - it('should get the currentVrm', () => { - const mockVehicleRecord = { - primaryVrm: 'bar', - secondaryVrms: ['foo'], - } as V3TechRecordModel; - component.vehicleTechRecord = mockVehicleRecord; - expect(component.currentVrm).toBe('bar'); - }); - it('should get the paginated fields', () => { - component.searchResults = ['foo', 'bar', 'foobar'] as unknown as ReferenceDataTyre[]; - expect(component.paginatedFields).toEqual(['foo', 'bar', 'foobar']); - }); - it('should get the number of results', () => { - component.searchResults = ['foo', 'bar', 'foobar'] as unknown as ReferenceDataTyre[]; - expect(component.numberOfResults).toEqual(component.searchResults?.length); - }); - }); + describe('Getters', () => { + it('should get the currentVrm', () => { + const mockVehicleRecord = { + primaryVrm: 'bar', + secondaryVrms: ['foo'], + } as V3TechRecordModel; + component.vehicleTechRecord = mockVehicleRecord; + expect(component.currentVrm).toBe('bar'); + }); + it('should get the paginated fields', () => { + component.searchResults = ['foo', 'bar', 'foobar'] as unknown as ReferenceDataTyre[]; + expect(component.paginatedFields).toEqual(['foo', 'bar', 'foobar']); + }); + it('should get the number of results', () => { + component.searchResults = ['foo', 'bar', 'foobar'] as unknown as ReferenceDataTyre[]; + expect(component.numberOfResults).toEqual(component.searchResults?.length); + }); + }); - describe('trackByFn', () => { - it('should return the resourceKey', () => { - expect(component.trackByFn(12, { resourceKey: 'foo' } as unknown as ReferenceDataTyre)).toBe('foo'); - }); - }); + describe('trackByFn', () => { + it('should return the resourceKey', () => { + expect(component.trackByFn(12, { resourceKey: 'foo' } as unknown as ReferenceDataTyre)).toBe('foo'); + }); + }); - describe('OnInit', () => { - it('should patch the form with the search criteria and the search return', () => { - const mockForm = { - controls: { - filter: { - patchValue: jest.fn(), - }, - term: { - patchValue: jest.fn(), - }, - }, - }; - const mockTyreSearchReturn = ['foobar']; - const mockSearchCriteria = { filter: 'foo', term: 'bar' }; - const dfsSpy = jest.spyOn(mockDynamicFormService, 'createForm').mockReturnValue(mockForm); - jest.spyOn(mockReferenceDataService, 'getTyreSearchReturn$').mockReturnValue(of(mockTyreSearchReturn)); - jest.spyOn(mockReferenceDataService, 'getTyreSearchCriteria$').mockReturnValue(of(mockSearchCriteria)); - const filterSpy = jest.spyOn(mockForm.controls.filter, 'patchValue'); - const termSpy = jest.spyOn(mockForm.controls.term, 'patchValue'); - component.ngOnInit(); - expect(dfsSpy).toHaveBeenCalledWith(component.template); - expect(filterSpy).toHaveBeenCalledWith(mockSearchCriteria.filter); - expect(termSpy).toHaveBeenCalledWith(mockSearchCriteria.term); - expect(component.searchResults).toEqual(mockTyreSearchReturn); - }); - it('should navigate if there is no viewable tech record', () => { - const routerSpy = jest.spyOn(router, 'navigate'); - jest.spyOn(mockTechRecordService, 'techRecord$', 'get').mockReturnValue(of(undefined) as unknown as Observable>); - component.ngOnInit(); - expect(routerSpy).toHaveBeenCalledWith(['../..'], { relativeTo: route }); - }); - }); + describe('OnInit', () => { + it('should patch the form with the search criteria and the search return', () => { + const mockForm = { + controls: { + filter: { + patchValue: jest.fn(), + }, + term: { + patchValue: jest.fn(), + }, + }, + }; + const mockTyreSearchReturn = ['foobar']; + const mockSearchCriteria = { filter: 'foo', term: 'bar' }; + const dfsSpy = jest.spyOn(mockDynamicFormService, 'createForm').mockReturnValue(mockForm); + jest.spyOn(mockReferenceDataService, 'getTyreSearchReturn$').mockReturnValue(of(mockTyreSearchReturn)); + jest.spyOn(mockReferenceDataService, 'getTyreSearchCriteria$').mockReturnValue(of(mockSearchCriteria)); + const filterSpy = jest.spyOn(mockForm.controls.filter, 'patchValue'); + const termSpy = jest.spyOn(mockForm.controls.term, 'patchValue'); + component.ngOnInit(); + expect(dfsSpy).toHaveBeenCalledWith(component.template); + expect(filterSpy).toHaveBeenCalledWith(mockSearchCriteria.filter); + expect(termSpy).toHaveBeenCalledWith(mockSearchCriteria.term); + expect(component.searchResults).toEqual(mockTyreSearchReturn); + }); + it('should navigate if there is no viewable tech record', () => { + const routerSpy = jest.spyOn(router, 'navigate'); + jest + .spyOn(mockTechRecordService, 'techRecord$', 'get') + .mockReturnValue(of(undefined) as unknown as Observable>); + component.ngOnInit(); + expect(routerSpy).toHaveBeenCalledWith(['../..'], { relativeTo: route }); + }); + }); }); diff --git a/src/app/features/tech-record/components/tech-record-search-tyres/tech-record-search-tyres.component.ts b/src/app/features/tech-record/components/tech-record-search-tyres/tech-record-search-tyres.component.ts index 72665d8c2b..9f10a98a03 100644 --- a/src/app/features/tech-record/components/tech-record-search-tyres/tech-record-search-tyres.component.ts +++ b/src/app/features/tech-record/components/tech-record-search-tyres/tech-record-search-tyres.component.ts @@ -6,9 +6,7 @@ import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/ import { TechRecordType as TechRecordTypeByVerb } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; import { MultiOptions } from '@forms/models/options.model'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; -import { - CustomFormGroup, FormNode, FormNodeTypes, SearchParams, -} from '@forms/services/dynamic-form.types'; +import { CustomFormGroup, FormNode, FormNodeTypes, SearchParams } from '@forms/services/dynamic-form.types'; import { ReferenceDataResourceType, ReferenceDataTyre, ReferenceDataTyreLoadIndex } from '@models/reference-data.model'; import { Roles } from '@models/roles.enum'; import { V3TechRecordModel } from '@models/vehicle-tech-record.model'; @@ -22,170 +20,175 @@ import { TechnicalRecordServiceState } from '@store/technical-records/reducers/t import { Observable, mergeMap, take } from 'rxjs'; @Component({ - selector: 'app-tyres-search', - templateUrl: './tech-record-search-tyres.component.html', - styleUrls: ['./tech-record-search-tyres.component.scss'], + selector: 'app-tyres-search', + templateUrl: './tech-record-search-tyres.component.html', + styleUrls: ['./tech-record-search-tyres.component.scss'], }) export class TechRecordSearchTyresComponent implements OnInit { - options?: MultiOptions = [ - { label: 'Tyre code', value: 'code' }, - { label: 'Ply rating', value: 'plyrating' }, - { label: 'Single load index', value: 'singleload' }, - { label: 'Double load index', value: 'doubleload' }, - ]; + options?: MultiOptions = [ + { label: 'Tyre code', value: 'code' }, + { label: 'Ply rating', value: 'plyrating' }, + { label: 'Single load index', value: 'singleload' }, + { label: 'Double load index', value: 'doubleload' }, + ]; - constructor( - private cdr: ChangeDetectorRef, - public dfs: DynamicFormService, - public globalErrorService: GlobalErrorService, - private referenceDataService: ReferenceDataService, - private route: ActivatedRoute, - private router: Router, - private technicalRecordService: TechnicalRecordService, - private store: Store, - private actions$: Actions, - ) {} + constructor( + private cdr: ChangeDetectorRef, + public dfs: DynamicFormService, + public globalErrorService: GlobalErrorService, + private referenceDataService: ReferenceDataService, + private route: ActivatedRoute, + private router: Router, + private technicalRecordService: TechnicalRecordService, + private store: Store, + private actions$: Actions + ) {} - public form!: CustomFormGroup; - public searchResults: Array | null = null; - public vehicleTechRecord?: V3TechRecordModel; - public viewableTechRecord?: TechRecordType<'hgv' | 'psv' | 'trl'>; - private params: SearchParams = {}; - private pageStart?: number; - private pageEnd?: number; - public itemsPerPage = 10; + public form!: CustomFormGroup; + public searchResults: Array | null = null; + public vehicleTechRecord?: V3TechRecordModel; + public viewableTechRecord?: TechRecordType<'hgv' | 'psv' | 'trl'>; + private params: SearchParams = {}; + private pageStart?: number; + private pageEnd?: number; + public itemsPerPage = 10; - public template: FormNode = { - name: 'criteria', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'filter', - label: 'Search filter', - value: '', - type: FormNodeTypes.CONTROL, - }, - { - name: 'term', - value: '', - type: FormNodeTypes.CONTROL, - }, - ], - }; + public template: FormNode = { + name: 'criteria', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'filter', + label: 'Search filter', + value: '', + type: FormNodeTypes.CONTROL, + }, + { + name: 'term', + value: '', + type: FormNodeTypes.CONTROL, + }, + ], + }; - ngOnInit() { - this.form = this.dfs.createForm(this.template) as CustomFormGroup; - this.globalErrorService.clearErrors(); - this.route.params.pipe(take(1)).subscribe((p) => { - this.params = p; - }); - this.technicalRecordService.techRecord$.pipe(take(1)).subscribe((data) => { - this.viewableTechRecord = data as TechRecordType<'hgv' | 'psv' | 'trl'>; - }); - this.referenceDataService - .getTyreSearchReturn$() - .pipe(take(1)) - .subscribe((data) => { - this.searchResults = data; - }); - this.referenceDataService - .getTyreSearchCriteria$() - .pipe(take(1)) - .subscribe((v) => { - this.form.controls['filter'].patchValue(v.filter); - this.form.controls['term'].patchValue(v.term); - }); - this.referenceDataService.loadReferenceData(ReferenceDataResourceType.TyreLoadIndex); - if (!this.viewableTechRecord) { - void this.router.navigate(['../..'], { relativeTo: this.route }); - } - this.technicalRecordService.techRecord$.pipe(take(1)).subscribe((data) => { - this.vehicleTechRecord = data; - }); - } + ngOnInit() { + this.form = this.dfs.createForm(this.template) as CustomFormGroup; + this.globalErrorService.clearErrors(); + this.route.params.pipe(take(1)).subscribe((p) => { + this.params = p; + }); + this.technicalRecordService.techRecord$.pipe(take(1)).subscribe((data) => { + this.viewableTechRecord = data as TechRecordType<'hgv' | 'psv' | 'trl'>; + }); + this.referenceDataService + .getTyreSearchReturn$() + .pipe(take(1)) + .subscribe((data) => { + this.searchResults = data; + }); + this.referenceDataService + .getTyreSearchCriteria$() + .pipe(take(1)) + .subscribe((v) => { + this.form.controls['filter'].patchValue(v.filter); + this.form.controls['term'].patchValue(v.term); + }); + this.referenceDataService.loadReferenceData(ReferenceDataResourceType.TyreLoadIndex); + if (!this.viewableTechRecord) { + void this.router.navigate(['../..'], { relativeTo: this.route }); + } + this.technicalRecordService.techRecord$.pipe(take(1)).subscribe((data) => { + this.vehicleTechRecord = data; + }); + } - get roles() { - return Roles; - } - get currentVrm(): string | undefined { - return this.vehicleTechRecord?.techRecord_vehicleType !== 'trl' ? this.vehicleTechRecord?.primaryVrm ?? '' : undefined; - } - get paginatedFields(): ReferenceDataTyre[] { - return this.searchResults?.slice(this.pageStart, this.pageEnd) ?? []; - } - get numberOfResults(): number { - return this.searchResults?.length ?? 0; - } + get roles() { + return Roles; + } + get currentVrm(): string | undefined { + return this.vehicleTechRecord?.techRecord_vehicleType !== 'trl' + ? this.vehicleTechRecord?.primaryVrm ?? '' + : undefined; + } + get paginatedFields(): ReferenceDataTyre[] { + return this.searchResults?.slice(this.pageStart, this.pageEnd) ?? []; + } + get numberOfResults(): number { + return this.searchResults?.length ?? 0; + } - get loadIndex$(): Observable { - return this.referenceDataService.getAll$(ReferenceDataResourceType.TyreLoadIndex) as Observable; - } + get loadIndex$(): Observable { + return this.referenceDataService.getAll$(ReferenceDataResourceType.TyreLoadIndex) as Observable< + ReferenceDataTyreLoadIndex[] + >; + } - handleSearch(filter: string, term: string): void { - this.globalErrorService.clearErrors(); - this.searchResults = []; - const trimmedTerm = term?.trim(); - if (!trimmedTerm || !filter) { - const error = !trimmedTerm ? 'You must provide a search criteria' : 'You must select a valid search filter'; - this.globalErrorService.addError({ error, anchorLink: 'term' }); - return; - } - this.referenceDataService.addSearchInformation(filter, trimmedTerm); - if (filter === 'code') { - this.referenceDataService.loadReferenceDataByKeySearch(ReferenceDataResourceType.Tyres, trimmedTerm); - } else { - this.referenceDataService.loadTyreReferenceDataByKeySearch(filter, trimmedTerm); - } + handleSearch(filter: string, term: string): void { + this.globalErrorService.clearErrors(); + this.searchResults = []; + const trimmedTerm = term?.trim(); + if (!trimmedTerm || !filter) { + const error = !trimmedTerm ? 'You must provide a search criteria' : 'You must select a valid search filter'; + this.globalErrorService.addError({ error, anchorLink: 'term' }); + return; + } + this.referenceDataService.addSearchInformation(filter, trimmedTerm); + if (filter === 'code') { + this.referenceDataService.loadReferenceDataByKeySearch(ReferenceDataResourceType.Tyres, trimmedTerm); + } else { + this.referenceDataService.loadTyreReferenceDataByKeySearch(filter, trimmedTerm); + } - this.actions$ - .pipe( - ofType(fetchReferenceDataByKeySearchSuccess, fetchTyreReferenceDataByKeySearchSuccess), - mergeMap(() => this.store.select(selectSearchReturn(ReferenceDataResourceType.Tyres))), - take(1), - ) - .subscribe((data) => { - void this.router.navigate(['.'], { relativeTo: this.route, queryParams: { 'search-results-page': 1 } }); - this.searchResults = data as ReferenceDataTyre[]; - }); - } + this.actions$ + .pipe( + ofType(fetchReferenceDataByKeySearchSuccess, fetchTyreReferenceDataByKeySearchSuccess), + mergeMap(() => this.store.select(selectSearchReturn(ReferenceDataResourceType.Tyres))), + take(1) + ) + .subscribe((data) => { + void this.router.navigate(['.'], { relativeTo: this.route, queryParams: { 'search-results-page': 1 } }); + this.searchResults = data as ReferenceDataTyre[]; + }); + } - handleAddTyreToRecord(tyre: ReferenceDataTyre): void { - const axleIndex = Number(this.params.axleNumber) - 1; - if (this.viewableTechRecord && !this.viewableTechRecord.techRecord_axles) { - this.viewableTechRecord.techRecord_axles = []; - } - if (this.viewableTechRecord?.techRecord_axles && !this.viewableTechRecord?.techRecord_axles?.[`${axleIndex}`]) { - this.viewableTechRecord.techRecord_axles[`${axleIndex}`] = {}; - } + handleAddTyreToRecord(tyre: ReferenceDataTyre): void { + const axleIndex = Number(this.params.axleNumber) - 1; + if (this.viewableTechRecord && !this.viewableTechRecord.techRecord_axles) { + this.viewableTechRecord.techRecord_axles = []; + } + if (this.viewableTechRecord?.techRecord_axles && !this.viewableTechRecord?.techRecord_axles?.[`${axleIndex}`]) { + this.viewableTechRecord.techRecord_axles[`${axleIndex}`] = {}; + } - if (this.viewableTechRecord?.techRecord_axles) { - this.viewableTechRecord.techRecord_axles[`${axleIndex}`].tyres_tyreCode = Number(tyre.code); - this.viewableTechRecord.techRecord_axles[`${axleIndex}`].tyres_tyreSize = tyre.tyreSize; - this.viewableTechRecord.techRecord_axles[`${axleIndex}`].tyres_plyRating = tyre.plyRating; - if (this.viewableTechRecord.techRecord_axles[`${axleIndex}`].tyres_fitmentCode) { - // eslint-disable-next-line max-len - this.viewableTechRecord.techRecord_axles[`${axleIndex}`].tyres_dataTrAxles = this.viewableTechRecord.techRecord_axles[`${axleIndex}`].tyres_fitmentCode === 'single' - ? parseInt(tyre.loadIndexSingleLoad ?? '0', 10) - : parseInt(tyre.loadIndexTwinLoad ?? '0', 10); - } - this.technicalRecordService.updateEditingTechRecord(this.viewableTechRecord as TechRecordTypeByVerb<'put'>); - void this.router.navigate(['../..'], { relativeTo: this.route }); - } - } + if (this.viewableTechRecord?.techRecord_axles) { + this.viewableTechRecord.techRecord_axles[`${axleIndex}`].tyres_tyreCode = Number(tyre.code); + this.viewableTechRecord.techRecord_axles[`${axleIndex}`].tyres_tyreSize = tyre.tyreSize; + this.viewableTechRecord.techRecord_axles[`${axleIndex}`].tyres_plyRating = tyre.plyRating; + if (this.viewableTechRecord.techRecord_axles[`${axleIndex}`].tyres_fitmentCode) { + // eslint-disable-next-line max-len + this.viewableTechRecord.techRecord_axles[`${axleIndex}`].tyres_dataTrAxles = + this.viewableTechRecord.techRecord_axles[`${axleIndex}`].tyres_fitmentCode === 'single' + ? Number.parseInt(tyre.loadIndexSingleLoad ?? '0', 10) + : Number.parseInt(tyre.loadIndexTwinLoad ?? '0', 10); + } + this.technicalRecordService.updateEditingTechRecord(this.viewableTechRecord as TechRecordTypeByVerb<'put'>); + void this.router.navigate(['../..'], { relativeTo: this.route }); + } + } - handlePaginationChange({ start, end }: { start: number; end: number }) { - this.pageStart = start; - this.pageEnd = end; - this.cdr.detectChanges(); - } - getErrorByName(errors: GlobalError[], name: string): GlobalError | undefined { - return errors.find((error) => error.anchorLink === name); - } - trackByFn(i: number, r: ReferenceDataTyre) { - return r.resourceKey; - } - cancel() { - this.globalErrorService.clearErrors(); - void this.router.navigate(['../..'], { relativeTo: this.route }); - } + handlePaginationChange({ start, end }: { start: number; end: number }) { + this.pageStart = start; + this.pageEnd = end; + this.cdr.detectChanges(); + } + getErrorByName(errors: GlobalError[], name: string): GlobalError | undefined { + return errors.find((error) => error.anchorLink === name); + } + trackByFn(i: number, r: ReferenceDataTyre) { + return r.resourceKey; + } + cancel() { + this.globalErrorService.clearErrors(); + void this.router.navigate(['../..'], { relativeTo: this.route }); + } } diff --git a/src/app/features/tech-record/components/tech-record-summary-changes/tech-record-summary-changes.component.spec.ts b/src/app/features/tech-record/components/tech-record-summary-changes/tech-record-summary-changes.component.spec.ts index 4a6486e76b..59b57aef14 100644 --- a/src/app/features/tech-record/components/tech-record-summary-changes/tech-record-summary-changes.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-summary-changes/tech-record-summary-changes.component.spec.ts @@ -15,7 +15,11 @@ import { UserService } from '@services/user-service/user-service'; import { SharedModule } from '@shared/shared.module'; import { initialAppState } from '@store/index'; import { - amendVrmSuccess, editingTechRecord, selectTechRecordChanges, selectTechRecordDeletions, techRecord, + amendVrmSuccess, + editingTechRecord, + selectTechRecordChanges, + selectTechRecordDeletions, + techRecord, } from '@store/technical-records'; import { ReplaySubject, of } from 'rxjs'; import { TechRecordSummaryChangesComponent } from './tech-record-summary-changes.component'; @@ -23,204 +27,204 @@ import { TechRecordSummaryChangesComponent } from './tech-record-summary-changes let actions$: ReplaySubject; let store: MockStore; describe('TechRecordSummaryChangesComponent', () => { - let component: TechRecordSummaryChangesComponent; - let fixture: ComponentFixture; - let router: Router; - - beforeEach(async () => { - actions$ = new ReplaySubject(); - await TestBed.configureTestingModule({ - declarations: [TechRecordSummaryChangesComponent], - imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule, SharedModule], - providers: [ - provideMockActions(() => actions$), - provideMockStore({ initialState: initialAppState }), - { - provide: UserService, - useValue: { - name$: of('tester'), - }, - }, - { - provide: RouterService, - useValue: { - getRouteNestedParam$(param: string) { - if (param === 'systemNumber') return of('123456'); - if (param === 'createdTimestamp') return of('123123123'); - return of(''); - }, - }, - }, - ], - }).compileComponents(); - router = TestBed.inject(Router); - fixture = TestBed.createComponent(TechRecordSummaryChangesComponent); - store = TestBed.inject(MockStore); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('navigateUponSuccess', () => { - it('should handle state management', () => { - const spy = jest.spyOn(component.actions$, 'pipe'); - component.navigateUponSuccess(); - expect(spy).toHaveBeenCalled(); - }); - }); - - describe('ngOnInit', () => { - it('should call navigateOnSuccess and initSubscriptions', () => { - const navigateOnSuccessSpy = jest.spyOn(component, 'navigateUponSuccess'); - const initSubscriptionsSpy = jest.spyOn(component, 'initSubscriptions'); - component.ngOnInit(); - expect(navigateOnSuccessSpy).toHaveBeenCalled(); - expect(initSubscriptionsSpy).toHaveBeenCalled(); - }); - it('should navigate when updateRecordSuccess dispatched', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - component.ngOnInit(); - - actions$.next( - amendVrmSuccess({ - vehicleTechRecord: { - createdTimestamp: 'now', - vin: 'testVin', - systemNumber: 'testNumber', - } as TechRecordType<'get'>, - }), - ); - - expect(navigateSpy).toHaveBeenCalled(); - }); - }); - - describe('initSubscriptions', () => { - let spy: unknown; - - beforeEach(() => { - spy = jest.spyOn(store, 'select'); - component.ngOnInit(); - }); - it('should grab techRecord from the store', () => { - expect(spy).toHaveBeenCalledWith(techRecord); - }); - it('should grab editingTechRecord from the store', () => { - expect(spy).toHaveBeenCalledWith(editingTechRecord); - }); - it('should grab selectTechRecordChanges from the store', () => { - expect(spy).toHaveBeenCalledWith(selectTechRecordChanges); - }); - it('should grab selectTechRecordDeletions from the store', () => { - expect(spy).toHaveBeenCalledWith(selectTechRecordDeletions); - }); - }); - - describe('ngOnDestroy', () => { - it('should call the destroy.next and destroy.complete', () => { - const nextSpy = jest.spyOn(component.destroy$, 'next'); - const completeSpy = jest.spyOn(component.destroy$, 'complete'); - component.ngOnDestroy(); - expect(nextSpy).toHaveBeenCalled(); - expect(completeSpy).toHaveBeenCalled(); - }); - }); - - describe('submit', () => { - it('should dispatch clearADRDetailsBeforeUpdate', () => { - const dispatch = jest.spyOn(store, 'dispatch'); - component.submit(); - expect(dispatch).toHaveBeenCalled(); - }); - - it('should dispatch updateTechRecords', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.submit(); - expect(dispatchSpy).toHaveBeenCalled(); - expect(dispatchSpy).toHaveBeenCalledWith({ - systemNumber: '123456', - createdTimestamp: '123123123', - type: '[Technical Record Service] updateTechRecords', - }); - }); - }); - - describe('cancel', () => { - it('should call globalErrorService.clearErrors and then navigate', () => { - const clearErrorsSpy = jest.spyOn(component.globalErrorService, 'clearErrors'); - const navigateSpy = jest.spyOn(component.router, 'navigate'); - component.cancel(); - expect(clearErrorsSpy).toHaveBeenCalled(); - expect(navigateSpy).toHaveBeenCalled(); - }); - }); - - describe('getTechRecordChangesKeys', () => { - it('should return a list of all of the populated keys', () => { - component.techRecordChanges = { techRecord_grossEecWeight: 1, techRecord_grossDesignWeight: 1 }; - const keys = component.getTechRecordChangesKeys(); - expect(keys).toEqual(['techRecord_grossEecWeight', 'techRecord_grossDesignWeight']); - }); - }); - - describe('getSectionsWhitelist', () => { - it('should return an empty array if vehicleType is null', () => { - component.techRecordEdited = undefined; - const value = component.getSectionsWhitelist(); - expect(value).toEqual([]); - }); - it('should return an empty array if techRecordChanges is null', () => { - component.techRecord = undefined; - const value = component.getSectionsWhitelist(); - expect(value).toEqual([]); - }); - it('should call haveAxlesChanged if vehicleType and techRecordChanges are defined', () => { - const localTechRecordEdited = getEmptyTechRecord(); - component.techRecordEdited = localTechRecordEdited as TechRecordType<'put'>; - component.techRecordChanges = { techRecord_grossEecWeight: 1, techRecord_grossDesignWeight: 1 }; - const value = component.getSectionsWhitelist(); - expect(value).toEqual(['weightsSection']); - }); - }); - - describe('toVisibleFormNode', () => { - it('updates the viewType property from hidden to string', () => { - const children = TechRecordReasonForCreationSection.children as FormNode[]; - const formNode = component.toVisibleFormNode(children[0]); - expect(formNode.viewType).toEqual(FormNodeViewTypes.STRING); - }); - }); + let component: TechRecordSummaryChangesComponent; + let fixture: ComponentFixture; + let router: Router; + + beforeEach(async () => { + actions$ = new ReplaySubject(); + await TestBed.configureTestingModule({ + declarations: [TechRecordSummaryChangesComponent], + imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule, SharedModule], + providers: [ + provideMockActions(() => actions$), + provideMockStore({ initialState: initialAppState }), + { + provide: UserService, + useValue: { + name$: of('tester'), + }, + }, + { + provide: RouterService, + useValue: { + getRouteNestedParam$(param: string) { + if (param === 'systemNumber') return of('123456'); + if (param === 'createdTimestamp') return of('123123123'); + return of(''); + }, + }, + }, + ], + }).compileComponents(); + router = TestBed.inject(Router); + fixture = TestBed.createComponent(TechRecordSummaryChangesComponent); + store = TestBed.inject(MockStore); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('navigateUponSuccess', () => { + it('should handle state management', () => { + const spy = jest.spyOn(component.actions$, 'pipe'); + component.navigateUponSuccess(); + expect(spy).toHaveBeenCalled(); + }); + }); + + describe('ngOnInit', () => { + it('should call navigateOnSuccess and initSubscriptions', () => { + const navigateOnSuccessSpy = jest.spyOn(component, 'navigateUponSuccess'); + const initSubscriptionsSpy = jest.spyOn(component, 'initSubscriptions'); + component.ngOnInit(); + expect(navigateOnSuccessSpy).toHaveBeenCalled(); + expect(initSubscriptionsSpy).toHaveBeenCalled(); + }); + it('should navigate when updateRecordSuccess dispatched', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + component.ngOnInit(); + + actions$.next( + amendVrmSuccess({ + vehicleTechRecord: { + createdTimestamp: 'now', + vin: 'testVin', + systemNumber: 'testNumber', + } as TechRecordType<'get'>, + }) + ); + + expect(navigateSpy).toHaveBeenCalled(); + }); + }); + + describe('initSubscriptions', () => { + let spy: unknown; + + beforeEach(() => { + spy = jest.spyOn(store, 'select'); + component.ngOnInit(); + }); + it('should grab techRecord from the store', () => { + expect(spy).toHaveBeenCalledWith(techRecord); + }); + it('should grab editingTechRecord from the store', () => { + expect(spy).toHaveBeenCalledWith(editingTechRecord); + }); + it('should grab selectTechRecordChanges from the store', () => { + expect(spy).toHaveBeenCalledWith(selectTechRecordChanges); + }); + it('should grab selectTechRecordDeletions from the store', () => { + expect(spy).toHaveBeenCalledWith(selectTechRecordDeletions); + }); + }); + + describe('ngOnDestroy', () => { + it('should call the destroy.next and destroy.complete', () => { + const nextSpy = jest.spyOn(component.destroy$, 'next'); + const completeSpy = jest.spyOn(component.destroy$, 'complete'); + component.ngOnDestroy(); + expect(nextSpy).toHaveBeenCalled(); + expect(completeSpy).toHaveBeenCalled(); + }); + }); + + describe('submit', () => { + it('should dispatch clearADRDetailsBeforeUpdate', () => { + const dispatch = jest.spyOn(store, 'dispatch'); + component.submit(); + expect(dispatch).toHaveBeenCalled(); + }); + + it('should dispatch updateTechRecords', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.submit(); + expect(dispatchSpy).toHaveBeenCalled(); + expect(dispatchSpy).toHaveBeenCalledWith({ + systemNumber: '123456', + createdTimestamp: '123123123', + type: '[Technical Record Service] updateTechRecords', + }); + }); + }); + + describe('cancel', () => { + it('should call globalErrorService.clearErrors and then navigate', () => { + const clearErrorsSpy = jest.spyOn(component.globalErrorService, 'clearErrors'); + const navigateSpy = jest.spyOn(component.router, 'navigate'); + component.cancel(); + expect(clearErrorsSpy).toHaveBeenCalled(); + expect(navigateSpy).toHaveBeenCalled(); + }); + }); + + describe('getTechRecordChangesKeys', () => { + it('should return a list of all of the populated keys', () => { + component.techRecordChanges = { techRecord_grossEecWeight: 1, techRecord_grossDesignWeight: 1 }; + const keys = component.getTechRecordChangesKeys(); + expect(keys).toEqual(['techRecord_grossEecWeight', 'techRecord_grossDesignWeight']); + }); + }); + + describe('getSectionsWhitelist', () => { + it('should return an empty array if vehicleType is null', () => { + component.techRecordEdited = undefined; + const value = component.getSectionsWhitelist(); + expect(value).toEqual([]); + }); + it('should return an empty array if techRecordChanges is null', () => { + component.techRecord = undefined; + const value = component.getSectionsWhitelist(); + expect(value).toEqual([]); + }); + it('should call haveAxlesChanged if vehicleType and techRecordChanges are defined', () => { + const localTechRecordEdited = getEmptyTechRecord(); + component.techRecordEdited = localTechRecordEdited as TechRecordType<'put'>; + component.techRecordChanges = { techRecord_grossEecWeight: 1, techRecord_grossDesignWeight: 1 }; + const value = component.getSectionsWhitelist(); + expect(value).toEqual(['weightsSection']); + }); + }); + + describe('toVisibleFormNode', () => { + it('updates the viewType property from hidden to string', () => { + const children = TechRecordReasonForCreationSection.children as FormNode[]; + const formNode = component.toVisibleFormNode(children[0]); + expect(formNode.viewType).toEqual(FormNodeViewTypes.STRING); + }); + }); }); function getEmptyTechRecord(): V3TechRecordModel { - return { - techRecord_createdAt: '', - techRecord_createdById: null, - techRecord_createdByName: null, - techRecord_euVehicleCategory: null, - techRecord_lastUpdatedAt: null, - techRecord_lastUpdatedById: null, - techRecord_lastUpdatedByName: null, - techRecord_manufactureYear: null, - techRecord_noOfAxles: 2, - techRecord_notes: undefined, - techRecord_applicantDetails_address1: null, - techRecord_applicantDetails_address2: null, - techRecord_applicantDetails_address3: null, - techRecord_applicantDetails_emailAddress: null, - techRecord_applicantDetails_name: null, - techRecord_applicantDetails_postCode: null, - techRecord_applicantDetails_postTown: null, - techRecord_applicantDetails_telephoneNumber: null, - techRecord_reasonForCreation: '', - techRecord_regnDate: null, - techRecord_statusCode: '', - techRecord_vehicleConfiguration: 'other', - techRecord_vehicleSubclass: undefined, - techRecord_vehicleType: 'hgv', - } as unknown as V3TechRecordModel; + return { + techRecord_createdAt: '', + techRecord_createdById: null, + techRecord_createdByName: null, + techRecord_euVehicleCategory: null, + techRecord_lastUpdatedAt: null, + techRecord_lastUpdatedById: null, + techRecord_lastUpdatedByName: null, + techRecord_manufactureYear: null, + techRecord_noOfAxles: 2, + techRecord_notes: undefined, + techRecord_applicantDetails_address1: null, + techRecord_applicantDetails_address2: null, + techRecord_applicantDetails_address3: null, + techRecord_applicantDetails_emailAddress: null, + techRecord_applicantDetails_name: null, + techRecord_applicantDetails_postCode: null, + techRecord_applicantDetails_postTown: null, + techRecord_applicantDetails_telephoneNumber: null, + techRecord_reasonForCreation: '', + techRecord_regnDate: null, + techRecord_statusCode: '', + techRecord_vehicleConfiguration: 'other', + techRecord_vehicleSubclass: undefined, + techRecord_vehicleType: 'hgv', + } as unknown as V3TechRecordModel; } diff --git a/src/app/features/tech-record/components/tech-record-summary-changes/tech-record-summary-changes.component.ts b/src/app/features/tech-record/components/tech-record-summary-changes/tech-record-summary-changes.component.ts index 43393017e3..d8e2896158 100644 --- a/src/app/features/tech-record/components/tech-record-summary-changes/tech-record-summary-changes.component.ts +++ b/src/app/features/tech-record/components/tech-record-summary-changes/tech-record-summary-changes.component.ts @@ -1,15 +1,13 @@ -import { - ChangeDetectionStrategy, Component, OnDestroy, OnInit, -} from '@angular/core'; +import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; import { - TechRecordGETCar, - TechRecordGETHGV, - TechRecordGETLGV, - TechRecordGETPSV, - TechRecordGETTRL, + TechRecordGETCar, + TechRecordGETHGV, + TechRecordGETLGV, + TechRecordGETPSV, + TechRecordGETTRL, } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb-vehicle-type'; import { FormNode, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; import { VehicleSummary } from '@forms/templates/tech-records/vehicle-summary.template'; @@ -22,215 +20,227 @@ import { TechnicalRecordService } from '@services/technical-record/technical-rec import { UserService } from '@services/user-service/user-service'; import { State } from '@store/index'; import { - clearADRDetailsBeforeUpdate, - clearAllSectionStates, - clearScrollPosition, - editingTechRecord, - selectTechRecordChanges, - selectTechRecordDeletions, - techRecord, updateADRAdditionalExaminerNotes, - updateTechRecord, - updateTechRecordSuccess, + clearADRDetailsBeforeUpdate, + clearAllSectionStates, + clearScrollPosition, + editingTechRecord, + selectTechRecordChanges, + selectTechRecordDeletions, + techRecord, + updateADRAdditionalExaminerNotes, + updateTechRecord, + updateTechRecordSuccess, } from '@store/technical-records'; -import { - Subject, combineLatest, map, take, takeUntil, -} from 'rxjs'; +import { Subject, combineLatest, map, take, takeUntil } from 'rxjs'; @Component({ - selector: 'app-tech-record-summary-changes', - templateUrl: './tech-record-summary-changes.component.html', - styleUrls: ['./tech-record-summary-changes.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-tech-record-summary-changes', + templateUrl: './tech-record-summary-changes.component.html', + styleUrls: ['./tech-record-summary-changes.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class TechRecordSummaryChangesComponent implements OnInit, OnDestroy { - destroy$ = new Subject(); - - techRecord?: TechRecordType<'get'>; - techRecordEdited?: TechRecordType<'put'>; - techRecordChanges?: Partial>; - techRecordDeletions?: Partial>; - techRecordChangesKeys: string[] = []; - - sectionsWhitelist: string[] = []; - username = ''; - - constructor( - public store$: Store, - public technicalRecordService: TechnicalRecordService, - public router: Router, - public globalErrorService: GlobalErrorService, - public route: ActivatedRoute, - public routerService: RouterService, - public actions$: Actions, - public userService$: UserService, - ) { } - - ngOnInit(): void { - this.navigateUponSuccess(); - this.initSubscriptions(); - } - - navigateUponSuccess(): void { - this.actions$.pipe(ofType(updateTechRecordSuccess), takeUntil(this.destroy$)).subscribe((vehicleTechRecord) => { - this.store$.dispatch(clearAllSectionStates()); - this.store$.dispatch(clearScrollPosition()); - void this.router.navigate([ - `/tech-records/${vehicleTechRecord.vehicleTechRecord.systemNumber}/${vehicleTechRecord.vehicleTechRecord.createdTimestamp}`, - ]); - }); - } - - initSubscriptions(): void { - this.userService$.name$.pipe(takeUntil(this.destroy$)).subscribe((name) => { - this.username = name; - }); - this.store$ - .select(techRecord) - .pipe(take(1), takeUntil(this.destroy$)) - .subscribe((data) => { - if (!data) this.cancel(); - this.techRecord = data; - }); - - this.store$ - .select(editingTechRecord) - .pipe(take(1), takeUntil(this.destroy$)) - .subscribe((data) => { - if (!data) this.cancel(); - this.techRecordEdited = data; - }); - - this.store$ - .select(selectTechRecordChanges) - .pipe(take(1), takeUntil(this.destroy$)) - .subscribe((changes) => { - this.techRecordChanges = changes; - if (this.vehicleType === VehicleTypes.PSV || this.vehicleType === VehicleTypes.HGV) { - delete (this.techRecordChanges as Partial).techRecord_numberOfWheelsDriven; - } if ( - (this.vehicleType === VehicleTypes.CAR || this.vehicleType === VehicleTypes.LGV) - && (changes as TechRecordGETCar | TechRecordGETLGV).techRecord_vehicleSubclass) { - (this.techRecordChanges as TechRecordGETCar | TechRecordGETLGV) - .techRecord_vehicleSubclass = (this.techRecordEdited as TechRecordGETCar | TechRecordGETLGV).techRecord_vehicleSubclass; - } - this.techRecordChangesKeys = this.getTechRecordChangesKeys(); - this.sectionsWhitelist = this.getSectionsWhitelist(); - }); - - this.store$ - .select(selectTechRecordDeletions) - .pipe(take(1), takeUntil(this.destroy$)) - .subscribe((deletions) => { - this.techRecordDeletions = deletions; - }); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - get vehicleType() { - return this.techRecordEdited ? this.technicalRecordService.getVehicleTypeWithSmallTrl(this.techRecordEdited) : undefined; - } - - get vehicleSummary(): FormNode { - return VehicleSummary; - } - - get deletedAxles(): Axles { - if (this.techRecordEdited?.techRecord_vehicleType === 'hgv' && this.techRecordDeletions) { - return Object.values((this.techRecordDeletions as Partial).techRecord_axles ?? {}); - } - - if (this.techRecordEdited?.techRecord_vehicleType === 'trl' && this.techRecordDeletions) { - return Object.values((this.techRecordDeletions as Partial).techRecord_axles ?? {}); - } - - if (this.techRecordEdited?.techRecord_vehicleType === 'psv' && this.techRecordDeletions) { - return Object.values((this.techRecordDeletions as Partial).techRecord_axles ?? {}); - } - - return []; - } - - get sectionTemplatesState$() { - return this.technicalRecordService.sectionStates$; - } - - isSectionExpanded$(sectionName: string | number) { - return this.sectionTemplatesState$?.pipe(map((sections) => sections?.includes(sectionName))); - } - - submit() { - combineLatest([this.routerService.getRouteNestedParam$('systemNumber'), this.routerService.getRouteNestedParam$('createdTimestamp')]) - .pipe(take(1), takeUntil(this.destroy$)) - .subscribe(([systemNumber, createdTimestamp]) => { - if (systemNumber && createdTimestamp) { - this.store$.dispatch(updateADRAdditionalExaminerNotes({ username: this.username })); - this.store$.dispatch(clearADRDetailsBeforeUpdate()); - this.store$.dispatch(updateTechRecord({ systemNumber, createdTimestamp })); - } - }); - } - - cancel() { - this.globalErrorService.clearErrors(); - void this.router.navigate(['..'], { relativeTo: this.route }); - } - - getTechRecordChangesKeys(): string[] { - const entries = Object.entries(this.techRecordChanges ?? {}); - const filter = entries.filter(([, value]) => this.isNotEmpty(value)); - const changeMap = filter.map(([key]) => key); - return changeMap; - } - - getSectionsWhitelist() { - const whitelist: string[] = []; - if (this.vehicleType == null) return whitelist; - if (this.techRecordChanges == null) return whitelist; - if (this.technicalRecordService.haveAxlesChanged(this.vehicleType, this.techRecordChanges)) { - whitelist.push('weightsSection'); - } - - return whitelist; - } - - get changesForWeights() { - if (this.techRecordEdited == null) return undefined; - - return ['hgv', 'trl', 'psv'].includes(this.techRecordEdited.techRecord_vehicleType) - ? (this.techRecordChanges as Partial) - : undefined; - } - - get vehicleTemplates() { - return vehicleTemplateMap - .get(this.techRecordEdited?.techRecord_vehicleType as VehicleTypes) - ?.filter((template) => template.name !== 'technicalRecordSummary'); - } - - get customVehicleTemplate() { - return this.vehicleTemplates - ?.map((vehicleTemplate) => ({ - ...this.toVisibleFormNode(vehicleTemplate), - children: vehicleTemplate.children - ?.filter((child) => { - return this.techRecordChangesKeys.includes(child.name); - }) - .map((child) => this.toVisibleFormNode(child)), - })) - .filter((section) => Boolean(section && section.children && section.children.length > 0) || this.sectionsWhitelist.includes(section.name)); - } - - toVisibleFormNode(node: FormNode): FormNode { - return { ...node, viewType: node.viewType === FormNodeViewTypes.HIDDEN ? FormNodeViewTypes.STRING : node.viewType }; - } - - isNotEmpty(value: unknown): boolean { - if (value === '' || value === undefined) return false; - if (typeof value === 'object' && value !== null) return Object.values(value).length > 0; - return true; - } + destroy$ = new Subject(); + + techRecord?: TechRecordType<'get'>; + techRecordEdited?: TechRecordType<'put'>; + techRecordChanges?: Partial>; + techRecordDeletions?: Partial>; + techRecordChangesKeys: string[] = []; + + sectionsWhitelist: string[] = []; + username = ''; + + constructor( + public store$: Store, + public technicalRecordService: TechnicalRecordService, + public router: Router, + public globalErrorService: GlobalErrorService, + public route: ActivatedRoute, + public routerService: RouterService, + public actions$: Actions, + public userService$: UserService + ) {} + + ngOnInit(): void { + this.navigateUponSuccess(); + this.initSubscriptions(); + } + + navigateUponSuccess(): void { + this.actions$.pipe(ofType(updateTechRecordSuccess), takeUntil(this.destroy$)).subscribe((vehicleTechRecord) => { + this.store$.dispatch(clearAllSectionStates()); + this.store$.dispatch(clearScrollPosition()); + void this.router.navigate([ + `/tech-records/${vehicleTechRecord.vehicleTechRecord.systemNumber}/${vehicleTechRecord.vehicleTechRecord.createdTimestamp}`, + ]); + }); + } + + initSubscriptions(): void { + this.userService$.name$.pipe(takeUntil(this.destroy$)).subscribe((name) => { + this.username = name; + }); + this.store$ + .select(techRecord) + .pipe(take(1), takeUntil(this.destroy$)) + .subscribe((data) => { + if (!data) this.cancel(); + this.techRecord = data; + }); + + this.store$ + .select(editingTechRecord) + .pipe(take(1), takeUntil(this.destroy$)) + .subscribe((data) => { + if (!data) this.cancel(); + this.techRecordEdited = data; + }); + + this.store$ + .select(selectTechRecordChanges) + .pipe(take(1), takeUntil(this.destroy$)) + .subscribe((changes) => { + this.techRecordChanges = changes; + if (this.vehicleType === VehicleTypes.PSV || this.vehicleType === VehicleTypes.HGV) { + delete (this.techRecordChanges as Partial) + .techRecord_numberOfWheelsDriven; + } + if ( + (this.vehicleType === VehicleTypes.CAR || this.vehicleType === VehicleTypes.LGV) && + (changes as TechRecordGETCar | TechRecordGETLGV).techRecord_vehicleSubclass + ) { + (this.techRecordChanges as TechRecordGETCar | TechRecordGETLGV).techRecord_vehicleSubclass = ( + this.techRecordEdited as TechRecordGETCar | TechRecordGETLGV + ).techRecord_vehicleSubclass; + } + this.techRecordChangesKeys = this.getTechRecordChangesKeys(); + this.sectionsWhitelist = this.getSectionsWhitelist(); + }); + + this.store$ + .select(selectTechRecordDeletions) + .pipe(take(1), takeUntil(this.destroy$)) + .subscribe((deletions) => { + this.techRecordDeletions = deletions; + }); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + get vehicleType() { + return this.techRecordEdited + ? this.technicalRecordService.getVehicleTypeWithSmallTrl(this.techRecordEdited) + : undefined; + } + + get vehicleSummary(): FormNode { + return VehicleSummary; + } + + get deletedAxles(): Axles { + if (this.techRecordEdited?.techRecord_vehicleType === 'hgv' && this.techRecordDeletions) { + return Object.values((this.techRecordDeletions as Partial).techRecord_axles ?? {}); + } + + if (this.techRecordEdited?.techRecord_vehicleType === 'trl' && this.techRecordDeletions) { + return Object.values((this.techRecordDeletions as Partial).techRecord_axles ?? {}); + } + + if (this.techRecordEdited?.techRecord_vehicleType === 'psv' && this.techRecordDeletions) { + return Object.values((this.techRecordDeletions as Partial).techRecord_axles ?? {}); + } + + return []; + } + + get sectionTemplatesState$() { + return this.technicalRecordService.sectionStates$; + } + + isSectionExpanded$(sectionName: string | number) { + return this.sectionTemplatesState$?.pipe(map((sections) => sections?.includes(sectionName))); + } + + submit() { + combineLatest([ + this.routerService.getRouteNestedParam$('systemNumber'), + this.routerService.getRouteNestedParam$('createdTimestamp'), + ]) + .pipe(take(1), takeUntil(this.destroy$)) + .subscribe(([systemNumber, createdTimestamp]) => { + if (systemNumber && createdTimestamp) { + this.store$.dispatch(updateADRAdditionalExaminerNotes({ username: this.username })); + this.store$.dispatch(clearADRDetailsBeforeUpdate()); + this.store$.dispatch(updateTechRecord({ systemNumber, createdTimestamp })); + } + }); + } + + cancel() { + this.globalErrorService.clearErrors(); + void this.router.navigate(['..'], { relativeTo: this.route }); + } + + getTechRecordChangesKeys(): string[] { + const entries = Object.entries(this.techRecordChanges ?? {}); + const filter = entries.filter(([, value]) => this.isNotEmpty(value)); + const changeMap = filter.map(([key]) => key); + return changeMap; + } + + getSectionsWhitelist() { + const whitelist: string[] = []; + if (this.vehicleType == null) return whitelist; + if (this.techRecordChanges == null) return whitelist; + if (this.technicalRecordService.haveAxlesChanged(this.vehicleType, this.techRecordChanges)) { + whitelist.push('weightsSection'); + } + + return whitelist; + } + + get changesForWeights() { + if (this.techRecordEdited == null) return undefined; + + return ['hgv', 'trl', 'psv'].includes(this.techRecordEdited.techRecord_vehicleType) + ? (this.techRecordChanges as Partial) + : undefined; + } + + get vehicleTemplates() { + return vehicleTemplateMap + .get(this.techRecordEdited?.techRecord_vehicleType as VehicleTypes) + ?.filter((template) => template.name !== 'technicalRecordSummary'); + } + + get customVehicleTemplate() { + return this.vehicleTemplates + ?.map((vehicleTemplate) => ({ + ...this.toVisibleFormNode(vehicleTemplate), + children: vehicleTemplate.children + ?.filter((child) => { + return this.techRecordChangesKeys.includes(child.name); + }) + .map((child) => this.toVisibleFormNode(child)), + })) + .filter( + (section) => + Boolean(section && section.children && section.children.length > 0) || + this.sectionsWhitelist.includes(section.name) + ); + } + + toVisibleFormNode(node: FormNode): FormNode { + return { ...node, viewType: node.viewType === FormNodeViewTypes.HIDDEN ? FormNodeViewTypes.STRING : node.viewType }; + } + + isNotEmpty(value: unknown): boolean { + if (value === '' || value === undefined) return false; + if (typeof value === 'object' && value !== null) return Object.values(value).length > 0; + return true; + } } diff --git a/src/app/features/tech-record/components/tech-record-summary/tech-record-summary.component.spec.ts b/src/app/features/tech-record/components/tech-record-summary/tech-record-summary.component.spec.ts index 0b22a7c87b..247eecb5c4 100644 --- a/src/app/features/tech-record/components/tech-record-summary/tech-record-summary.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-summary/tech-record-summary.component.spec.ts @@ -13,219 +13,222 @@ import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/ import { Roles } from '@models/roles.enum'; import { V3TechRecordModel, VehicleTypes } from '@models/vehicle-tech-record.model'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; +import { FeatureToggleService } from '@services/feature-toggle-service/feature-toggle-service'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { UserService } from '@services/user-service/user-service'; import { SharedModule } from '@shared/shared.module'; import { State, initialAppState } from '@store/index'; import { updateEditingTechRecord } from '@store/technical-records'; import { of } from 'rxjs'; -import { FeatureToggleService } from '@services/feature-toggle-service/feature-toggle-service'; import { TechRecordSummaryComponent } from './tech-record-summary.component'; global.scrollTo = jest.fn(); describe('TechRecordSummaryComponent', () => { - let component: TechRecordSummaryComponent; - let fixture: ComponentFixture; - let store: MockStore; - let techRecordService: TechnicalRecordService; - let featureToggleService: FeatureToggleService; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TechRecordSummaryComponent], - imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule, SharedModule], - providers: [ - MultiOptionsService, - provideMockStore({ initialState: initialAppState }), - { - provide: UserService, - useValue: { - roles$: of([Roles.TechRecordAmend]), - }, - }, - TechnicalRecordService, - FeatureToggleService, - ], - }) - .overrideComponent(LettersComponent, { - set: { - selector: 'app-letters', - template: '

Mock Letters Component

', - }, - }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(TechRecordSummaryComponent); - store = TestBed.inject(MockStore); - techRecordService = TestBed.inject(TechnicalRecordService); - featureToggleService = TestBed.inject(FeatureToggleService); - component = fixture.componentInstance; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - function checkHeadingAndForm(): void { - const heading = fixture.debugElement.query(By.css('.govuk-heading-s')); - expect(heading).toBeFalsy(); - - const form = fixture.nativeElement.querySelector('app-dynamic-form-group'); - expect(form).toBeTruthy(); - } - - describe('TechRecordSummaryComponent View', () => { - it('should show PSV record found', () => { - component.isEditing = false; - jest - .spyOn(techRecordService, 'techRecord$', 'get') - .mockReturnValue( - of({ - systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin', techRecord_vehicleType: VehicleTypes.PSV, - } as V3TechRecordModel), - ); - fixture.detectChanges(); - checkHeadingAndForm(); - expect(component.vehicleType).toEqual(VehicleTypes.PSV); - }); - - it('should show PSV record found without dimensions', () => { - component.isEditing = false; - jest - .spyOn(techRecordService, 'techRecord$', 'get') - .mockReturnValue( - of({ - systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin', techRecord_vehicleType: VehicleTypes.PSV, - } as V3TechRecordModel), - ); - fixture.detectChanges(); - - checkHeadingAndForm(); - expect((component.techRecordCalculated as TechRecordTypeByVehicle<'psv'>).techRecord_dimensions_height).toBeUndefined(); - }); - - it('should show HGV record found', () => { - component.isEditing = false; - jest - .spyOn(techRecordService, 'techRecord$', 'get') - .mockReturnValue( - of({ - systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin', techRecord_vehicleType: VehicleTypes.HGV, - } as V3TechRecordModel), - ); - fixture.detectChanges(); - - checkHeadingAndForm(); - expect(component.vehicleType).toEqual(VehicleTypes.HGV); - }); - - it('should show HGV record found without dimensions', () => { - component.isEditing = false; - jest - .spyOn(techRecordService, 'techRecord$', 'get') - .mockReturnValue( - of({ - systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin', techRecord_vehicleType: VehicleTypes.HGV, - } as V3TechRecordModel), - ); - fixture.detectChanges(); - - checkHeadingAndForm(); - expect(component.vehicleType).toEqual(VehicleTypes.HGV); - }); - - it('should show TRL record found', () => { - component.isEditing = false; - jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue( - of({ - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_vehicleType: VehicleTypes.TRL, - techRecord_euVehicleCategory: 'o2', - } as V3TechRecordModel), - ); - fixture.detectChanges(); - - checkHeadingAndForm(); - expect(component.vehicleType).toEqual(VehicleTypes.SMALL_TRL); - }); - - it('should show TRL record found without dimensions', () => { - component.isEditing = false; - jest - .spyOn(techRecordService, 'techRecord$', 'get') - .mockReturnValue( - of({ - systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin', techRecord_vehicleType: VehicleTypes.TRL, - } as V3TechRecordModel), - ); - fixture.detectChanges(); - - checkHeadingAndForm(); - expect(component.vehicleType).toEqual(VehicleTypes.TRL); - }); - it('should show adr section if ADR is enabled', () => { - component.isEditing = false; - jest.spyOn(featureToggleService, 'isFeatureEnabled').mockReturnValue(true); - jest - .spyOn(techRecordService, 'techRecord$', 'get') - .mockReturnValue( - of({ - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_vehicleType: VehicleTypes.HGV, - techRecord_adrDetails_dangerousGoods: true, - techRecord_adrDetails_applicantDetails_name: 'Test', - } as V3TechRecordModel), - ); - fixture.detectChanges(); - - checkHeadingAndForm(); - expect(component.adr).toBeDefined(); - }); - it('should not show adr section if ADR is disabled', () => { - component.isEditing = false; - jest.spyOn(featureToggleService, 'isFeatureEnabled').mockReturnValue(false); - jest - .spyOn(techRecordService, 'techRecord$', 'get') - .mockReturnValue( - of({ - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_vehicleType: VehicleTypes.TRL, - techRecord_adrDetails_applicantDetails_name: 'Test', - } as V3TechRecordModel), - ); - fixture.detectChanges(); - - checkHeadingAndForm(); - expect(component.adr).toBeUndefined(); - }); - }); - - describe('handleFormState', () => { - it('should dispatch updateEditingTechRecord', () => { - jest.spyOn(component, 'checkForms').mockImplementation(); - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const mockTechRecord = { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_vehicleType: VehicleTypes.LGV, - } as unknown as TechRecordType<'put'>; - component.techRecordCalculated = mockTechRecord; - jest.spyOn(store, 'select').mockReturnValue(of(mockTechRecord)); - component.sections = new QueryList(); - - component.handleFormState({}); - - expect(dispatchSpy).toHaveBeenCalledWith(updateEditingTechRecord({ vehicleTechRecord: mockTechRecord })); - }); - }); + let component: TechRecordSummaryComponent; + let fixture: ComponentFixture; + let store: MockStore; + let techRecordService: TechnicalRecordService; + let featureToggleService: FeatureToggleService; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TechRecordSummaryComponent], + imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule, SharedModule], + providers: [ + MultiOptionsService, + provideMockStore({ initialState: initialAppState }), + { + provide: UserService, + useValue: { + roles$: of([Roles.TechRecordAmend]), + }, + }, + TechnicalRecordService, + FeatureToggleService, + ], + }) + .overrideComponent(LettersComponent, { + set: { + selector: 'app-letters', + template: '

Mock Letters Component

', + }, + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(TechRecordSummaryComponent); + store = TestBed.inject(MockStore); + techRecordService = TestBed.inject(TechnicalRecordService); + featureToggleService = TestBed.inject(FeatureToggleService); + component = fixture.componentInstance; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + function checkHeadingAndForm(): void { + const heading = fixture.debugElement.query(By.css('.govuk-heading-s')); + expect(heading).toBeFalsy(); + + const form = fixture.nativeElement.querySelector('app-dynamic-form-group'); + expect(form).toBeTruthy(); + } + + describe('TechRecordSummaryComponent View', () => { + it('should show PSV record found', () => { + component.isEditing = false; + jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue( + of({ + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_vehicleType: VehicleTypes.PSV, + } as V3TechRecordModel) + ); + fixture.detectChanges(); + checkHeadingAndForm(); + expect(component.vehicleType).toEqual(VehicleTypes.PSV); + }); + + it('should show PSV record found without dimensions', () => { + component.isEditing = false; + jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue( + of({ + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_vehicleType: VehicleTypes.PSV, + } as V3TechRecordModel) + ); + fixture.detectChanges(); + + checkHeadingAndForm(); + expect( + (component.techRecordCalculated as TechRecordTypeByVehicle<'psv'>).techRecord_dimensions_height + ).toBeUndefined(); + }); + + it('should show HGV record found', () => { + component.isEditing = false; + jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue( + of({ + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_vehicleType: VehicleTypes.HGV, + } as V3TechRecordModel) + ); + fixture.detectChanges(); + + checkHeadingAndForm(); + expect(component.vehicleType).toEqual(VehicleTypes.HGV); + }); + + it('should show HGV record found without dimensions', () => { + component.isEditing = false; + jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue( + of({ + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_vehicleType: VehicleTypes.HGV, + } as V3TechRecordModel) + ); + fixture.detectChanges(); + + checkHeadingAndForm(); + expect(component.vehicleType).toEqual(VehicleTypes.HGV); + }); + + it('should show TRL record found', () => { + component.isEditing = false; + jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue( + of({ + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_vehicleType: VehicleTypes.TRL, + techRecord_euVehicleCategory: 'o2', + } as V3TechRecordModel) + ); + fixture.detectChanges(); + + checkHeadingAndForm(); + expect(component.vehicleType).toEqual(VehicleTypes.SMALL_TRL); + }); + + it('should show TRL record found without dimensions', () => { + component.isEditing = false; + jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue( + of({ + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_vehicleType: VehicleTypes.TRL, + } as V3TechRecordModel) + ); + fixture.detectChanges(); + + checkHeadingAndForm(); + expect(component.vehicleType).toEqual(VehicleTypes.TRL); + }); + it('should show adr section if ADR is enabled', () => { + component.isEditing = false; + jest.spyOn(featureToggleService, 'isFeatureEnabled').mockReturnValue(true); + jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue( + of({ + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_vehicleType: VehicleTypes.HGV, + techRecord_adrDetails_dangerousGoods: true, + techRecord_adrDetails_applicantDetails_name: 'Test', + } as V3TechRecordModel) + ); + fixture.detectChanges(); + + checkHeadingAndForm(); + expect(component.adr).toBeDefined(); + }); + it('should not show adr section if ADR is disabled', () => { + component.isEditing = false; + jest.spyOn(featureToggleService, 'isFeatureEnabled').mockReturnValue(false); + jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue( + of({ + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_vehicleType: VehicleTypes.TRL, + techRecord_adrDetails_applicantDetails_name: 'Test', + } as V3TechRecordModel) + ); + fixture.detectChanges(); + + checkHeadingAndForm(); + expect(component.adr).toBeUndefined(); + }); + }); + + describe('handleFormState', () => { + it('should dispatch updateEditingTechRecord', () => { + jest.spyOn(component, 'checkForms').mockImplementation(); + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const mockTechRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_vehicleType: VehicleTypes.LGV, + } as unknown as TechRecordType<'put'>; + component.techRecordCalculated = mockTechRecord; + jest.spyOn(store, 'select').mockReturnValue(of(mockTechRecord)); + component.sections = new QueryList(); + + component.handleFormState({}); + + expect(dispatchSpy).toHaveBeenCalledWith(updateEditingTechRecord({ vehicleTechRecord: mockTechRecord })); + }); + }); }); 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 89b2ce5759..a96a974f24 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 @@ -1,14 +1,14 @@ import { ViewportScroller } from '@angular/common'; import { - ChangeDetectionStrategy, - Component, - EventEmitter, - OnDestroy, - OnInit, - Output, - QueryList, - ViewChild, - ViewChildren, + ChangeDetectionStrategy, + Component, + EventEmitter, + OnDestroy, + OnInit, + Output, + QueryList, + ViewChild, + ViewChildren, } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { GlobalError } from '@core/components/global-error/global-error.interface'; @@ -29,9 +29,7 @@ import { WeightsComponent } from '@forms/custom-sections/weights/weights.compone import { DynamicFormService } from '@forms/services/dynamic-form.service'; import { CustomFormArray, CustomFormGroup, FormNode } from '@forms/services/dynamic-form.types'; import { vehicleTemplateMap } from '@forms/utils/tech-record-constants'; -import { - ReasonForEditing, StatusCodes, V3TechRecordModel, VehicleTypes, -} from '@models/vehicle-tech-record.model'; +import { ReasonForEditing, StatusCodes, V3TechRecordModel, VehicleTypes } from '@models/vehicle-tech-record.model'; import { Store } from '@ngrx/store'; import { AxlesService } from '@services/axles/axles.service'; import { FeatureToggleService } from '@services/feature-toggle-service/feature-toggle-service'; @@ -41,228 +39,229 @@ import { RouterService } from '@services/router/router.service'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { selectScrollPosition } from '@store/technical-records'; import { cloneDeep, mergeWith } from 'lodash'; -import { - Observable, Subject, - debounceTime, map, - take, takeUntil, -} from 'rxjs'; +import { Observable, Subject, debounceTime, map, take, takeUntil } from 'rxjs'; @Component({ - selector: 'app-tech-record-summary', - templateUrl: './tech-record-summary.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, - styleUrls: ['./tech-record-summary.component.scss'], + selector: 'app-tech-record-summary', + templateUrl: './tech-record-summary.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + styleUrls: ['./tech-record-summary.component.scss'], }) export class TechRecordSummaryComponent implements OnInit, OnDestroy { - @ViewChildren(DynamicFormGroupComponent) sections!: QueryList; - @ViewChild(BodyComponent) body!: BodyComponent; - @ViewChild(DimensionsComponent) dimensions!: DimensionsComponent; - @ViewChild(PsvBrakesComponent) psvBrakes!: PsvBrakesComponent; - @ViewChild(TrlBrakesComponent) trlBrakes!: TrlBrakesComponent; - @ViewChild(TyresComponent) tyres!: TyresComponent; - @ViewChild(WeightsComponent) weights!: WeightsComponent; - @ViewChild(LettersComponent) letters!: LettersComponent; - @ViewChild(ApprovalTypeComponent) approvalType!: ApprovalTypeComponent; - @ViewChild(AdrComponent) adr!: AdrComponent; - - @Output() isFormDirty = new EventEmitter(); - @Output() isFormInvalid = new EventEmitter(); - - techRecordCalculated?: V3TechRecordModel; - sectionTemplates: Array = []; - middleIndex = 0; - isEditing = false; - scrollPosition: [number, number] = [0, 0]; - isADREnabled = false; - isADRCertGenEnabled = false; - - private destroy$ = new Subject(); - - constructor( - private axlesService: AxlesService, - private errorService: GlobalErrorService, - private warningService: GlobalWarningService, - private referenceDataService: ReferenceDataService, - private technicalRecordService: TechnicalRecordService, - private routerService: RouterService, - private activatedRoute: ActivatedRoute, - private viewportScroller: ViewportScroller, - private store: Store, - private loading: LoadingService, - private featureToggleService: FeatureToggleService, - ) { } - - ngOnInit(): void { - this.isADREnabled = this.featureToggleService.isFeatureEnabled('adrToggle'); - this.isADRCertGenEnabled = this.featureToggleService.isFeatureEnabled('adrCertToggle'); - this.technicalRecordService.techRecord$ - .pipe( - map((record) => { - if (!record) { - return; - } - - let techRecord = cloneDeep(record); - techRecord = this.normaliseAxles(record); - - return techRecord; - }), - takeUntil(this.destroy$), - ) - .subscribe((techRecord) => { - if (techRecord) { - this.techRecordCalculated = techRecord; - } - this.referenceDataService.removeTyreSearch(); - this.sectionTemplates = this.vehicleTemplates; - this.middleIndex = Math.floor(this.sectionTemplates.length / 2); - }); - - const editingReason = this.activatedRoute.snapshot.data['reason']; - if (this.isEditing) { - this.technicalRecordService.clearReasonForCreation(); - this.technicalRecordService.techRecord$.pipe(takeUntil(this.destroy$), take(1)).subscribe((techRecord) => { - if (techRecord) { - if (editingReason === ReasonForEditing.NOTIFIABLE_ALTERATION_NEEDED) { - this.technicalRecordService.updateEditingTechRecord({ - ...(techRecord as TechRecordType<'put'>), - techRecord_statusCode: StatusCodes.PROVISIONAL, - }); - } - - if (techRecord?.vin?.match('([IOQ])a*')) { - const warnings: GlobalWarning[] = []; - warnings.push({ warning: 'VIN should not contain I, O or Q', anchorLink: 'vin' }); - this.warningService.setWarnings(warnings); - } - } - }); - } else if (!this.isEditing) { - this.warningService.clearWarnings(); - } - - this.store - .select(selectScrollPosition) - .pipe(take(1), takeUntil(this.destroy$)) - .subscribe((position) => { - this.scrollPosition = position; - }); - - this.loading.showSpinner$.pipe(takeUntil(this.destroy$), debounceTime(10)).subscribe((loading) => { - if (!loading) { - this.viewportScroller.scrollToPosition(this.scrollPosition); - } - }); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - get vehicleType() { - return this.techRecordCalculated ? this.technicalRecordService.getVehicleTypeWithSmallTrl(this.techRecordCalculated) : undefined; - } - - get vehicleTemplates(): Array { - this.isEditing$.pipe(takeUntil(this.destroy$)).subscribe((editing) => { - this.isEditing = editing; - }); - if (!this.vehicleType) { - return []; - } - return ( - vehicleTemplateMap.get(this.vehicleType)?.filter((template) => template.name !== (this.isEditing ? 'audit' : 'reasonForCreationSection')) - .filter((template) => template.name !== (this.isADREnabled ? '' : 'adrSection')) - .filter((template) => template.name !== (this.isADRCertGenEnabled ? '' : 'adrCertificateSection')) - ?? [] - ); - } - - get sectionTemplatesState$() { - return this.technicalRecordService.sectionStates$; - } - - isSectionExpanded$(sectionName: string | number) { - return this.sectionTemplatesState$?.pipe(map((sections) => sections?.includes(sectionName))); - } - - get isEditing$(): Observable { - return this.routerService.getRouteDataProperty$('isEditing').pipe(map((isEditing) => !!isEditing)); - } - - get hint(): string { - return 'Complete all required fields to create a testable record'; - } - - get customSectionForms(): Array { - const commonCustomSections = [ - this.body?.form, - this.dimensions?.form, - this.tyres?.form, - this.weights?.form, - this.approvalType?.form, - ]; - - switch (this.vehicleType) { - case VehicleTypes.PSV: - return [...commonCustomSections, this.psvBrakes.form]; - case VehicleTypes.HGV: - return this.isADREnabled ? [...commonCustomSections, this.adr.form] : commonCustomSections; - case VehicleTypes.TRL: - return this.isADREnabled ? [...commonCustomSections, this.trlBrakes.form, this.letters.form, this.adr.form] - : [...commonCustomSections, this.trlBrakes.form, this.letters.form]; - case VehicleTypes.LGV: - return this.isADREnabled ? [this.adr.form] : []; - default: - return []; - } - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - handleFormState(event: any): void { - const isPrimitiveArray = (a: unknown, b: unknown) => (Array.isArray(a) && !a.some((i) => typeof i === 'object') ? b : undefined); - - this.techRecordCalculated = mergeWith(cloneDeep(this.techRecordCalculated), event, isPrimitiveArray); - this.technicalRecordService.updateEditingTechRecord(this.techRecordCalculated as TechRecordType<'put'>); - } - - checkForms(): void { - const forms = this.sections?.map((section) => section.form).concat(this.customSectionForms); - - this.isFormDirty.emit(forms.some((form) => form.dirty)); - - this.setErrors(forms); - - this.isFormInvalid.emit(forms.some((form) => form.invalid)); - } - - setErrors(forms: Array): void { - const errors: GlobalError[] = []; - - forms.forEach((form) => DynamicFormService.validate(form, errors)); - - if (errors.length) { - this.errorService.setErrors(errors); - } else { - this.errorService.clearErrors(); - } - } - - private normaliseAxles(record: V3TechRecordModel): V3TechRecordModel { - const type = record.techRecord_vehicleType; - const category = record.techRecord_euVehicleCategory; - - if (type === VehicleTypes.HGV || (type === VehicleTypes.TRL && category !== 'o1' && category !== 'o2')) { - const [axles, axleSpacing] = this.axlesService.normaliseAxles( - record.techRecord_axles ?? [], - record.techRecord_dimensions_axleSpacing, - ); - - record.techRecord_dimensions_axleSpacing = axleSpacing; - record.techRecord_axles = axles; - } - - return record; - } + @ViewChildren(DynamicFormGroupComponent) sections!: QueryList; + @ViewChild(BodyComponent) body!: BodyComponent; + @ViewChild(DimensionsComponent) dimensions!: DimensionsComponent; + @ViewChild(PsvBrakesComponent) psvBrakes!: PsvBrakesComponent; + @ViewChild(TrlBrakesComponent) trlBrakes!: TrlBrakesComponent; + @ViewChild(TyresComponent) tyres!: TyresComponent; + @ViewChild(WeightsComponent) weights!: WeightsComponent; + @ViewChild(LettersComponent) letters!: LettersComponent; + @ViewChild(ApprovalTypeComponent) approvalType!: ApprovalTypeComponent; + @ViewChild(AdrComponent) adr!: AdrComponent; + + @Output() isFormDirty = new EventEmitter(); + @Output() isFormInvalid = new EventEmitter(); + + techRecordCalculated?: V3TechRecordModel; + sectionTemplates: Array = []; + middleIndex = 0; + isEditing = false; + scrollPosition: [number, number] = [0, 0]; + isADREnabled = false; + isADRCertGenEnabled = false; + + private destroy$ = new Subject(); + + constructor( + private axlesService: AxlesService, + private errorService: GlobalErrorService, + private warningService: GlobalWarningService, + private referenceDataService: ReferenceDataService, + private technicalRecordService: TechnicalRecordService, + private routerService: RouterService, + private activatedRoute: ActivatedRoute, + private viewportScroller: ViewportScroller, + private store: Store, + private loading: LoadingService, + private featureToggleService: FeatureToggleService + ) {} + + ngOnInit(): void { + this.isADREnabled = this.featureToggleService.isFeatureEnabled('adrToggle'); + this.isADRCertGenEnabled = this.featureToggleService.isFeatureEnabled('adrCertToggle'); + this.technicalRecordService.techRecord$ + .pipe( + map((record) => { + if (!record) { + return; + } + + let techRecord = cloneDeep(record); + techRecord = this.normaliseAxles(record); + + return techRecord; + }), + takeUntil(this.destroy$) + ) + .subscribe((techRecord) => { + if (techRecord) { + this.techRecordCalculated = techRecord; + } + this.referenceDataService.removeTyreSearch(); + this.sectionTemplates = this.vehicleTemplates; + this.middleIndex = Math.floor(this.sectionTemplates.length / 2); + }); + + const editingReason = this.activatedRoute.snapshot.data['reason']; + if (this.isEditing) { + this.technicalRecordService.clearReasonForCreation(); + this.technicalRecordService.techRecord$.pipe(takeUntil(this.destroy$), take(1)).subscribe((techRecord) => { + if (techRecord) { + if (editingReason === ReasonForEditing.NOTIFIABLE_ALTERATION_NEEDED) { + this.technicalRecordService.updateEditingTechRecord({ + ...(techRecord as TechRecordType<'put'>), + techRecord_statusCode: StatusCodes.PROVISIONAL, + }); + } + + if (techRecord?.vin?.match('([IOQ])a*')) { + const warnings: GlobalWarning[] = []; + warnings.push({ warning: 'VIN should not contain I, O or Q', anchorLink: 'vin' }); + this.warningService.setWarnings(warnings); + } + } + }); + } else if (!this.isEditing) { + this.warningService.clearWarnings(); + } + + this.store + .select(selectScrollPosition) + .pipe(take(1), takeUntil(this.destroy$)) + .subscribe((position) => { + this.scrollPosition = position; + }); + + this.loading.showSpinner$.pipe(takeUntil(this.destroy$), debounceTime(10)).subscribe((loading) => { + if (!loading) { + this.viewportScroller.scrollToPosition(this.scrollPosition); + } + }); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + get vehicleType() { + return this.techRecordCalculated + ? this.technicalRecordService.getVehicleTypeWithSmallTrl(this.techRecordCalculated) + : undefined; + } + + get vehicleTemplates(): Array { + this.isEditing$.pipe(takeUntil(this.destroy$)).subscribe((editing) => { + this.isEditing = editing; + }); + if (!this.vehicleType) { + return []; + } + return ( + vehicleTemplateMap + .get(this.vehicleType) + ?.filter((template) => template.name !== (this.isEditing ? 'audit' : 'reasonForCreationSection')) + .filter((template) => template.name !== (this.isADREnabled ? '' : 'adrSection')) + .filter((template) => template.name !== (this.isADRCertGenEnabled ? '' : 'adrCertificateSection')) ?? [] + ); + } + + get sectionTemplatesState$() { + return this.technicalRecordService.sectionStates$; + } + + isSectionExpanded$(sectionName: string | number) { + return this.sectionTemplatesState$?.pipe(map((sections) => sections?.includes(sectionName))); + } + + get isEditing$(): Observable { + return this.routerService.getRouteDataProperty$('isEditing').pipe(map((isEditing) => !!isEditing)); + } + + get hint(): string { + return 'Complete all required fields to create a testable record'; + } + + get customSectionForms(): Array { + const commonCustomSections = [ + this.body?.form, + this.dimensions?.form, + this.tyres?.form, + this.weights?.form, + this.approvalType?.form, + ]; + + switch (this.vehicleType) { + case VehicleTypes.PSV: + return [...commonCustomSections, this.psvBrakes.form]; + case VehicleTypes.HGV: + return this.isADREnabled ? [...commonCustomSections, this.adr.form] : commonCustomSections; + case VehicleTypes.TRL: + return this.isADREnabled + ? [...commonCustomSections, this.trlBrakes.form, this.letters.form, this.adr.form] + : [...commonCustomSections, this.trlBrakes.form, this.letters.form]; + case VehicleTypes.LGV: + return this.isADREnabled ? [this.adr.form] : []; + default: + return []; + } + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + handleFormState(event: any): void { + const isPrimitiveArray = (a: unknown, b: unknown) => + Array.isArray(a) && !a.some((i) => typeof i === 'object') ? b : undefined; + + this.techRecordCalculated = mergeWith(cloneDeep(this.techRecordCalculated), event, isPrimitiveArray); + this.technicalRecordService.updateEditingTechRecord(this.techRecordCalculated as TechRecordType<'put'>); + } + + checkForms(): void { + const forms = this.sections?.map((section) => section.form).concat(this.customSectionForms); + + this.isFormDirty.emit(forms.some((form) => form.dirty)); + + this.setErrors(forms); + + this.isFormInvalid.emit(forms.some((form) => form.invalid)); + } + + setErrors(forms: Array): void { + const errors: GlobalError[] = []; + + forms.forEach((form) => DynamicFormService.validate(form, errors)); + + if (errors.length) { + this.errorService.setErrors(errors); + } else { + this.errorService.clearErrors(); + } + } + + private normaliseAxles(record: V3TechRecordModel): V3TechRecordModel { + const type = record.techRecord_vehicleType; + const category = record.techRecord_euVehicleCategory; + + if (type === VehicleTypes.HGV || (type === VehicleTypes.TRL && category !== 'o1' && category !== 'o2')) { + const [axles, axleSpacing] = this.axlesService.normaliseAxles( + record.techRecord_axles ?? [], + record.techRecord_dimensions_axleSpacing + ); + + record.techRecord_dimensions_axleSpacing = axleSpacing; + record.techRecord_axles = axles; + } + + return record; + } } diff --git a/src/app/features/tech-record/components/tech-record-title/tech-record-title.component.spec.ts b/src/app/features/tech-record/components/tech-record-title/tech-record-title.component.spec.ts index 15b767a223..144aee7562 100644 --- a/src/app/features/tech-record/components/tech-record-title/tech-record-title.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-title/tech-record-title.component.spec.ts @@ -7,10 +7,7 @@ import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/ import { DynamicFormsModule } from '@forms/dynamic-forms.module'; import { mockVehicleTechnicalRecord } from '@mocks/mock-vehicle-technical-record.mock'; import { Roles } from '@models/roles.enum'; -import { - V3TechRecordModel, VehicleTypes, - VehiclesOtherThan, -} from '@models/vehicle-tech-record.model'; +import { V3TechRecordModel, VehicleTypes, VehiclesOtherThan } from '@models/vehicle-tech-record.model'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { UserService } from '@services/user-service/user-service'; @@ -21,103 +18,107 @@ import { Observable, of } from 'rxjs'; import { TechRecordTitleComponent } from './tech-record-title.component'; const MockUserService = { - getUserName$: jest.fn().mockReturnValue(new Observable()), - roles$: of([Roles.TestResultAmend, Roles.TestResultView]), + getUserName$: jest.fn().mockReturnValue(new Observable()), + roles$: of([Roles.TestResultAmend, Roles.TestResultView]), }; describe('TechRecordTitleComponent', () => { - let component: TechRecordTitleComponent; - let fixture: ComponentFixture; - let store: MockStore; - let technicalRecordService: TechnicalRecordService; - let mockRecord: V3TechRecordModel; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TechRecordTitleComponent], - imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule, SharedModule], - providers: [provideMockStore({ initialState: initialAppState }), { provide: UserService, useValue: MockUserService }, TechnicalRecordService], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(TechRecordTitleComponent); - store = TestBed.inject(MockStore); - component = fixture.componentInstance; - technicalRecordService = TestBed.inject(TechnicalRecordService); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('the VRM fields', () => { - beforeEach(() => { - mockRecord = { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - primaryVrm: 'TESTVRM', - secondaryVrms: ['TESTVRM1', 'TESTVRM2', 'TESTVRM3', 'TESTVRM4', 'TESTVRM5'], - techRecord_vehicleType: VehicleTypes.LGV, - } as unknown as TechRecordType<'put'>; - jest.spyOn(store, 'select').mockReturnValue(of(mockRecord)); - component.vehicle = mockRecord; - store.overrideSelector(editingTechRecord, mockRecord); - }); - it('should show primary VRM for current record', () => { - fixture.detectChanges(); - - const vrmField = fixture.nativeElement.querySelector('app-number-plate'); - expect(vrmField.textContent).toContain('TEST VRM'); - }); - - it('should show the newest (last) secondary VRM', () => { - fixture.detectChanges(); - - const vrmField = fixture.nativeElement.querySelectorAll('app-number-plate')[1]; - expect(vrmField.textContent).toContain('TESTV RM5'); - expect(vrmField.textContent).not.toContain('TEST VRM'); - expect(vrmField.textContent).not.toContain('TESTV RM2'); - expect(vrmField.textContent).not.toContain('TESTV RM3'); - expect(vrmField.textContent).not.toContain('TESTV RM4'); - }); - it('should not create previous-vrm-span if no secondary vrm exists', () => { - delete (mockRecord as VehiclesOtherThan<'trl'>).secondaryVrms; - fixture.detectChanges(); - - const vrmField = fixture.debugElement.query(By.css('#previous-vrm-span')); - expect(vrmField).toBeNull(); - }); - }); - describe('trailer ID', () => { - it('shows a trailer ID instead of VRM when vehicle type is a trailer', () => { - const mockRecordTrailer = mockVehicleTechnicalRecord(VehicleTypes.TRL); - jest.spyOn(technicalRecordService, 'techRecord$', 'get').mockReturnValue(of(mockRecordTrailer)); - - component.vehicle = mockRecordTrailer; - - store.overrideSelector(selectTechRecord, mockRecordTrailer); - fixture.detectChanges(); - - const trailerIdField = fixture.debugElement.query(By.css('#trailer-id')); - expect(trailerIdField.nativeElement.textContent).toContain('TestId'); - }); - - const smallTrailerEuVehicleCategories = [EUVehicleCategory.O1, EUVehicleCategory.O2]; - - it.each(smallTrailerEuVehicleCategories)('does not show secondary VRMs for small trailer', (euVehicleCategory) => { - const mockRecordTrailer = mockVehicleTechnicalRecord(VehicleTypes.TRL); - jest.spyOn(technicalRecordService, 'techRecord$', 'get').mockReturnValue(of(mockRecordTrailer)); - mockRecordTrailer.techRecord_euVehicleCategory = euVehicleCategory; - component.vehicle = mockRecordTrailer; - store.overrideSelector(selectTechRecord, mockRecordTrailer); - fixture.detectChanges(); - - const trailerIdField = fixture.debugElement.query(By.css('#trailer-id')); - expect(trailerIdField.nativeElement.textContent).toContain('TestId'); - const secondaryVrmField = fixture.debugElement.query(By.css('#previous-vrm')); - expect(secondaryVrmField).toBeNull(); - }); - }); + let component: TechRecordTitleComponent; + let fixture: ComponentFixture; + let store: MockStore; + let technicalRecordService: TechnicalRecordService; + let mockRecord: V3TechRecordModel; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TechRecordTitleComponent], + imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule, SharedModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + { provide: UserService, useValue: MockUserService }, + TechnicalRecordService, + ], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(TechRecordTitleComponent); + store = TestBed.inject(MockStore); + component = fixture.componentInstance; + technicalRecordService = TestBed.inject(TechnicalRecordService); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('the VRM fields', () => { + beforeEach(() => { + mockRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + primaryVrm: 'TESTVRM', + secondaryVrms: ['TESTVRM1', 'TESTVRM2', 'TESTVRM3', 'TESTVRM4', 'TESTVRM5'], + techRecord_vehicleType: VehicleTypes.LGV, + } as unknown as TechRecordType<'put'>; + jest.spyOn(store, 'select').mockReturnValue(of(mockRecord)); + component.vehicle = mockRecord; + store.overrideSelector(editingTechRecord, mockRecord); + }); + it('should show primary VRM for current record', () => { + fixture.detectChanges(); + + const vrmField = fixture.nativeElement.querySelector('app-number-plate'); + expect(vrmField.textContent).toContain('TEST VRM'); + }); + + it('should show the newest (last) secondary VRM', () => { + fixture.detectChanges(); + + const vrmField = fixture.nativeElement.querySelectorAll('app-number-plate')[1]; + expect(vrmField.textContent).toContain('TESTV RM5'); + expect(vrmField.textContent).not.toContain('TEST VRM'); + expect(vrmField.textContent).not.toContain('TESTV RM2'); + expect(vrmField.textContent).not.toContain('TESTV RM3'); + expect(vrmField.textContent).not.toContain('TESTV RM4'); + }); + it('should not create previous-vrm-span if no secondary vrm exists', () => { + delete (mockRecord as VehiclesOtherThan<'trl'>).secondaryVrms; + fixture.detectChanges(); + + const vrmField = fixture.debugElement.query(By.css('#previous-vrm-span')); + expect(vrmField).toBeNull(); + }); + }); + describe('trailer ID', () => { + it('shows a trailer ID instead of VRM when vehicle type is a trailer', () => { + const mockRecordTrailer = mockVehicleTechnicalRecord(VehicleTypes.TRL); + jest.spyOn(technicalRecordService, 'techRecord$', 'get').mockReturnValue(of(mockRecordTrailer)); + + component.vehicle = mockRecordTrailer; + + store.overrideSelector(selectTechRecord, mockRecordTrailer); + fixture.detectChanges(); + + const trailerIdField = fixture.debugElement.query(By.css('#trailer-id')); + expect(trailerIdField.nativeElement.textContent).toContain('TestId'); + }); + + const smallTrailerEuVehicleCategories = [EUVehicleCategory.O1, EUVehicleCategory.O2]; + + it.each(smallTrailerEuVehicleCategories)('does not show secondary VRMs for small trailer', (euVehicleCategory) => { + const mockRecordTrailer = mockVehicleTechnicalRecord(VehicleTypes.TRL); + jest.spyOn(technicalRecordService, 'techRecord$', 'get').mockReturnValue(of(mockRecordTrailer)); + mockRecordTrailer.techRecord_euVehicleCategory = euVehicleCategory; + component.vehicle = mockRecordTrailer; + store.overrideSelector(selectTechRecord, mockRecordTrailer); + fixture.detectChanges(); + + const trailerIdField = fixture.debugElement.query(By.css('#trailer-id')); + expect(trailerIdField.nativeElement.textContent).toContain('TestId'); + const secondaryVrmField = fixture.debugElement.query(By.css('#previous-vrm')); + expect(secondaryVrmField).toBeNull(); + }); + }); }); diff --git a/src/app/features/tech-record/components/tech-record-title/tech-record-title.component.ts b/src/app/features/tech-record/components/tech-record-title/tech-record-title.component.ts index a89e9491f9..21056f613a 100644 --- a/src/app/features/tech-record/components/tech-record-title/tech-record-title.component.ts +++ b/src/app/features/tech-record/components/tech-record-title/tech-record-title.component.ts @@ -12,68 +12,77 @@ import { selectTechRecord } from '@store/technical-records'; import { Observable, take } from 'rxjs'; @Component({ - selector: 'app-tech-record-title[vehicle]', - templateUrl: './tech-record-title.component.html', - styleUrls: ['./tech-record-title.component.scss'], + selector: 'app-tech-record-title[vehicle]', + templateUrl: './tech-record-title.component.html', + styleUrls: ['./tech-record-title.component.scss'], }) export class TechRecordTitleComponent implements OnInit { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - @Input() vehicle?: any; - @Input() actions: TechRecordActions = TechRecordActions.NONE; - @Input() hideActions = false; - @Input() customTitle = ''; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + @Input() vehicle?: any; + @Input() actions: TechRecordActions = TechRecordActions.NONE; + @Input() hideActions = false; + @Input() customTitle = ''; - currentTechRecord$?: Observable | undefined>; - queryableActions: string[] = []; - vehicleMakeAndModel = ''; + currentTechRecord$?: Observable | undefined>; + queryableActions: string[] = []; + vehicleMakeAndModel = ''; - constructor(private route: ActivatedRoute, private router: Router, private store: Store, private technicalRecordService: TechnicalRecordService) {} + constructor( + private route: ActivatedRoute, + private router: Router, + private store: Store, + private technicalRecordService: TechnicalRecordService + ) {} - ngOnInit(): void { - this.queryableActions = this.actions.split(','); + ngOnInit(): void { + this.queryableActions = this.actions.split(','); - this.currentTechRecord$ = this.store.select(selectTechRecord) as Observable | undefined>; + this.currentTechRecord$ = this.store.select(selectTechRecord) as Observable | undefined>; - this.currentTechRecord$.pipe(take(1)).subscribe((data) => { - if (data) { - this.vehicleMakeAndModel = this.technicalRecordService.getMakeAndModel(data); - } - }); - } + this.currentTechRecord$.pipe(take(1)).subscribe((data) => { + if (data) { + this.vehicleMakeAndModel = this.technicalRecordService.getMakeAndModel(data); + } + }); + } - get currentVrm(): string | undefined { - return this.vehicle?.techRecord_vehicleType !== 'trl' ? this.vehicle?.primaryVrm ?? '' : undefined; - } + get currentVrm(): string | undefined { + return this.vehicle?.techRecord_vehicleType !== 'trl' ? this.vehicle?.primaryVrm ?? '' : undefined; + } - get otherVrms(): string[] | undefined { - return this.vehicle?.techRecord_vehicleType !== 'trl' ? this.vehicle?.secondaryVrms ?? [] : undefined; - } + get otherVrms(): string[] | undefined { + return this.vehicle?.techRecord_vehicleType !== 'trl' ? this.vehicle?.secondaryVrms ?? [] : undefined; + } - get vehicleTypes(): typeof VehicleTypes { - return VehicleTypes; - } + get vehicleTypes(): typeof VehicleTypes { + return VehicleTypes; + } - get roles(): typeof Roles { - return Roles; - } + get roles(): typeof Roles { + return Roles; + } - get statuses(): typeof StatusCodes { - return StatusCodes; - } + get statuses(): typeof StatusCodes { + return StatusCodes; + } - getVehicleType(techRecord: V3TechRecordModel): VehicleTypes { - return this.technicalRecordService.getVehicleTypeWithSmallTrl(techRecord); - } + getVehicleType(techRecord: V3TechRecordModel): VehicleTypes { + return this.technicalRecordService.getVehicleTypeWithSmallTrl(techRecord); + } - getCompletenessColor(completeness?: string): 'green' | 'red' { - return completeness === 'complete' ? 'green' : 'red'; - } + getCompletenessColor(completeness?: string): 'green' | 'red' { + return completeness === 'complete' ? 'green' : 'red'; + } - isVrmEditable(statusCode: StatusCode | undefined, currentVehicleType: VehicleType, editableVehicleType: VehicleType): boolean { - return !this.hideActions && statusCode !== StatusCodes.ARCHIVED && currentVehicleType === editableVehicleType; - } + isVrmEditable( + statusCode: StatusCode | undefined, + currentVehicleType: VehicleType, + editableVehicleType: VehicleType + ): boolean { + return !this.hideActions && statusCode !== StatusCodes.ARCHIVED && currentVehicleType === editableVehicleType; + } - navigateTo(path: string, queryParams?: Params): void { - void this.router.navigate([path], { relativeTo: this.route, queryParams }); - } + navigateTo(path: string, queryParams?: Params): void { + void this.router.navigate([path], { relativeTo: this.route, queryParams }); + } } diff --git a/src/app/features/tech-record/components/tech-record-unarchive/tech-record-unarchive-component.ts b/src/app/features/tech-record/components/tech-record-unarchive/tech-record-unarchive-component.ts index 1ba1b66e50..284793c9c7 100644 --- a/src/app/features/tech-record/components/tech-record-unarchive/tech-record-unarchive-component.ts +++ b/src/app/features/tech-record/components/tech-record-unarchive/tech-record-unarchive-component.ts @@ -3,9 +3,7 @@ import { Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; -import { - CustomFormControl, CustomFormGroup, FormNodeOption, FormNodeTypes, -} from '@forms/services/dynamic-form.types'; +import { CustomFormControl, CustomFormGroup, FormNodeOption, FormNodeTypes } from '@forms/services/dynamic-form.types'; import { StatusCodes } from '@models/vehicle-tech-record.model'; import { Actions, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; @@ -15,97 +13,105 @@ import { unarchiveTechRecord, unarchiveTechRecordSuccess } from '@store/technica import { Subject, takeUntil } from 'rxjs'; @Component({ - selector: 'app-tech-record-unarchive', - templateUrl: './tech-record-unarchive.component.html', + selector: 'app-tech-record-unarchive', + templateUrl: './tech-record-unarchive.component.html', }) export class TechRecordUnarchiveComponent implements OnInit, OnDestroy { - techRecord: TechRecordType<'get'> | undefined; - statusCodes: Array> = [ - { label: 'Provisional', value: StatusCodes.PROVISIONAL }, - { label: 'Current', value: StatusCodes.CURRENT }, - ]; - form: CustomFormGroup; - - destroy$ = new Subject(); - - constructor( - private actions$: Actions, - private errorService: GlobalErrorService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - private technicalRecordService: TechnicalRecordService, - ) { - this.form = new CustomFormGroup( - { name: 'unarchivalForm', type: FormNodeTypes.GROUP }, - { - newRecordStatus: new CustomFormControl({ name: 'newRecordStatus', type: FormNodeTypes.CONTROL }, undefined, [Validators.required]), - reason: new CustomFormControl({ name: 'reason', type: FormNodeTypes.CONTROL }, undefined, [Validators.required]), - }, - ); - } - - ngOnInit(): void { - this.technicalRecordService.techRecord$.pipe(takeUntil(this.destroy$)).subscribe((record) => { - this.techRecord = record as TechRecordType<'get'>; - }); - - this.actions$.pipe(ofType(unarchiveTechRecordSuccess), takeUntil(this.destroy$)).subscribe(({ vehicleTechRecord }) => { - void this.router.navigate([`/tech-records/${vehicleTechRecord.systemNumber}/${vehicleTechRecord.createdTimestamp}`]); - - this.technicalRecordService.clearEditingTechRecord(); - }); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - navigateBack(relativePath = '..'): void { - void this.router.navigate([relativePath], { relativeTo: this.route }); - } - - handleSubmit(form: { reason: string; newRecordStatus: string }): void { - if (!this.techRecord) { - return; - } - - if (this.form.valid) { - this.errorService.clearErrors(); - } - - if (this.form.invalid) { - this.validateControls(); - } - - if (!this.form.valid || !form.reason || !form.newRecordStatus) { - return; - } - - this.store.dispatch( - unarchiveTechRecord({ - systemNumber: this.techRecord.systemNumber, - createdTimestamp: this.techRecord.createdTimestamp, - reasonForUnarchiving: this.form.value.reason, - status: this.form.value.newRecordStatus, - }), - ); - } - - private validateControls() { - const reasonControl = this.form.controls['reason']; - const newRecordStatusControl = this.form.controls['newRecordStatus']; - - const errors = []; - if (!reasonControl.valid) { - errors.push({ error: 'Reason for unarchival is required', anchorLink: 'reason' }); - } - - if (!newRecordStatusControl.valid) { - errors.push({ error: 'New Record Status is required', anchorLink: 'newRecordStatus' }); - } - - this.errorService.setErrors(errors); - } + techRecord: TechRecordType<'get'> | undefined; + statusCodes: Array> = [ + { label: 'Provisional', value: StatusCodes.PROVISIONAL }, + { label: 'Current', value: StatusCodes.CURRENT }, + ]; + form: CustomFormGroup; + + destroy$ = new Subject(); + + constructor( + private actions$: Actions, + private errorService: GlobalErrorService, + private route: ActivatedRoute, + private router: Router, + private store: Store, + private technicalRecordService: TechnicalRecordService + ) { + this.form = new CustomFormGroup( + { name: 'unarchivalForm', type: FormNodeTypes.GROUP }, + { + newRecordStatus: new CustomFormControl({ name: 'newRecordStatus', type: FormNodeTypes.CONTROL }, undefined, [ + Validators.required, + ]), + reason: new CustomFormControl({ name: 'reason', type: FormNodeTypes.CONTROL }, undefined, [ + Validators.required, + ]), + } + ); + } + + ngOnInit(): void { + this.technicalRecordService.techRecord$.pipe(takeUntil(this.destroy$)).subscribe((record) => { + this.techRecord = record as TechRecordType<'get'>; + }); + + this.actions$ + .pipe(ofType(unarchiveTechRecordSuccess), takeUntil(this.destroy$)) + .subscribe(({ vehicleTechRecord }) => { + void this.router.navigate([ + `/tech-records/${vehicleTechRecord.systemNumber}/${vehicleTechRecord.createdTimestamp}`, + ]); + + this.technicalRecordService.clearEditingTechRecord(); + }); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + navigateBack(relativePath = '..'): void { + void this.router.navigate([relativePath], { relativeTo: this.route }); + } + + handleSubmit(form: { reason: string; newRecordStatus: string }): void { + if (!this.techRecord) { + return; + } + + if (this.form.valid) { + this.errorService.clearErrors(); + } + + if (this.form.invalid) { + this.validateControls(); + } + + if (!this.form.valid || !form.reason || !form.newRecordStatus) { + return; + } + + this.store.dispatch( + unarchiveTechRecord({ + systemNumber: this.techRecord.systemNumber, + createdTimestamp: this.techRecord.createdTimestamp, + reasonForUnarchiving: this.form.value.reason, + status: this.form.value.newRecordStatus, + }) + ); + } + + private validateControls() { + const reasonControl = this.form.controls['reason']; + const newRecordStatusControl = this.form.controls['newRecordStatus']; + + const errors = []; + if (!reasonControl.valid) { + errors.push({ error: 'Reason for unarchival is required', anchorLink: 'reason' }); + } + + if (!newRecordStatusControl.valid) { + errors.push({ error: 'New Record Status is required', anchorLink: 'newRecordStatus' }); + } + + this.errorService.setErrors(errors); + } } diff --git a/src/app/features/tech-record/components/tech-record-unarchive/tech-record-unarchive.component.spec.ts b/src/app/features/tech-record/components/tech-record-unarchive/tech-record-unarchive.component.spec.ts index 59746b4bdf..9cce85b866 100644 --- a/src/app/features/tech-record/components/tech-record-unarchive/tech-record-unarchive.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-unarchive/tech-record-unarchive.component.spec.ts @@ -16,37 +16,44 @@ import { TechRecordTitleComponent } from '../tech-record-title/tech-record-title import { TechRecordUnarchiveComponent } from './tech-record-unarchive-component'; describe('TechRecordUnarchiveComponent', () => { - let actions$: ReplaySubject; - let component: TechRecordUnarchiveComponent; - let fixture: ComponentFixture; + let actions$: ReplaySubject; + let component: TechRecordUnarchiveComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - actions$ = new ReplaySubject(); + beforeEach(async () => { + actions$ = new ReplaySubject(); - await TestBed.configureTestingModule({ - declarations: [TechRecordUnarchiveComponent, TechRecordTitleComponent], - imports: [DynamicFormsModule, HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule, SharedModule, StoreModule.forRoot({})], - providers: [ - provideMockActions(() => actions$), - provideMockStore({ initialState: initialAppState }), - { provide: APP_BASE_HREF, useValue: '/' }, - { - provide: UserService, - useValue: { - roles$: of([Roles.TechRecordArchive]), - }, - }, - ], - }).compileComponents(); - }); + await TestBed.configureTestingModule({ + declarations: [TechRecordUnarchiveComponent, TechRecordTitleComponent], + imports: [ + DynamicFormsModule, + HttpClientTestingModule, + ReactiveFormsModule, + RouterTestingModule, + SharedModule, + StoreModule.forRoot({}), + ], + providers: [ + provideMockActions(() => actions$), + provideMockStore({ initialState: initialAppState }), + { provide: APP_BASE_HREF, useValue: '/' }, + { + provide: UserService, + useValue: { + roles$: of([Roles.TechRecordArchive]), + }, + }, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TechRecordUnarchiveComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(TechRecordUnarchiveComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/features/tech-record/components/tech-router-outlet/tech-router-outlet.component.ts b/src/app/features/tech-record/components/tech-router-outlet/tech-router-outlet.component.ts index ab3a77dd1a..1911c09b8c 100644 --- a/src/app/features/tech-record/components/tech-router-outlet/tech-router-outlet.component.ts +++ b/src/app/features/tech-record/components/tech-router-outlet/tech-router-outlet.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; @Component({ - selector: 'app-tech-router-outlet', - templateUrl: './tech-router-outlet.component.html', + selector: 'app-tech-router-outlet', + templateUrl: './tech-router-outlet.component.html', }) export class TechRouterOutletComponent {} diff --git a/src/app/features/tech-record/components/test-record-summary/test-record-summary.component.spec.ts b/src/app/features/tech-record/components/test-record-summary/test-record-summary.component.spec.ts index 25612ae2b5..ac1b4359b5 100644 --- a/src/app/features/tech-record/components/test-record-summary/test-record-summary.component.spec.ts +++ b/src/app/features/tech-record/components/test-record-summary/test-record-summary.component.spec.ts @@ -9,110 +9,107 @@ import { SharedModule } from '@shared/shared.module'; import { TestRecordSummaryComponent } from './test-record-summary.component'; describe('TestRecordSummaryComponent', () => { - let component: TestRecordSummaryComponent; - let fixture: ComponentFixture; + let component: TestRecordSummaryComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TestRecordSummaryComponent], - imports: [RouterTestingModule, SharedModule], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TestRecordSummaryComponent], + imports: [RouterTestingModule, SharedModule], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TestRecordSummaryComponent); - component = fixture.componentInstance; - }); + beforeEach(() => { + fixture = TestBed.createComponent(TestRecordSummaryComponent); + component = fixture.componentInstance; + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it('should not show table if no records found', () => { - component.testResults = []; - fixture.detectChanges(); + it('should not show table if no records found', () => { + component.testResults = []; + fixture.detectChanges(); - const heading = fixture.debugElement.query(By.css('.govuk-heading-s')); - expect(heading).toBeTruthy(); - expect(heading.nativeElement.innerHTML).toBe('No test records found.'); + const heading = fixture.debugElement.query(By.css('.govuk-heading-s')); + expect(heading).toBeTruthy(); + expect(heading.nativeElement.innerHTML).toBe('No test records found.'); - const table = fixture.debugElement.query(By.css('.govuk-table__body')); - expect(table).toBeFalsy(); - }); + const table = fixture.debugElement.query(By.css('.govuk-table__body')); + expect(table).toBeFalsy(); + }); - it('should show table if records found', () => { - component.testResults = [createMockTestResult()]; - fixture.detectChanges(); + it('should show table if records found', () => { + component.testResults = [createMockTestResult()]; + fixture.detectChanges(); - const heading = fixture.debugElement.query(By.css('.govuk-heading-s')); - expect(heading).toBeFalsy(); + const heading = fixture.debugElement.query(By.css('.govuk-heading-s')); + expect(heading).toBeFalsy(); - const table = fixture.debugElement.query(By.css('.govuk-table__body')); - expect(table).toBeTruthy(); - }); + const table = fixture.debugElement.query(By.css('.govuk-table__body')); + expect(table).toBeTruthy(); + }); - it('should concatinate multiple test types', () => { - const testTypeNames = component.getTestTypeName( - createMockTestResult({ - testTypes: [ - createMockTestType({ testTypeName: 'name' }), - createMockTestType({ testTypeName: 'name' }), - ], - }), - ); - expect(testTypeNames).toBe('name,name'); - }); + it('should concatinate multiple test types', () => { + const testTypeNames = component.getTestTypeName( + createMockTestResult({ + testTypes: [createMockTestType({ testTypeName: 'name' }), createMockTestType({ testTypeName: 'name' })], + }) + ); + expect(testTypeNames).toBe('name,name'); + }); - it('should concatinate multiple test results', () => { - const testTypeResults = component.getTestTypeResults( - createMockTestResult({ - testTypes: [ - createMockTestType({ testResult: resultOfTestEnum.pass }), - createMockTestType({ testResult: resultOfTestEnum.pass }), - ], - }), - ); - expect(testTypeResults).toBe('pass,pass'); - }); + it('should concatinate multiple test results', () => { + const testTypeResults = component.getTestTypeResults( + createMockTestResult({ + testTypes: [ + createMockTestType({ testResult: resultOfTestEnum.pass }), + createMockTestType({ testResult: resultOfTestEnum.pass }), + ], + }) + ); + expect(testTypeResults).toBe('pass,pass'); + }); - it('should retrieve all testTypes and creates sorted TestField[]', () => { - const mockRecords = [ - { - testResultId: '1', - testTypes: [ - { - testTypeStartTimestamp: new Date('12/12/2022').toISOString(), - testNumber: '1', - testResult: resultOfTestEnum.pass, - testTypeName: 'annual', - }, - { - testTypeStartTimestamp: new Date('12/12/2023').toISOString(), - testNumber: '2', - testResult: resultOfTestEnum.pass, - testTypeName: 'annual', - }, - ], - }, - { - testResultId: '1', - testTypes: [ - { - testTypeStartTimestamp: new Date('12/12/2021').toISOString(), - testNumber: '1', - testResult: resultOfTestEnum.pass, - testTypeName: 'annual', - }, - ], - }, - ] as TestResultModel[]; - component.testResults = mockRecords; - const testFieldResults = component.sortedTestTypeFields; + it('should retrieve all testTypes and creates sorted TestField[]', () => { + const mockRecords = [ + { + testResultId: '1', + testTypes: [ + { + testTypeStartTimestamp: new Date('12/12/2022').toISOString(), + testNumber: '1', + testResult: resultOfTestEnum.pass, + testTypeName: 'annual', + }, + { + testTypeStartTimestamp: new Date('12/12/2023').toISOString(), + testNumber: '2', + testResult: resultOfTestEnum.pass, + testTypeName: 'annual', + }, + ], + }, + { + testResultId: '1', + testTypes: [ + { + testTypeStartTimestamp: new Date('12/12/2021').toISOString(), + testNumber: '1', + testResult: resultOfTestEnum.pass, + testTypeName: 'annual', + }, + ], + }, + ] as TestResultModel[]; + component.testResults = mockRecords; + const testFieldResults = component.sortedTestTypeFields; - expect(testFieldResults).toHaveLength(3); + expect(testFieldResults).toHaveLength(3); - expect(testFieldResults[0].testTypeStartTimestamp).toBe(mockRecords[0].testTypes[1].testTypeStartTimestamp); - expect(testFieldResults[1].testTypeStartTimestamp).toBe(mockRecords[0].testTypes[0].testTypeStartTimestamp); - expect(testFieldResults[2].testTypeStartTimestamp).toBe(mockRecords[1].testTypes[0].testTypeStartTimestamp); - }); + expect(testFieldResults[0].testTypeStartTimestamp).toBe(mockRecords[0].testTypes[1].testTypeStartTimestamp); + expect(testFieldResults[1].testTypeStartTimestamp).toBe(mockRecords[0].testTypes[0].testTypeStartTimestamp); + expect(testFieldResults[2].testTypeStartTimestamp).toBe(mockRecords[1].testTypes[0].testTypeStartTimestamp); + }); }); diff --git a/src/app/features/tech-record/components/test-record-summary/test-record-summary.component.ts b/src/app/features/tech-record/components/test-record-summary/test-record-summary.component.ts index 6ddbbaa2de..443c28ea5a 100644 --- a/src/app/features/tech-record/components/test-record-summary/test-record-summary.component.ts +++ b/src/app/features/tech-record/components/test-record-summary/test-record-summary.component.ts @@ -1,81 +1,81 @@ -import { - ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, -} from '@angular/core'; -import { TestResultModel } from '@models/test-results/test-result.model'; -import { resultOfTestEnum } from '@models/test-types/test-type.model'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input } from '@angular/core'; import { Roles } from '@models/roles.enum'; import { TestResultStatus } from '@models/test-results/test-result-status.enum'; +import { TestResultModel } from '@models/test-results/test-result.model'; +import { resultOfTestEnum } from '@models/test-types/test-type.model'; interface TestField { - testTypeStartTimestamp: string | Date; - testTypeName: string; - testNumber: string; - testResult: resultOfTestEnum; - testResultId: string; - testResultStatus?: TestResultStatus; + testTypeStartTimestamp: string | Date; + testTypeName: string; + testNumber: string; + testResult: resultOfTestEnum; + testResultId: string; + testResultStatus?: TestResultStatus; } @Component({ - selector: 'app-test-record-summary', - templateUrl: './test-record-summary.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-test-record-summary', + templateUrl: './test-record-summary.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class TestRecordSummaryComponent { - @Input() isEditing = false; - @Input() testResults: TestResultModel[] = []; + @Input() isEditing = false; + @Input() testResults: TestResultModel[] = []; - pageStart?: number; - pageEnd?: number; + pageStart?: number; + pageEnd?: number; - constructor(private cdr: ChangeDetectorRef) {} + constructor(private cdr: ChangeDetectorRef) {} - public get roles(): typeof Roles { - return Roles; - } + public get roles(): typeof Roles { + return Roles; + } - get numberOfRecords(): number { - return this.testResults.length; - } + get numberOfRecords(): number { + return this.testResults.length; + } - get paginatedTestFields(): TestField[] { - return this.sortedTestTypeFields.slice(this.pageStart, this.pageEnd); - } + get paginatedTestFields(): TestField[] { + return this.sortedTestTypeFields.slice(this.pageStart, this.pageEnd); + } - get sortedTestTypeFields(): TestField[] { - const byDate = (a: TestField, b: TestField) => new Date(b.testTypeStartTimestamp).getTime() - new Date(a.testTypeStartTimestamp).getTime(); + get sortedTestTypeFields(): TestField[] { + const byDate = (a: TestField, b: TestField) => + new Date(b.testTypeStartTimestamp).getTime() - new Date(a.testTypeStartTimestamp).getTime(); - return this.testResults - .flatMap((record) => - record.testTypes.map((testType) => ({ - testTypeStartTimestamp: testType.testTypeStartTimestamp, - testTypeName: testType.testTypeName, - testNumber: testType.testNumber, - testResult: testType.testResult, - testResultId: record.testResultId, - testResultStatus: record.testStatus, - }))) - .sort(byDate); - } + return this.testResults + .flatMap((record) => + record.testTypes.map((testType) => ({ + testTypeStartTimestamp: testType.testTypeStartTimestamp, + testTypeName: testType.testTypeName, + testNumber: testType.testNumber, + testResult: testType.testResult, + testResultId: record.testResultId, + testResultStatus: record.testStatus, + })) + ) + .sort(byDate); + } - getResult(test: TestField): string { - return test.testResultStatus === TestResultStatus.CANCELLED ? TestResultStatus.CANCELLED : test.testResult; - } + getResult(test: TestField): string { + return test.testResultStatus === TestResultStatus.CANCELLED ? TestResultStatus.CANCELLED : test.testResult; + } - getTestTypeName(testResult: TestResultModel): string { - return testResult.testTypes.map((t) => t.testTypeName).join(','); - } + getTestTypeName(testResult: TestResultModel): string { + return testResult.testTypes.map((t) => t.testTypeName).join(','); + } - getTestTypeResults(testResult: TestResultModel): string { - return testResult.testTypes.map((t) => t.testResult).join(','); - } + getTestTypeResults(testResult: TestResultModel): string { + return testResult.testTypes.map((t) => t.testResult).join(','); + } - trackByFn(i: number, t: TestField): string { - return t.testNumber; - } + trackByFn(i: number, t: TestField): string { + return t.testNumber; + } - handlePaginationChange({ start, end }: { start: number; end: number }): void { - this.pageStart = start; - this.pageEnd = end; - this.cdr.detectChanges(); - } + handlePaginationChange({ start, end }: { start: number; end: number }): void { + this.pageStart = start; + this.pageEnd = end; + this.cdr.detectChanges(); + } } diff --git a/src/app/features/tech-record/components/test-record-summary/test-record-summary.stories.ts b/src/app/features/tech-record/components/test-record-summary/test-record-summary.stories.ts index 1fa4d530e9..d9ed212f2c 100644 --- a/src/app/features/tech-record/components/test-record-summary/test-record-summary.stories.ts +++ b/src/app/features/tech-record/components/test-record-summary/test-record-summary.stories.ts @@ -1,23 +1,28 @@ -import { Meta, Story } from '@storybook/angular'; -import { TestRecordSummaryComponent } from './test-record-summary.component'; import { mockTestResult } from '@mocks/mock-test-result'; import { TestResultModel } from '@models/test-results/test-result.model'; +import { Meta, Story } from '@storybook/angular'; +import { TestRecordSummaryComponent } from './test-record-summary.component'; const fakeRecord: TestResultModel = mockTestResult(); export default { - title: 'Test Record Summary', - component: TestRecordSummaryComponent + title: 'Test Record Summary', + component: TestRecordSummaryComponent, } as Meta; export const NoRecords: Story = () => ({ - props: {} + props: {}, }); export const Record: Story = () => ({ - props: { testRecords: [fakeRecord] } + props: { testRecords: [fakeRecord] }, }); export const Records: Story = () => ({ - props: { testRecords: [fakeRecord, { ...fakeRecord, testStartTimestamp: '2022-02-02:13.23', vin: 'xthoeu213', testStatus: 'PASSED' }] } + props: { + testRecords: [ + fakeRecord, + { ...fakeRecord, testStartTimestamp: '2022-02-02:13.23', vin: 'xthoeu213', testStatus: 'PASSED' }, + ], + }, }); diff --git a/src/app/features/tech-record/components/vehicle-technical-record/vehicle-technical-record.component.spec.ts b/src/app/features/tech-record/components/vehicle-technical-record/vehicle-technical-record.component.spec.ts index 0bd7a87c78..2d4ae4b74b 100644 --- a/src/app/features/tech-record/components/vehicle-technical-record/vehicle-technical-record.component.spec.ts +++ b/src/app/features/tech-record/components/vehicle-technical-record/vehicle-technical-record.component.spec.ts @@ -7,9 +7,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ApiModule } from '@api/test-results'; import { DynamicFormsModule } from '@forms/dynamic-forms.module'; import { MultiOptionsService } from '@forms/services/multi-options.service'; -import { - StatusCodes, TechRecordModel, V3TechRecordModel, -} from '@models/vehicle-tech-record.model'; +import { StatusCodes, TechRecordModel, V3TechRecordModel } from '@models/vehicle-tech-record.model'; import { EffectsModule } from '@ngrx/effects'; import { StoreModule } from '@ngrx/store'; import { provideMockStore } from '@ngrx/store/testing'; @@ -28,79 +26,79 @@ import { VehicleTechnicalRecordComponent } from './vehicle-technical-record.comp global.scrollTo = jest.fn(); describe('VehicleTechnicalRecordComponent', () => { - let component: VehicleTechnicalRecordComponent; - let fixture: ComponentFixture; - @Component({}) - class TechRecordSummaryStubComponent { - checkForms() {} - } + let component: VehicleTechnicalRecordComponent; + let fixture: ComponentFixture; + @Component({}) + class TechRecordSummaryStubComponent { + checkForms() {} + } - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - ApiModule, - DynamicFormsModule, - EffectsModule.forRoot(), - HttpClientTestingModule, - RouterModule.forRoot([]), - RouterTestingModule, - SharedModule, - StoreModule.forRoot({}), - ], - declarations: [ - EditTechRecordButtonComponent, - TechRecordHistoryComponent, - TechRecordSummaryComponent, - TechRecordTitleComponent, - TechRecordSummaryStubComponent, - TestRecordSummaryComponent, - VehicleTechnicalRecordComponent, - ], - providers: [ - MultiOptionsService, - provideMockStore({ initialState: initialAppState }), - { provide: APP_BASE_HREF, useValue: '/' }, - { - provide: UserService, - useValue: { - roles$: of(['TestResult.View', 'TestResult.CreateContingency']), - }, - }, - { - provide: TechnicalRecordService, - useValue: { - get techRecord$() { - return of({ - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_statusCode: StatusCodes.CURRENT, - }); - }, - updateEditingTechRecord: () => {}, - get editableTechRecord$() { - return of({ systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' }); - }, - get sectionStates$() { - return of(['TEST_SECTION']); - }, - getVehicleTypeWithSmallTrl: (techRecord: TechRecordModel) => { - return techRecord.vehicleType; - }, - }, - }, - ], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + ApiModule, + DynamicFormsModule, + EffectsModule.forRoot(), + HttpClientTestingModule, + RouterModule.forRoot([]), + RouterTestingModule, + SharedModule, + StoreModule.forRoot({}), + ], + declarations: [ + EditTechRecordButtonComponent, + TechRecordHistoryComponent, + TechRecordSummaryComponent, + TechRecordTitleComponent, + TechRecordSummaryStubComponent, + TestRecordSummaryComponent, + VehicleTechnicalRecordComponent, + ], + providers: [ + MultiOptionsService, + provideMockStore({ initialState: initialAppState }), + { provide: APP_BASE_HREF, useValue: '/' }, + { + provide: UserService, + useValue: { + roles$: of(['TestResult.View', 'TestResult.CreateContingency']), + }, + }, + { + provide: TechnicalRecordService, + useValue: { + get techRecord$() { + return of({ + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_statusCode: StatusCodes.CURRENT, + }); + }, + updateEditingTechRecord: () => {}, + get editableTechRecord$() { + return of({ systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' }); + }, + get sectionStates$() { + return of(['TEST_SECTION']); + }, + getVehicleTypeWithSmallTrl: (techRecord: TechRecordModel) => { + return techRecord.vehicleType; + }, + }, + }, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(VehicleTechnicalRecordComponent); - component = fixture.componentInstance; - component.techRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel; - }); + beforeEach(() => { + fixture = TestBed.createComponent(VehicleTechnicalRecordComponent); + component = fixture.componentInstance; + component.techRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel; + }); - it('should create', () => { - fixture.detectChanges(); - expect(component).toBeTruthy(); - }); + it('should create', () => { + fixture.detectChanges(); + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/features/tech-record/components/vehicle-technical-record/vehicle-technical-record.component.ts b/src/app/features/tech-record/components/vehicle-technical-record/vehicle-technical-record.component.ts index b00822c10b..3b3473000e 100644 --- a/src/app/features/tech-record/components/vehicle-technical-record/vehicle-technical-record.component.ts +++ b/src/app/features/tech-record/components/vehicle-technical-record/vehicle-technical-record.component.ts @@ -1,7 +1,5 @@ import { ViewportScroller } from '@angular/common'; -import { - Component, Input, OnDestroy, OnInit, ViewChild, -} from '@angular/core'; +import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; @@ -10,164 +8,166 @@ import { Roles } from '@models/roles.enum'; import { TechRecordActions } from '@models/tech-record/tech-record-actions.enum'; import { TestResultModel } from '@models/test-results/test-result.model'; import { - ReasonForEditing, StatusCodes, TechRecordModel, V3TechRecordModel, VehicleTypes, + ReasonForEditing, + StatusCodes, + TechRecordModel, + V3TechRecordModel, + VehicleTypes, } from '@models/vehicle-tech-record.model'; -import { AdrService } from '@services/adr/adr.service'; import { Actions, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; +import { AdrService } from '@services/adr/adr.service'; import { FeatureToggleService } from '@services/feature-toggle-service/feature-toggle-service'; import { TestRecordsService } from '@services/test-records/test-records.service'; import { UserService } from '@services/user-service/user-service'; import { clearScrollPosition, updateTechRecordSuccess } from '@store/technical-records'; import { TechnicalRecordServiceState } from '@store/technical-records/reducers/technical-record-service.reducer'; -import { - Observable, Subject, take, takeUntil, -} from 'rxjs'; +import { Observable, Subject, take, takeUntil } from 'rxjs'; import { TechRecordSummaryComponent } from '../tech-record-summary/tech-record-summary.component'; @Component({ - selector: 'app-vehicle-technical-record', - templateUrl: './vehicle-technical-record.component.html', - styleUrls: ['./vehicle-technical-record.component.scss'], + selector: 'app-vehicle-technical-record', + templateUrl: './vehicle-technical-record.component.html', + styleUrls: ['./vehicle-technical-record.component.scss'], }) export class VehicleTechnicalRecordComponent implements OnInit, OnDestroy { - @ViewChild(TechRecordSummaryComponent) summary!: TechRecordSummaryComponent; - @Input() techRecord?: V3TechRecordModel; - - testResults$: Observable; - editingReason?: ReasonForEditing; - recordHistory?: TechRecordSearchSchema[]; - - isCurrent = false; - isArchived = false; - isEditing = false; - isDirty = false; - isInvalid = false; - - private destroy$ = new Subject(); - hasTestResultAmend: boolean | undefined = false; - - constructor( - public globalErrorService: GlobalErrorService, - public userService: UserService, - testRecordService: TestRecordsService, - private activatedRoute: ActivatedRoute, - private route: ActivatedRoute, - private router: Router, - private store: Store, - private actions$: Actions, - private viewportScroller: ViewportScroller, - private featureToggleService: FeatureToggleService, - public adrService: AdrService, - ) { - this.testResults$ = testRecordService.testRecords$; - this.isEditing = this.activatedRoute.snapshot.data['isEditing'] ?? false; - this.editingReason = this.activatedRoute.snapshot.data['reason']; - } - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - ngOnInit(): void { - this.actions$.pipe(ofType(updateTechRecordSuccess), takeUntil(this.destroy$)).subscribe((vehicleTechRecord) => { - void this.router.navigate([ - `/tech-records/${vehicleTechRecord.vehicleTechRecord.systemNumber}/${vehicleTechRecord.vehicleTechRecord.createdTimestamp}`, - ]); - }); - this.isArchived = this.techRecord?.techRecord_statusCode === StatusCodes.ARCHIVED; - this.isCurrent = this.techRecord?.techRecord_statusCode === StatusCodes.CURRENT; - - this.userService.roles$.pipe(take(1)).subscribe((storedRoles) => { - this.hasTestResultAmend = storedRoles?.some((role) => { - return Roles.TestResultAmend.split(',').includes(role); - }); - }); - } - - get currentVrm(): string | undefined { - return this.techRecord?.techRecord_vehicleType !== 'trl' ? this.techRecord?.primaryVrm ?? '' : undefined; - } - - get roles(): typeof Roles { - return Roles; - } - - get vehicleTypes(): typeof VehicleTypes { - return VehicleTypes; - } - - get statusCodes(): typeof StatusCodes { - return StatusCodes; - } - - hasPlates(techRecord: TechRecordModel) { - return (techRecord.plates?.length ?? 0) > 0; - } - - getActions(techRecord?: V3TechRecordModel): TechRecordActions { - switch (techRecord?.techRecord_statusCode) { - case StatusCodes.CURRENT: - return TechRecordActions.CURRENT; - case StatusCodes.PROVISIONAL: - return TechRecordActions.PROVISIONAL; - case StatusCodes.ARCHIVED: - return TechRecordActions.ARCHIVED; - default: - return TechRecordActions.NONE; - } - } - - getVehicleDescription(techRecord: TechRecordModel, vehicleType: VehicleTypes | undefined): string { - switch (vehicleType) { - case VehicleTypes.TRL: - return techRecord.vehicleConfiguration ?? ''; - case VehicleTypes.PSV: - return techRecord.bodyMake && techRecord.bodyModel ? `${techRecord.bodyMake}-${techRecord.bodyModel}` : ''; - case VehicleTypes.HGV: - return techRecord.make && techRecord.model ? `${techRecord.make}-${techRecord.model}` : ''; - default: - return 'Unknown Vehicle Type'; - } - } - - showCreateTestButton(): boolean { - return !this.isArchived && !this.isEditing; - } - - async createTest(techRecord?: V3TechRecordModel): Promise { - this.store.dispatch(clearScrollPosition()); - if ( - (techRecord as TechRecordType<'get'>)?.techRecord_recordCompleteness === 'complete' - || (techRecord as TechRecordType<'get'>)?.techRecord_recordCompleteness === 'testable' - ) { - await this.router.navigate(['test-records/create-test/type'], { relativeTo: this.route }); - } else { - this.globalErrorService.setErrors([ - { - error: this.getCreateTestErrorMessage(techRecord?.techRecord_hiddenInVta ?? false), - anchorLink: 'create-test', - }, - ]); - - this.viewportScroller.scrollToPosition([0, 0]); - } - } - - async handleSubmit(): Promise { - this.summary.checkForms(); - if (this.isInvalid) return; - - await this.router.navigate(['change-summary'], { relativeTo: this.route }); - } - - private getCreateTestErrorMessage(hiddenInVta: boolean | undefined): string { - if (hiddenInVta) { - return 'Vehicle record is hidden in VTA. Show the vehicle record in VTA to start recording tests against it.'; - } - - return this.hasTestResultAmend - ? 'This vehicle does not have enough information to be tested. Please complete this record so tests can be recorded against it.' - : 'This vehicle does not have enough information to be tested.' - + ' Call the Contact Centre to complete this record so tests can be recorded against it.'; - } + @ViewChild(TechRecordSummaryComponent) summary!: TechRecordSummaryComponent; + @Input() techRecord?: V3TechRecordModel; + + testResults$: Observable; + editingReason?: ReasonForEditing; + recordHistory?: TechRecordSearchSchema[]; + + isCurrent = false; + isArchived = false; + isEditing = false; + isDirty = false; + isInvalid = false; + + private destroy$ = new Subject(); + hasTestResultAmend: boolean | undefined = false; + + constructor( + public globalErrorService: GlobalErrorService, + public userService: UserService, + testRecordService: TestRecordsService, + private activatedRoute: ActivatedRoute, + private route: ActivatedRoute, + private router: Router, + private store: Store, + private actions$: Actions, + private viewportScroller: ViewportScroller, + private featureToggleService: FeatureToggleService, + public adrService: AdrService + ) { + this.testResults$ = testRecordService.testRecords$; + this.isEditing = this.activatedRoute.snapshot.data['isEditing'] ?? false; + this.editingReason = this.activatedRoute.snapshot.data['reason']; + } + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + ngOnInit(): void { + this.actions$.pipe(ofType(updateTechRecordSuccess), takeUntil(this.destroy$)).subscribe((vehicleTechRecord) => { + void this.router.navigate([ + `/tech-records/${vehicleTechRecord.vehicleTechRecord.systemNumber}/${vehicleTechRecord.vehicleTechRecord.createdTimestamp}`, + ]); + }); + this.isArchived = this.techRecord?.techRecord_statusCode === StatusCodes.ARCHIVED; + this.isCurrent = this.techRecord?.techRecord_statusCode === StatusCodes.CURRENT; + + this.userService.roles$.pipe(take(1)).subscribe((storedRoles) => { + this.hasTestResultAmend = storedRoles?.some((role) => { + return Roles.TestResultAmend.split(',').includes(role); + }); + }); + } + + get currentVrm(): string | undefined { + return this.techRecord?.techRecord_vehicleType !== 'trl' ? this.techRecord?.primaryVrm ?? '' : undefined; + } + + get roles(): typeof Roles { + return Roles; + } + + get vehicleTypes(): typeof VehicleTypes { + return VehicleTypes; + } + + get statusCodes(): typeof StatusCodes { + return StatusCodes; + } + + hasPlates(techRecord: TechRecordModel) { + return (techRecord.plates?.length ?? 0) > 0; + } + + getActions(techRecord?: V3TechRecordModel): TechRecordActions { + switch (techRecord?.techRecord_statusCode) { + case StatusCodes.CURRENT: + return TechRecordActions.CURRENT; + case StatusCodes.PROVISIONAL: + return TechRecordActions.PROVISIONAL; + case StatusCodes.ARCHIVED: + return TechRecordActions.ARCHIVED; + default: + return TechRecordActions.NONE; + } + } + + getVehicleDescription(techRecord: TechRecordModel, vehicleType: VehicleTypes | undefined): string { + switch (vehicleType) { + case VehicleTypes.TRL: + return techRecord.vehicleConfiguration ?? ''; + case VehicleTypes.PSV: + return techRecord.bodyMake && techRecord.bodyModel ? `${techRecord.bodyMake}-${techRecord.bodyModel}` : ''; + case VehicleTypes.HGV: + return techRecord.make && techRecord.model ? `${techRecord.make}-${techRecord.model}` : ''; + default: + return 'Unknown Vehicle Type'; + } + } + + showCreateTestButton(): boolean { + return !this.isArchived && !this.isEditing; + } + + async createTest(techRecord?: V3TechRecordModel): Promise { + this.store.dispatch(clearScrollPosition()); + if ( + (techRecord as TechRecordType<'get'>)?.techRecord_recordCompleteness === 'complete' || + (techRecord as TechRecordType<'get'>)?.techRecord_recordCompleteness === 'testable' + ) { + await this.router.navigate(['test-records/create-test/type'], { relativeTo: this.route }); + } else { + this.globalErrorService.setErrors([ + { + error: this.getCreateTestErrorMessage(techRecord?.techRecord_hiddenInVta ?? false), + anchorLink: 'create-test', + }, + ]); + + this.viewportScroller.scrollToPosition([0, 0]); + } + } + + async handleSubmit(): Promise { + this.summary.checkForms(); + if (this.isInvalid) return; + + await this.router.navigate(['change-summary'], { relativeTo: this.route }); + } + + private getCreateTestErrorMessage(hiddenInVta: boolean | undefined): string { + if (hiddenInVta) { + return 'Vehicle record is hidden in VTA. Show the vehicle record in VTA to start recording tests against it.'; + } + + return this.hasTestResultAmend + ? 'This vehicle does not have enough information to be tested. Please complete this record so tests can be recorded against it.' + : 'This vehicle does not have enough information to be tested.' + + ' Call the Contact Centre to complete this record so tests can be recorded against it.'; + } } diff --git a/src/app/features/tech-record/components/vehicle-technical-record/vehicle-technical-record.stories.ts b/src/app/features/tech-record/components/vehicle-technical-record/vehicle-technical-record.stories.ts index 1e0a385fc4..eea6fcd914 100644 --- a/src/app/features/tech-record/components/vehicle-technical-record/vehicle-technical-record.stories.ts +++ b/src/app/features/tech-record/components/vehicle-technical-record/vehicle-technical-record.stories.ts @@ -3,15 +3,15 @@ import { Meta, Story } from '@storybook/angular'; import { VehicleTechnicalRecordComponent } from './vehicle-technical-record.component'; export default { - title: 'Vehicle Tech Record', - component: VehicleTechnicalRecordComponent + title: 'Vehicle Tech Record', + component: VehicleTechnicalRecordComponent, } as Meta; -const Template: Story = args => ({ - props: args +const Template: Story = (args) => ({ + props: args, }); export const Primary = Template.bind({}); Primary.args = { - vehicleTechRecord: mockVehicleTechnicalRecord() + vehicleTechRecord: mockVehicleTechnicalRecord(), }; diff --git a/src/app/features/tech-record/create-batch/components/batch-vehicle-details/batch-vehicle-details.component.spec.ts b/src/app/features/tech-record/create-batch/components/batch-vehicle-details/batch-vehicle-details.component.spec.ts index adb11ee264..593c04fd5e 100644 --- a/src/app/features/tech-record/create-batch/components/batch-vehicle-details/batch-vehicle-details.component.spec.ts +++ b/src/app/features/tech-record/create-batch/components/batch-vehicle-details/batch-vehicle-details.component.spec.ts @@ -11,52 +11,57 @@ import { of } from 'rxjs'; import { BatchVehicleDetailsComponent } from './batch-vehicle-details.component'; const mockGlobalErrorService = { - addError: jest.fn(), - clearErrors: jest.fn(), - setErrors: jest.fn(), + addError: jest.fn(), + clearErrors: jest.fn(), + setErrors: jest.fn(), }; describe('BatchVehicleDetailsComponent', () => { - let component: BatchVehicleDetailsComponent; - let fixture: ComponentFixture; + let component: BatchVehicleDetailsComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [BatchVehicleDetailsComponent], - imports: [DynamicFormsModule, ReactiveFormsModule, HttpClientTestingModule, RouterTestingModule, SharedModule], - providers: [FormBuilder, { provide: GlobalErrorService, useValue: mockGlobalErrorService }, - provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BatchVehicleDetailsComponent], + imports: [DynamicFormsModule, ReactiveFormsModule, HttpClientTestingModule, RouterTestingModule, SharedModule], + providers: [ + FormBuilder, + { provide: GlobalErrorService, useValue: mockGlobalErrorService }, + provideMockStore({ initialState: initialAppState }), + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(BatchVehicleDetailsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(BatchVehicleDetailsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - describe('isFormValid', () => { - it('should throw an error if there are no vehicles', async () => { - jest.spyOn(component, 'formStatus', 'get').mockImplementationOnce(() => of('VALID')); - component.vehicles.push(component.vehicleForm); - component.vehicleForm.get('vin')?.clearAsyncValidators(); + describe('isFormValid', () => { + it('should throw an error if there are no vehicles', async () => { + jest.spyOn(component, 'formStatus', 'get').mockImplementationOnce(() => of('VALID')); + component.vehicles.push(component.vehicleForm); + component.vehicleForm.get('vin')?.clearAsyncValidators(); - await component.isFormValid(); - component.vehicleForm.updateValueAndValidity(); - expect(mockGlobalErrorService.addError).toHaveBeenCalledWith({ error: 'At least 1 vehicle must be created or updated in a batch' }); - }); - }); + await component.isFormValid(); + component.vehicleForm.updateValueAndValidity(); + expect(mockGlobalErrorService.addError).toHaveBeenCalledWith({ + error: 'At least 1 vehicle must be created or updated in a batch', + }); + }); + }); - describe('checkDuplicateVins', () => { - it('should return duplicate vins and their indexes', () => { - const arr = [{ vin: '123' }, { vin: '123' }, { vin: '123' }, { vin: '' }, { vin: '' }]; - expect(component.checkDuplicateVins(arr)).toStrictEqual([ - { vin: '123', anchor: 1 }, - { vin: '123', anchor: 2 }, - ]); - }); - }); + describe('checkDuplicateVins', () => { + it('should return duplicate vins and their indexes', () => { + const arr = [{ vin: '123' }, { vin: '123' }, { vin: '123' }, { vin: '' }, { vin: '' }]; + expect(component.checkDuplicateVins(arr)).toStrictEqual([ + { vin: '123', anchor: 1 }, + { vin: '123', anchor: 2 }, + ]); + }); + }); }); diff --git a/src/app/features/tech-record/create-batch/components/batch-vehicle-details/batch-vehicle-details.component.ts b/src/app/features/tech-record/create-batch/components/batch-vehicle-details/batch-vehicle-details.component.ts index 60914ad722..fc9f6c7cb2 100644 --- a/src/app/features/tech-record/create-batch/components/batch-vehicle-details/batch-vehicle-details.component.ts +++ b/src/app/features/tech-record/create-batch/components/batch-vehicle-details/batch-vehicle-details.component.ts @@ -1,193 +1,200 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; -import { - AbstractControl, FormArray, FormBuilder, FormControlStatus, FormGroup, Validators, -} from '@angular/forms'; +import { AbstractControl, FormArray, FormBuilder, FormControlStatus, FormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalError } from '@core/components/global-error/global-error.interface'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; import { - CustomFormControl, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + CustomFormControl, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; import { CustomValidators } from '@forms/validators/custom-validators'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { BatchTechnicalRecordService } from '@services/batch-technical-record/batch-technical-record.service'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; -import { - Observable, Subject, combineLatest, filter, firstValueFrom, take, -} from 'rxjs'; +import { Observable, Subject, combineLatest, filter, firstValueFrom, take } from 'rxjs'; @Component({ - selector: 'app-batch-vehicle-details', - templateUrl: './batch-vehicle-details.component.html', - styleUrls: ['./batch-vehicle-details.component.scss'], + selector: 'app-batch-vehicle-details', + templateUrl: './batch-vehicle-details.component.html', + styleUrls: ['./batch-vehicle-details.component.scss'], }) export class BatchVehicleDetailsComponent implements OnInit, OnDestroy { - form: FormGroup; - vehicleType?: VehicleTypes; - readonly maxNumberOfVehicles = 40; - - private destroy$ = new Subject(); - - constructor( - private fb: FormBuilder, - private globalErrorService: GlobalErrorService, - private router: Router, - private route: ActivatedRoute, - private technicalRecordService: TechnicalRecordService, - private batchTechRecordService: BatchTechnicalRecordService, - ) { - this.form = this.fb.group({ - vehicles: this.fb.array([]), - applicationId: new CustomFormControl({ name: 'applicationId', label: 'Application ID', type: FormNodeTypes.CONTROL }, null, [ - Validators.required, - ]), - }); - - this.technicalRecordService.techRecord$.pipe(take(1)).subscribe((vehicle) => { - if (!vehicle) return this.back(); - }); - - this.batchTechRecordService.vehicleType$.pipe(take(1)).subscribe((vehicleType) => { - this.vehicleType = vehicleType; - }); - } - ngOnInit(): void { - this.addVehicles(this.maxNumberOfVehicles); - combineLatest([this.batchTechRecordService.batchVehicles$, this.batchTechRecordService.applicationId$]) - .pipe(take(1)) - .subscribe(([vehicles, applicationId]) => { - if (this.form && vehicles.length) { - this.form.patchValue({ vehicles, applicationId }); - } - }); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - get vehicles(): FormArray { - return this.form.get('vehicles') as FormArray; - } - - get generateNumber$(): Observable { - return this.batchTechRecordService.generateNumber$; - } - - get filledVinsInForm() { - return this.vehicles.value ?? []; - } - - get width(): typeof FormNodeWidth { - return FormNodeWidth; - } - - get vehicleForm(): FormGroup { - return this.fb.group({ - vin: new CustomFormControl( - { name: 'vin', type: FormNodeTypes.CONTROL }, - null, - [CustomValidators.alphanumeric(), Validators.minLength(3), Validators.maxLength(21)], - this.batchTechRecordService.validateForBatch(), - ), - trailerIdOrVrm: new CustomFormControl({ name: 'trailerIdOrVrm', type: FormNodeTypes.CONTROL }, '', [ - CustomValidators.validateVRMTrailerIdLength('vehicleType'), - CustomValidators.alphanumeric(), - ]), - vehicleType: new CustomFormControl( - { - name: 'change-vehicle-type-select', - label: 'Vehicle type', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - this.vehicleType, - ), - createdTimestamp: [''], - systemNumber: [''], - }); - } - - validate(group: AbstractControl): void { - group.get('vin')?.updateValueAndValidity(); - } - - getVinControl(group: AbstractControl): CustomFormControl | null { - return group.get('vin') as CustomFormControl | null; - } - - addVehicles(n: number): void { - for (let i = 0; i < n; i++) { - this.vehicles.push(this.vehicleForm); - } - } - - showErrors(): void { - const errors: GlobalError[] = []; - DynamicFormService.validate(this.form, errors, false); - this.globalErrorService.setErrors(errors); - } - - back(): void { - void this.router.navigate(['..'], { relativeTo: this.route }); - } - - async handleSubmit(): Promise { - const valid = await this.isFormValid(); - if (!valid) return; - - this.globalErrorService.setErrors([]); - this.batchTechRecordService.setApplicationId(this.form.get('applicationId')?.value); - this.batchTechRecordService.upsertVehicleBatch(this.cleanEmptyValues(this.vehicles.value)); - this.back(); - } - - private cleanEmptyValues(input: { vin: string; trailerIdOrVrm?: string }[]): { vin: string; trailerIdOrVrm?: string }[] { - return input.filter((formInput) => !!formInput.vin); - } - - public checkDuplicateVins(input: { vin: string }[]) { - const vinArray = input.map((item) => item.vin); - const duplicates: { vin: string; anchor: number }[] = []; - vinArray.forEach((item, index) => { - if (!!item && vinArray.indexOf(item) !== index) { - duplicates.push({ vin: item, anchor: index }); - } - }); - return duplicates; - } - - async isFormValid(): Promise { - this.globalErrorService.clearErrors(); - this.form.markAllAsTouched(); - - const errors: GlobalError[] = []; - - DynamicFormService.validate(this.form, errors, true); - await firstValueFrom(this.formStatus); - - if (errors?.length) { - this.globalErrorService.setErrors(errors); - } - - if (this.cleanEmptyValues(this.vehicles.value).length === 0) { - this.globalErrorService.addError({ error: 'At least 1 vehicle must be created or updated in a batch' }); - return false; - } - const duplicates = this.checkDuplicateVins(this.vehicles.value); - if (duplicates.length > 0) { - duplicates.forEach((element) => { - this.globalErrorService.addError({ error: `Remove duplicate VIN - ${element.vin}`, anchorLink: `input-vin${element.anchor.toString()}` }); - }); - return false; - } - return this.form.valid; - } - - get formStatus(): Observable { - return this.form.statusChanges.pipe(filter((status) => status !== 'PENDING')); - } + form: FormGroup; + vehicleType?: VehicleTypes; + readonly maxNumberOfVehicles = 40; + + private destroy$ = new Subject(); + + constructor( + private fb: FormBuilder, + private globalErrorService: GlobalErrorService, + private router: Router, + private route: ActivatedRoute, + private technicalRecordService: TechnicalRecordService, + private batchTechRecordService: BatchTechnicalRecordService + ) { + this.form = this.fb.group({ + vehicles: this.fb.array([]), + applicationId: new CustomFormControl( + { name: 'applicationId', label: 'Application ID', type: FormNodeTypes.CONTROL }, + null, + [Validators.required] + ), + }); + + this.technicalRecordService.techRecord$.pipe(take(1)).subscribe((vehicle) => { + if (!vehicle) return this.back(); + }); + + this.batchTechRecordService.vehicleType$.pipe(take(1)).subscribe((vehicleType) => { + this.vehicleType = vehicleType; + }); + } + ngOnInit(): void { + this.addVehicles(this.maxNumberOfVehicles); + combineLatest([this.batchTechRecordService.batchVehicles$, this.batchTechRecordService.applicationId$]) + .pipe(take(1)) + .subscribe(([vehicles, applicationId]) => { + if (this.form && vehicles.length) { + this.form.patchValue({ vehicles, applicationId }); + } + }); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + get vehicles(): FormArray { + return this.form.get('vehicles') as FormArray; + } + + get generateNumber$(): Observable { + return this.batchTechRecordService.generateNumber$; + } + + get filledVinsInForm() { + return this.vehicles.value ?? []; + } + + get width(): typeof FormNodeWidth { + return FormNodeWidth; + } + + get vehicleForm(): FormGroup { + return this.fb.group({ + vin: new CustomFormControl( + { name: 'vin', type: FormNodeTypes.CONTROL }, + null, + [CustomValidators.alphanumeric(), Validators.minLength(3), Validators.maxLength(21)], + this.batchTechRecordService.validateForBatch() + ), + trailerIdOrVrm: new CustomFormControl({ name: 'trailerIdOrVrm', type: FormNodeTypes.CONTROL }, '', [ + CustomValidators.validateVRMTrailerIdLength('vehicleType'), + CustomValidators.alphanumeric(), + ]), + vehicleType: new CustomFormControl( + { + name: 'change-vehicle-type-select', + label: 'Vehicle type', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + this.vehicleType + ), + createdTimestamp: [''], + systemNumber: [''], + }); + } + + validate(group: AbstractControl): void { + group.get('vin')?.updateValueAndValidity(); + } + + getVinControl(group: AbstractControl): CustomFormControl | null { + return group.get('vin') as CustomFormControl | null; + } + + addVehicles(n: number): void { + for (let i = 0; i < n; i++) { + this.vehicles.push(this.vehicleForm); + } + } + + showErrors(): void { + const errors: GlobalError[] = []; + DynamicFormService.validate(this.form, errors, false); + this.globalErrorService.setErrors(errors); + } + + back(): void { + void this.router.navigate(['..'], { relativeTo: this.route }); + } + + async handleSubmit(): Promise { + const valid = await this.isFormValid(); + if (!valid) return; + + this.globalErrorService.setErrors([]); + this.batchTechRecordService.setApplicationId(this.form.get('applicationId')?.value); + this.batchTechRecordService.upsertVehicleBatch(this.cleanEmptyValues(this.vehicles.value)); + this.back(); + } + + private cleanEmptyValues( + input: { vin: string; trailerIdOrVrm?: string }[] + ): { vin: string; trailerIdOrVrm?: string }[] { + return input.filter((formInput) => !!formInput.vin); + } + + public checkDuplicateVins(input: { vin: string }[]) { + const vinArray = input.map((item) => item.vin); + const duplicates: { vin: string; anchor: number }[] = []; + vinArray.forEach((item, index) => { + if (!!item && vinArray.indexOf(item) !== index) { + duplicates.push({ vin: item, anchor: index }); + } + }); + return duplicates; + } + + async isFormValid(): Promise { + this.globalErrorService.clearErrors(); + this.form.markAllAsTouched(); + + const errors: GlobalError[] = []; + + DynamicFormService.validate(this.form, errors, true); + await firstValueFrom(this.formStatus); + + if (errors?.length) { + this.globalErrorService.setErrors(errors); + } + + if (this.cleanEmptyValues(this.vehicles.value).length === 0) { + this.globalErrorService.addError({ error: 'At least 1 vehicle must be created or updated in a batch' }); + return false; + } + const duplicates = this.checkDuplicateVins(this.vehicles.value); + if (duplicates.length > 0) { + duplicates.forEach((element) => { + this.globalErrorService.addError({ + error: `Remove duplicate VIN - ${element.vin}`, + anchorLink: `input-vin${element.anchor.toString()}`, + }); + }); + return false; + } + return this.form.valid; + } + + get formStatus(): Observable { + return this.form.statusChanges.pipe(filter((status) => status !== 'PENDING')); + } } diff --git a/src/app/features/tech-record/create-batch/components/batch-vehicle-results/batch-vehicle-results.component.spec.ts b/src/app/features/tech-record/create-batch/components/batch-vehicle-results/batch-vehicle-results.component.spec.ts index d101bdc626..e0a32f5ab3 100644 --- a/src/app/features/tech-record/create-batch/components/batch-vehicle-results/batch-vehicle-results.component.spec.ts +++ b/src/app/features/tech-record/create-batch/components/batch-vehicle-results/batch-vehicle-results.component.spec.ts @@ -8,36 +8,36 @@ import { SharedModule } from '@shared/shared.module'; import { BatchVehicleResultsComponent } from './batch-vehicle-results.component'; describe('BatchVehicleResultsComponent', () => { - let component: BatchVehicleResultsComponent; - let fixture: ComponentFixture; + let component: BatchVehicleResultsComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule, SharedModule], - declarations: [BatchVehicleResultsComponent], - providers: [provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [HttpClientTestingModule, RouterTestingModule, SharedModule], + declarations: [BatchVehicleResultsComponent], + providers: [provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(BatchVehicleResultsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(BatchVehicleResultsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it('should expose relevant observables', () => { - expect(component.batchCount$).toBeTruthy(); - expect(component.batchSuccessCount$).toBeTruthy(); - expect(component.batchCreatedCount$).toBeTruthy(); - expect(component.batchTotalCreatedCount$).toBeTruthy(); - expect(component.batchUpdatedCount$).toBeTruthy(); - expect(component.batchTotalUpdatedCount$).toBeTruthy(); - expect(component.applicationId$).toBeTruthy(); - expect(component.batchVehiclesSuccess$).toBeTruthy(); - expect(component.vehicleType$).toBeTruthy(); - }); + it('should expose relevant observables', () => { + expect(component.batchCount$).toBeTruthy(); + expect(component.batchSuccessCount$).toBeTruthy(); + expect(component.batchCreatedCount$).toBeTruthy(); + expect(component.batchTotalCreatedCount$).toBeTruthy(); + expect(component.batchUpdatedCount$).toBeTruthy(); + expect(component.batchTotalUpdatedCount$).toBeTruthy(); + expect(component.applicationId$).toBeTruthy(); + expect(component.batchVehiclesSuccess$).toBeTruthy(); + expect(component.vehicleType$).toBeTruthy(); + }); }); diff --git a/src/app/features/tech-record/create-batch/components/batch-vehicle-results/batch-vehicle-results.component.ts b/src/app/features/tech-record/create-batch/components/batch-vehicle-results/batch-vehicle-results.component.ts index 598763eac4..0792040f63 100644 --- a/src/app/features/tech-record/create-batch/components/batch-vehicle-results/batch-vehicle-results.component.ts +++ b/src/app/features/tech-record/create-batch/components/batch-vehicle-results/batch-vehicle-results.component.ts @@ -3,86 +3,84 @@ import { ActivatedRoute, Router } from '@angular/router'; import { StatusCodes } from '@models/vehicle-tech-record.model'; import { BatchTechnicalRecordService } from '@services/batch-technical-record/batch-technical-record.service'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; -import { - Subject, filter, race, take, withLatestFrom, -} from 'rxjs'; +import { Subject, filter, race, take, withLatestFrom } from 'rxjs'; @Component({ - selector: 'app-batch-vehicle-results', - templateUrl: './batch-vehicle-results.component.html', + selector: 'app-batch-vehicle-results', + templateUrl: './batch-vehicle-results.component.html', }) export class BatchVehicleResultsComponent implements OnDestroy { - private destroy$ = new Subject(); + private destroy$ = new Subject(); - constructor( - private technicalRecordService: TechnicalRecordService, - private router: Router, - private route: ActivatedRoute, - private batchTechRecordService: BatchTechnicalRecordService, - ) { - this.batchTechRecordService.batchCount$.pipe(take(1)).subscribe((count) => { - if (!count) { - void this.router.navigate(['../..'], { relativeTo: this.route }); - } - }); + constructor( + private technicalRecordService: TechnicalRecordService, + private router: Router, + private route: ActivatedRoute, + private batchTechRecordService: BatchTechnicalRecordService + ) { + this.batchTechRecordService.batchCount$.pipe(take(1)).subscribe((count) => { + if (!count) { + void this.router.navigate(['../..'], { relativeTo: this.route }); + } + }); - race( - this.batchTechRecordService.batchCount$.pipe( - withLatestFrom(this.batchTechRecordService.batchCreatedCount$, this.batchTechRecordService.batchUpdatedCount$), - filter(([total, created, updated]) => total === created + updated), - ), - this.destroy$, - ) - .pipe(take(1)) - .subscribe(() => { - this.technicalRecordService.clearEditingTechRecord(); - }); - } + race( + this.batchTechRecordService.batchCount$.pipe( + withLatestFrom(this.batchTechRecordService.batchCreatedCount$, this.batchTechRecordService.batchUpdatedCount$), + filter(([total, created, updated]) => total === created + updated) + ), + this.destroy$ + ) + .pipe(take(1)) + .subscribe(() => { + this.technicalRecordService.clearEditingTechRecord(); + }); + } - ngOnDestroy(): void { - this.batchTechRecordService.clearBatch(); - this.technicalRecordService.clearSectionTemplateStates(); - this.destroy$.next(); - this.destroy$.complete(); - } + ngOnDestroy(): void { + this.batchTechRecordService.clearBatch(); + this.technicalRecordService.clearSectionTemplateStates(); + this.destroy$.next(); + this.destroy$.complete(); + } - get vehicleType$() { - return this.batchTechRecordService.vehicleType$; - } + get vehicleType$() { + return this.batchTechRecordService.vehicleType$; + } - get applicationId$() { - return this.batchTechRecordService.applicationId$; - } + get applicationId$() { + return this.batchTechRecordService.applicationId$; + } - get batchVehiclesSuccess$() { - return this.batchTechRecordService.batchVehiclesSuccess$; - } + get batchVehiclesSuccess$() { + return this.batchTechRecordService.batchVehiclesSuccess$; + } - get vehicleStatus() { - return StatusCodes; - } + get vehicleStatus() { + return StatusCodes; + } - get batchCount$() { - return this.batchTechRecordService.batchCount$; - } + get batchCount$() { + return this.batchTechRecordService.batchCount$; + } - get batchSuccessCount$() { - return this.batchTechRecordService.batchSuccessCount$; - } + get batchSuccessCount$() { + return this.batchTechRecordService.batchSuccessCount$; + } - get batchTotalCreatedCount$() { - return this.batchTechRecordService.batchTotalCreatedCount$; - } + get batchTotalCreatedCount$() { + return this.batchTechRecordService.batchTotalCreatedCount$; + } - get batchTotalUpdatedCount$() { - return this.batchTechRecordService.batchTotalUpdatedCount$; - } + get batchTotalUpdatedCount$() { + return this.batchTechRecordService.batchTotalUpdatedCount$; + } - get batchCreatedCount$() { - return this.batchTechRecordService.batchCreatedCount$; - } + get batchCreatedCount$() { + return this.batchTechRecordService.batchCreatedCount$; + } - get batchUpdatedCount$() { - return this.batchTechRecordService.batchUpdatedCount$; - } + get batchUpdatedCount$() { + return this.batchTechRecordService.batchUpdatedCount$; + } } diff --git a/src/app/features/tech-record/create-batch/components/batch-vehicle-template/batch-vehicle-template.component.spec.ts b/src/app/features/tech-record/create-batch/components/batch-vehicle-template/batch-vehicle-template.component.spec.ts index 1db33d5d9a..c2b59435e8 100644 --- a/src/app/features/tech-record/create-batch/components/batch-vehicle-template/batch-vehicle-template.component.spec.ts +++ b/src/app/features/tech-record/create-batch/components/batch-vehicle-template/batch-vehicle-template.component.spec.ts @@ -1,8 +1,6 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { Component } from '@angular/core'; -import { - ComponentFixture, fakeAsync, TestBed, tick, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; @@ -11,7 +9,7 @@ import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { BatchTechnicalRecordService } from '@services/batch-technical-record/batch-technical-record.service'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { FixNavigationTriggeredOutsideAngularZoneNgModule } from '@shared/custom-module/fixNgZoneError'; -import { initialAppState, State } from '@store/.'; +import { State, initialAppState } from '@store/.'; import { createVehicleRecord, updateTechRecord } from '@store/technical-records'; import { BatchRecord } from '@store/technical-records/reducers/batch-create.reducer'; import { of } from 'rxjs'; @@ -22,199 +20,212 @@ import { BatchVehicleTemplateComponent } from './batch-vehicle-template.componen let batchOfVehicles: BatchRecord[] = []; const mockTechRecordService = ({ - editableVehicleTechRecord$: of({ techRecord: [] }), - updateEditingTechRecord: jest.fn(), - createVehicleRecord: jest.fn(), - clearSectionTemplateStates: jest.fn(), + editableVehicleTechRecord$: of({ techRecord: [] }), + updateEditingTechRecord: jest.fn(), + createVehicleRecord: jest.fn(), + clearSectionTemplateStates: jest.fn(), }) as TechnicalRecordService; const mockBatchTechRecordService = ({ - get batchVehicles$() { - return of(batchOfVehicles); - }, - applicationId$: of('TES_1_APPLICATION_ID'), - isBatchCreate$: of(true), - batchCount$: of(2), - vehicleType$: of(VehicleTypes.TRL), - get vehicleStatus$() { - return of('current'); - }, + get batchVehicles$() { + return of(batchOfVehicles); + }, + applicationId$: of('TES_1_APPLICATION_ID'), + isBatchCreate$: of(true), + batchCount$: of(2), + vehicleType$: of(VehicleTypes.TRL), + get vehicleStatus$() { + return of('current'); + }, }) as BatchTechnicalRecordService; @Component({}) class TechRecordSummaryStubComponent { - checkForms() {} + checkForms() {} } describe('BatchVehicleTemplateComponent', () => { - let component: BatchVehicleTemplateComponent; - let fixture: ComponentFixture; - let store: MockStore; - let router: Router; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - RouterTestingModule.withRoutes([{ path: 'batch-results', component: BatchVehicleResultsComponent }]), - HttpClientTestingModule, - FixNavigationTriggeredOutsideAngularZoneNgModule, - ], - declarations: [BatchVehicleTemplateComponent, TechRecordSummaryStubComponent], - providers: [ - GlobalErrorService, - provideMockStore({ initialState: initialAppState }), - { provide: TechnicalRecordService, useValue: mockTechRecordService }, - { provide: BatchTechnicalRecordService, useValue: mockBatchTechRecordService }, - ], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(BatchVehicleTemplateComponent); - store = TestBed.inject(MockStore); - router = TestBed.inject(Router); - component = fixture.componentInstance; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - // TODO V3 HGV PSV TRL - it('should expose the editableVehicleTechRecord$ observable', () => { - expect(component.vehicle$).toBeTruthy(); - }); - - it('should expose the applicationId$ observable', () => { - expect(component.applicationId$).toBeTruthy(); - }); - - it('should expose the isBatch$ observable', () => { - expect(component.isBatch$).toBeTruthy(); - }); - - it('should expose the batchCount$ observable', () => { - expect(component.batchCount$).toBeTruthy(); - }); - - it('should expose the vehicleType$ observable', () => { - expect(component.vehicleType$).toBeTruthy(); - }); - - describe('should dispatch the createVehicleTechRecord action for every vin and trailerId given', () => { - beforeEach(() => { - component.summary = TestBed.createComponent(TechRecordSummaryStubComponent).componentInstance as TechRecordSummaryComponent; - }); - - it('given a batch of 0', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch').mockImplementation(); - jest.spyOn(component, 'isVehicleStatusValid', 'get').mockReturnValue(true); - component.handleSubmit(); - expect(dispatchSpy).toHaveBeenCalledTimes(0); - }); - - it('given a batch of 2 vehicles to create', () => { - batchOfVehicles = [{ vin: 'EXAMPLEVIN000001' }, { vin: 'EXAMPLEVIN000002' }]; - - const dispatchSpy = jest.spyOn(store, 'dispatch').mockImplementation(); - jest.spyOn(component, 'isVehicleStatusValid', 'get').mockReturnValue(true); - component.handleSubmit(); - expect(dispatchSpy).toHaveBeenCalledTimes(2); - }); - - it('given a batch of 2 vehicles to update', fakeAsync(() => { - jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - batchOfVehicles = [ - { - vin: 'EXAMPLEVIN000001', trailerIdOrVrm: '1000001', systemNumber: '1', createdTimestamp: 'foobar', - }, - { - vin: 'EXAMPLEVIN000002', trailerIdOrVrm: '1000002', systemNumber: '2', createdTimestamp: '2022', - }, - ]; - jest.spyOn(mockBatchTechRecordService, 'batchVehicles$', 'get').mockReturnValue(of(batchOfVehicles)); - - jest.spyOn(component, 'isVehicleStatusValid', 'get').mockReturnValue(true); - - const dispatchSpy = jest.spyOn(store, 'dispatch').mockImplementation(); - component.handleSubmit(); - - tick(); - - expect(dispatchSpy).toHaveBeenCalledTimes(2); - expect(dispatchSpy).toHaveBeenNthCalledWith( - 1, - updateTechRecord({ - systemNumber: '1', - createdTimestamp: 'foobar', - }), - ); - - expect(dispatchSpy).toHaveBeenNthCalledWith( - 2, - updateTechRecord({ - systemNumber: '2', - createdTimestamp: '2022', - }), - ); - })); - - it('given a batch of 5 vehicles to create and update', fakeAsync(() => { - jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - batchOfVehicles = [ - { - vin: 'EXAMPLEVIN000001', trailerIdOrVrm: '1000001', systemNumber: '1', createdTimestamp: '2022', - }, - { vin: 'EXAMPLEVIN000002' }, - { - vin: 'EXAMPLEVIN000003', trailerIdOrVrm: '1000002', systemNumber: '3', createdTimestamp: '2023', - }, - { vin: 'EXAMPLEVIN000004' }, - { vin: 'EXAMPLEVIN000005' }, - ]; - - jest.spyOn(mockBatchTechRecordService, 'batchVehicles$', 'get').mockReturnValue(of(batchOfVehicles)); - jest.spyOn(component, 'isVehicleStatusValid', 'get').mockReturnValue(true); - const dispatchSpy = jest.spyOn(store, 'dispatch').mockImplementation(); - component.handleSubmit(); - - tick(); - - expect(dispatchSpy).toHaveBeenCalledTimes(5); - expect(dispatchSpy).toHaveBeenNthCalledWith( - 1, - updateTechRecord({ - systemNumber: '1', - createdTimestamp: '2022', - }), - ); - expect(dispatchSpy).toHaveBeenNthCalledWith(2, createVehicleRecord({ vehicle: expect.anything() })); - expect(dispatchSpy).toHaveBeenNthCalledWith( - 3, - updateTechRecord({ - systemNumber: '3', - createdTimestamp: '2023', - }), - ); - expect(dispatchSpy).toHaveBeenNthCalledWith(4, createVehicleRecord({ vehicle: expect.anything() })); - expect(dispatchSpy).toHaveBeenNthCalledWith(5, createVehicleRecord({ vehicle: expect.anything() })); - })); - - it('given a batch of 40', fakeAsync(() => { - jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - batchOfVehicles = []; - for (let i = 1; i <= 40; i++) { - batchOfVehicles.push({ vin: `EXAMPLEVIN0000${i}`, trailerIdOrVrm: `100000${i}` }); - } - - jest.spyOn(mockBatchTechRecordService, 'batchVehicles$', 'get').mockReturnValue(of(batchOfVehicles)); - jest.spyOn(component, 'isVehicleStatusValid', 'get').mockReturnValue(true); - - const dispatchSpy = jest.spyOn(store, 'dispatch').mockImplementation(); - component.handleSubmit(); - tick(); - expect(dispatchSpy).toHaveBeenCalledTimes(40); - })); - }); + let component: BatchVehicleTemplateComponent; + let fixture: ComponentFixture; + let store: MockStore; + let router: Router; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + RouterTestingModule.withRoutes([{ path: 'batch-results', component: BatchVehicleResultsComponent }]), + HttpClientTestingModule, + FixNavigationTriggeredOutsideAngularZoneNgModule, + ], + declarations: [BatchVehicleTemplateComponent, TechRecordSummaryStubComponent], + providers: [ + GlobalErrorService, + provideMockStore({ initialState: initialAppState }), + { provide: TechnicalRecordService, useValue: mockTechRecordService }, + { provide: BatchTechnicalRecordService, useValue: mockBatchTechRecordService }, + ], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(BatchVehicleTemplateComponent); + store = TestBed.inject(MockStore); + router = TestBed.inject(Router); + component = fixture.componentInstance; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + // TODO V3 HGV PSV TRL + it('should expose the editableVehicleTechRecord$ observable', () => { + expect(component.vehicle$).toBeTruthy(); + }); + + it('should expose the applicationId$ observable', () => { + expect(component.applicationId$).toBeTruthy(); + }); + + it('should expose the isBatch$ observable', () => { + expect(component.isBatch$).toBeTruthy(); + }); + + it('should expose the batchCount$ observable', () => { + expect(component.batchCount$).toBeTruthy(); + }); + + it('should expose the vehicleType$ observable', () => { + expect(component.vehicleType$).toBeTruthy(); + }); + + describe('should dispatch the createVehicleTechRecord action for every vin and trailerId given', () => { + beforeEach(() => { + component.summary = TestBed.createComponent(TechRecordSummaryStubComponent) + .componentInstance as TechRecordSummaryComponent; + }); + + it('given a batch of 0', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch').mockImplementation(); + jest.spyOn(component, 'isVehicleStatusValid', 'get').mockReturnValue(true); + component.handleSubmit(); + expect(dispatchSpy).toHaveBeenCalledTimes(0); + }); + + it('given a batch of 2 vehicles to create', () => { + batchOfVehicles = [{ vin: 'EXAMPLEVIN000001' }, { vin: 'EXAMPLEVIN000002' }]; + + const dispatchSpy = jest.spyOn(store, 'dispatch').mockImplementation(); + jest.spyOn(component, 'isVehicleStatusValid', 'get').mockReturnValue(true); + component.handleSubmit(); + expect(dispatchSpy).toHaveBeenCalledTimes(2); + }); + + it('given a batch of 2 vehicles to update', fakeAsync(() => { + jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + batchOfVehicles = [ + { + vin: 'EXAMPLEVIN000001', + trailerIdOrVrm: '1000001', + systemNumber: '1', + createdTimestamp: 'foobar', + }, + { + vin: 'EXAMPLEVIN000002', + trailerIdOrVrm: '1000002', + systemNumber: '2', + createdTimestamp: '2022', + }, + ]; + jest.spyOn(mockBatchTechRecordService, 'batchVehicles$', 'get').mockReturnValue(of(batchOfVehicles)); + + jest.spyOn(component, 'isVehicleStatusValid', 'get').mockReturnValue(true); + + const dispatchSpy = jest.spyOn(store, 'dispatch').mockImplementation(); + component.handleSubmit(); + + tick(); + + expect(dispatchSpy).toHaveBeenCalledTimes(2); + expect(dispatchSpy).toHaveBeenNthCalledWith( + 1, + updateTechRecord({ + systemNumber: '1', + createdTimestamp: 'foobar', + }) + ); + + expect(dispatchSpy).toHaveBeenNthCalledWith( + 2, + updateTechRecord({ + systemNumber: '2', + createdTimestamp: '2022', + }) + ); + })); + + it('given a batch of 5 vehicles to create and update', fakeAsync(() => { + jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + batchOfVehicles = [ + { + vin: 'EXAMPLEVIN000001', + trailerIdOrVrm: '1000001', + systemNumber: '1', + createdTimestamp: '2022', + }, + { vin: 'EXAMPLEVIN000002' }, + { + vin: 'EXAMPLEVIN000003', + trailerIdOrVrm: '1000002', + systemNumber: '3', + createdTimestamp: '2023', + }, + { vin: 'EXAMPLEVIN000004' }, + { vin: 'EXAMPLEVIN000005' }, + ]; + + jest.spyOn(mockBatchTechRecordService, 'batchVehicles$', 'get').mockReturnValue(of(batchOfVehicles)); + jest.spyOn(component, 'isVehicleStatusValid', 'get').mockReturnValue(true); + const dispatchSpy = jest.spyOn(store, 'dispatch').mockImplementation(); + component.handleSubmit(); + + tick(); + + expect(dispatchSpy).toHaveBeenCalledTimes(5); + expect(dispatchSpy).toHaveBeenNthCalledWith( + 1, + updateTechRecord({ + systemNumber: '1', + createdTimestamp: '2022', + }) + ); + expect(dispatchSpy).toHaveBeenNthCalledWith(2, createVehicleRecord({ vehicle: expect.anything() })); + expect(dispatchSpy).toHaveBeenNthCalledWith( + 3, + updateTechRecord({ + systemNumber: '3', + createdTimestamp: '2023', + }) + ); + expect(dispatchSpy).toHaveBeenNthCalledWith(4, createVehicleRecord({ vehicle: expect.anything() })); + expect(dispatchSpy).toHaveBeenNthCalledWith(5, createVehicleRecord({ vehicle: expect.anything() })); + })); + + it('given a batch of 40', fakeAsync(() => { + jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + batchOfVehicles = []; + for (let i = 1; i <= 40; i++) { + batchOfVehicles.push({ vin: `EXAMPLEVIN0000${i}`, trailerIdOrVrm: `100000${i}` }); + } + + jest.spyOn(mockBatchTechRecordService, 'batchVehicles$', 'get').mockReturnValue(of(batchOfVehicles)); + jest.spyOn(component, 'isVehicleStatusValid', 'get').mockReturnValue(true); + + const dispatchSpy = jest.spyOn(store, 'dispatch').mockImplementation(); + component.handleSubmit(); + tick(); + expect(dispatchSpy).toHaveBeenCalledTimes(40); + })); + }); }); diff --git a/src/app/features/tech-record/create-batch/components/batch-vehicle-template/batch-vehicle-template.component.ts b/src/app/features/tech-record/create-batch/components/batch-vehicle-template/batch-vehicle-template.component.ts index 466717a209..4a7d7933d0 100644 --- a/src/app/features/tech-record/create-batch/components/batch-vehicle-template/batch-vehicle-template.component.ts +++ b/src/app/features/tech-record/create-batch/components/batch-vehicle-template/batch-vehicle-template.component.ts @@ -8,134 +8,140 @@ import { MultiOptions } from '@forms/models/options.model'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; import { CustomFormControl, CustomFormGroup, FormNodeTypes } from '@forms/services/dynamic-form.types'; import { - BatchUpdateVehicleModel, StatusCodes, V3TechRecordModel, VehicleTypes, + BatchUpdateVehicleModel, + StatusCodes, + V3TechRecordModel, + VehicleTypes, } from '@models/vehicle-tech-record.model'; import { Store } from '@ngrx/store'; import { BatchTechnicalRecordService } from '@services/batch-technical-record/batch-technical-record.service'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { createVehicleRecord, selectTechRecord, updateTechRecord } from '@store/technical-records'; import { TechnicalRecordServiceState } from '@store/technical-records/reducers/technical-record-service.reducer'; -import { - Observable, map, take, withLatestFrom, -} from 'rxjs'; +import { Observable, map, take, withLatestFrom } from 'rxjs'; import { TechRecordSummaryComponent } from '../../../components/tech-record-summary/tech-record-summary.component'; @Component({ - selector: 'app-batch-vehicle-template', - templateUrl: './batch-vehicle-template.component.html', + selector: 'app-batch-vehicle-template', + templateUrl: './batch-vehicle-template.component.html', }) export class BatchVehicleTemplateComponent { - @ViewChild(TechRecordSummaryComponent) summary?: TechRecordSummaryComponent; - isInvalid = false; - form: CustomFormGroup; - public vehicleStatusOptions: MultiOptions = [ - { label: 'Provisional', value: StatusCodes.PROVISIONAL }, - { label: 'Current', value: StatusCodes.CURRENT }, - ]; - - constructor( - private route: ActivatedRoute, - private router: Router, - private store: Store, - private technicalRecordService: TechnicalRecordService, - private batchTechRecordService: BatchTechnicalRecordService, - private globalErrorService: GlobalErrorService, - ) { - this.store - .select(selectTechRecord) - .pipe(take(1)) - .subscribe((vehicle) => { - if (!vehicle) { - void this.router.navigate(['..'], { relativeTo: this.route }); - } - }); - - this.form = new CustomFormGroup( - { name: 'form-group', type: FormNodeTypes.GROUP }, - { - vehicleStatus: new CustomFormControl({ name: 'change-vehicle-status-select', label: 'Vehicle status', type: FormNodeTypes.CONTROL }, '', [ - Validators.required, - ]), - }, - ); - - this.batchTechRecordService.vehicleStatus$.pipe(take(1)).subscribe((vehicleStatus) => { - if (this.form) { - this.form.patchValue({ vehicleStatus }); - } - }); - } - - get vehicle$(): Observable { - return this.store.select(selectTechRecord); - } - - get applicationId$() { - return this.batchTechRecordService.applicationId$; - } - - get isBatch$() { - return this.batchTechRecordService.isBatchCreate$; - } - - get batchCount$() { - return this.batchTechRecordService.batchCount$; - } - - get vehicleType$() { - return this.batchTechRecordService.vehicleType$; - } - - statusChange(): void { - return this.batchTechRecordService.setVehicleStatus(this.form.get('vehicleStatus')?.value); - } - - get isVehicleStatusValid(): boolean { - const errors: GlobalError[] = []; - - DynamicFormService.validate(this.form, errors); - - this.globalErrorService.setErrors(errors); - - return this.form.valid; - } - - handleSubmit() { - this.summary?.checkForms(); - const check = this.isVehicleStatusValid; - - if (!this.isInvalid && check) { - this.store - .select(selectTechRecord) - .pipe( - withLatestFrom(this.batchTechRecordService.batchVehicles$), - take(1), - map(([record, batch]) => - batch.map( - (v): BatchUpdateVehicleModel => - ({ - ...record, - techRecord_statusCode: this.form.value.vehicleStatus ?? StatusCodes.PROVISIONAL, - vin: v.vin, - trailerId: v.vehicleType === VehicleTypes.TRL ? v.trailerIdOrVrm : undefined, - primaryVrm: v.vehicleType !== VehicleTypes.TRL ? v.trailerIdOrVrm : undefined, - systemNumber: v.systemNumber, - createdTimestamp: v.createdTimestamp, - } as unknown as BatchUpdateVehicleModel), - )), - ) - .subscribe((vehicleList) => { - vehicleList.forEach((vehicle) => { - if (!vehicle.systemNumber) { - this.store.dispatch(createVehicleRecord({ vehicle: vehicle as unknown as TechRecordType<'put'> })); - } else { - this.technicalRecordService.updateEditingTechRecord(vehicle); - this.store.dispatch(updateTechRecord({ systemNumber: vehicle.systemNumber, createdTimestamp: vehicle.createdTimestamp })); - } - }); - this.technicalRecordService.clearSectionTemplateStates(); - void this.router.navigate(['batch-results'], { relativeTo: this.route }); - }); - } - } + @ViewChild(TechRecordSummaryComponent) summary?: TechRecordSummaryComponent; + isInvalid = false; + form: CustomFormGroup; + public vehicleStatusOptions: MultiOptions = [ + { label: 'Provisional', value: StatusCodes.PROVISIONAL }, + { label: 'Current', value: StatusCodes.CURRENT }, + ]; + + constructor( + private route: ActivatedRoute, + private router: Router, + private store: Store, + private technicalRecordService: TechnicalRecordService, + private batchTechRecordService: BatchTechnicalRecordService, + private globalErrorService: GlobalErrorService + ) { + this.store + .select(selectTechRecord) + .pipe(take(1)) + .subscribe((vehicle) => { + if (!vehicle) { + void this.router.navigate(['..'], { relativeTo: this.route }); + } + }); + + this.form = new CustomFormGroup( + { name: 'form-group', type: FormNodeTypes.GROUP }, + { + vehicleStatus: new CustomFormControl( + { name: 'change-vehicle-status-select', label: 'Vehicle status', type: FormNodeTypes.CONTROL }, + '', + [Validators.required] + ), + } + ); + + this.batchTechRecordService.vehicleStatus$.pipe(take(1)).subscribe((vehicleStatus) => { + if (this.form) { + this.form.patchValue({ vehicleStatus }); + } + }); + } + + get vehicle$(): Observable { + return this.store.select(selectTechRecord); + } + + get applicationId$() { + return this.batchTechRecordService.applicationId$; + } + + get isBatch$() { + return this.batchTechRecordService.isBatchCreate$; + } + + get batchCount$() { + return this.batchTechRecordService.batchCount$; + } + + get vehicleType$() { + return this.batchTechRecordService.vehicleType$; + } + + statusChange(): void { + return this.batchTechRecordService.setVehicleStatus(this.form.get('vehicleStatus')?.value); + } + + get isVehicleStatusValid(): boolean { + const errors: GlobalError[] = []; + + DynamicFormService.validate(this.form, errors); + + this.globalErrorService.setErrors(errors); + + return this.form.valid; + } + + handleSubmit() { + this.summary?.checkForms(); + const check = this.isVehicleStatusValid; + + if (!this.isInvalid && check) { + this.store + .select(selectTechRecord) + .pipe( + withLatestFrom(this.batchTechRecordService.batchVehicles$), + take(1), + map(([record, batch]) => + batch.map( + (v): BatchUpdateVehicleModel => + ({ + ...record, + techRecord_statusCode: this.form.value.vehicleStatus ?? StatusCodes.PROVISIONAL, + vin: v.vin, + trailerId: v.vehicleType === VehicleTypes.TRL ? v.trailerIdOrVrm : undefined, + primaryVrm: v.vehicleType !== VehicleTypes.TRL ? v.trailerIdOrVrm : undefined, + systemNumber: v.systemNumber, + createdTimestamp: v.createdTimestamp, + }) as unknown as BatchUpdateVehicleModel + ) + ) + ) + .subscribe((vehicleList) => { + vehicleList.forEach((vehicle) => { + if (!vehicle.systemNumber) { + this.store.dispatch(createVehicleRecord({ vehicle: vehicle as unknown as TechRecordType<'put'> })); + } else { + this.technicalRecordService.updateEditingTechRecord(vehicle); + this.store.dispatch( + updateTechRecord({ systemNumber: vehicle.systemNumber, createdTimestamp: vehicle.createdTimestamp }) + ); + } + }); + this.technicalRecordService.clearSectionTemplateStates(); + void this.router.navigate(['batch-results'], { relativeTo: this.route }); + }); + } + } } diff --git a/src/app/features/tech-record/create-batch/components/select-vehicle-type/select-vehicle-type.component.spec.ts b/src/app/features/tech-record/create-batch/components/select-vehicle-type/select-vehicle-type.component.spec.ts index 12aec546b7..de9f9b3990 100644 --- a/src/app/features/tech-record/create-batch/components/select-vehicle-type/select-vehicle-type.component.spec.ts +++ b/src/app/features/tech-record/create-batch/components/select-vehicle-type/select-vehicle-type.component.spec.ts @@ -14,76 +14,76 @@ import { of } from 'rxjs'; import { SelectVehicleTypeComponent } from './select-vehicle-type.component'; describe('SelectVehicleTypeComponent', () => { - let component: SelectVehicleTypeComponent; - let fixture: ComponentFixture; - let errorService: GlobalErrorService; - let route: ActivatedRoute; - let router: Router; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [SelectVehicleTypeComponent], - imports: [DynamicFormsModule, HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule, SharedModule], - providers: [ - GlobalErrorService, - provideMockStore({ initialState: initialAppState }), - { provide: ActivatedRoute, useValue: { params: of([{ vehicleType: 'trl' }]) } }, - ], - }).compileComponents(); - - fixture = TestBed.createComponent(SelectVehicleTypeComponent); - errorService = TestBed.inject(GlobalErrorService); - route = TestBed.inject(ActivatedRoute); - router = TestBed.inject(Router); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('get vehicleTypeOptions', () => { - it('should return the expected options', () => { - expect(component.vehicleTypeOptions).toBeTruthy(); - }); - }); - - describe('cancel', () => { - it('should clear all errors', () => { - jest.spyOn(router, 'navigate').mockImplementation(); - - const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); - - component.cancel(); - - expect(clearErrorsSpy).toHaveBeenCalledTimes(1); - }); - - it('should navigate back to the previous page', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - component.cancel(); - - expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); - }); - }); - - describe('handleSubmit', () => { - it('should do nothing if the form is not valid', () => { - jest.spyOn(component, 'isFormValid', 'get').mockReturnValue(false); - const navigateSpy = jest.spyOn(router, 'navigate'); - component.handleSubmit(VehicleTypes.TRL); - expect(navigateSpy).toHaveBeenCalledTimes(0); - }); - - it('should navigate to batch records when successful', () => { - jest.spyOn(component, 'isFormValid', 'get').mockReturnValue(true); - const routerSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - component.handleSubmit(VehicleTypes.HGV); - - fixture.detectChanges(); - expect(routerSpy).toHaveBeenCalledWith(['hgv'], { relativeTo: route }); - }); - }); + let component: SelectVehicleTypeComponent; + let fixture: ComponentFixture; + let errorService: GlobalErrorService; + let route: ActivatedRoute; + let router: Router; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [SelectVehicleTypeComponent], + imports: [DynamicFormsModule, HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule, SharedModule], + providers: [ + GlobalErrorService, + provideMockStore({ initialState: initialAppState }), + { provide: ActivatedRoute, useValue: { params: of([{ vehicleType: 'trl' }]) } }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(SelectVehicleTypeComponent); + errorService = TestBed.inject(GlobalErrorService); + route = TestBed.inject(ActivatedRoute); + router = TestBed.inject(Router); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('get vehicleTypeOptions', () => { + it('should return the expected options', () => { + expect(component.vehicleTypeOptions).toBeTruthy(); + }); + }); + + describe('cancel', () => { + it('should clear all errors', () => { + jest.spyOn(router, 'navigate').mockImplementation(); + + const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); + + component.cancel(); + + expect(clearErrorsSpy).toHaveBeenCalledTimes(1); + }); + + it('should navigate back to the previous page', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + component.cancel(); + + expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); + }); + }); + + describe('handleSubmit', () => { + it('should do nothing if the form is not valid', () => { + jest.spyOn(component, 'isFormValid', 'get').mockReturnValue(false); + const navigateSpy = jest.spyOn(router, 'navigate'); + component.handleSubmit(VehicleTypes.TRL); + expect(navigateSpy).toHaveBeenCalledTimes(0); + }); + + it('should navigate to batch records when successful', () => { + jest.spyOn(component, 'isFormValid', 'get').mockReturnValue(true); + const routerSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + component.handleSubmit(VehicleTypes.HGV); + + fixture.detectChanges(); + expect(routerSpy).toHaveBeenCalledWith(['hgv'], { relativeTo: route }); + }); + }); }); diff --git a/src/app/features/tech-record/create-batch/components/select-vehicle-type/select-vehicle-type.component.ts b/src/app/features/tech-record/create-batch/components/select-vehicle-type/select-vehicle-type.component.ts index 8ea572c169..196ad264a4 100644 --- a/src/app/features/tech-record/create-batch/components/select-vehicle-type/select-vehicle-type.component.ts +++ b/src/app/features/tech-record/create-batch/components/select-vehicle-type/select-vehicle-type.component.ts @@ -5,9 +5,7 @@ import { GlobalError } from '@core/components/global-error/global-error.interfac import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; -import { - CustomFormControl, CustomFormGroup, FormNodeOption, FormNodeTypes, -} from '@forms/services/dynamic-form.types'; +import { CustomFormControl, CustomFormGroup, FormNodeOption, FormNodeTypes } from '@forms/services/dynamic-form.types'; import { CustomValidators } from '@forms/validators/custom-validators'; import { StatusCodes, TrailerFormType, VehicleTypes } from '@models/vehicle-tech-record.model'; import { Store } from '@ngrx/store'; @@ -17,78 +15,88 @@ import { selectTechRecord } from '@store/technical-records'; import { take } from 'rxjs'; @Component({ - selector: 'app-select-vehicle-type', - templateUrl: './select-vehicle-type.component.html', + selector: 'app-select-vehicle-type', + templateUrl: './select-vehicle-type.component.html', }) export class SelectVehicleTypeComponent { - form: CustomFormGroup = new CustomFormGroup( - { name: 'form-group', type: FormNodeTypes.GROUP }, - { - vehicleType: new CustomFormControl({ name: 'vehicle-type', label: 'Vehicle type', type: FormNodeTypes.CONTROL }, '', [Validators.required]), - tes1Tes2: new CustomFormControl({ name: 'tes1-tes2', label: 'Trailer form type', type: FormNodeTypes.CONTROL }, '', [ - CustomValidators.requiredIfEquals('vehicleType', [VehicleTypes.TRL]), - ]), - }, - ); + form: CustomFormGroup = new CustomFormGroup( + { name: 'form-group', type: FormNodeTypes.GROUP }, + { + vehicleType: new CustomFormControl( + { name: 'vehicle-type', label: 'Vehicle type', type: FormNodeTypes.CONTROL }, + '', + [Validators.required] + ), + tes1Tes2: new CustomFormControl( + { name: 'tes1-tes2', label: 'Trailer form type', type: FormNodeTypes.CONTROL }, + '', + [CustomValidators.requiredIfEquals('vehicleType', [VehicleTypes.TRL])] + ), + } + ); - public vehicleTypeOptions: Array> = [ - { label: 'Heavy goods vehicle (HGV)', value: VehicleTypes.HGV }, - { label: 'Public service vehicle (PSV)', value: VehicleTypes.PSV }, - { label: 'Trailer (TRL)', value: VehicleTypes.TRL }, - ]; + public vehicleTypeOptions: Array> = [ + { label: 'Heavy goods vehicle (HGV)', value: VehicleTypes.HGV }, + { label: 'Public service vehicle (PSV)', value: VehicleTypes.PSV }, + { label: 'Trailer (TRL)', value: VehicleTypes.TRL }, + ]; - public tes1Tes2Options: Array> = [ - { label: 'TES 1', value: TrailerFormType.TES1 }, - { label: 'TES 2', value: TrailerFormType.TES2 }, - ]; + public tes1Tes2Options: Array> = [ + { label: 'TES 1', value: TrailerFormType.TES1 }, + { label: 'TES 2', value: TrailerFormType.TES2 }, + ]; - constructor( - private globalErrorService: GlobalErrorService, - private batchTechRecordService: BatchTechnicalRecordService, - private trs: TechnicalRecordService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - ) { - this.batchTechRecordService.clearBatch(); - this.trs.clearSectionTemplateStates(); - } + constructor( + private globalErrorService: GlobalErrorService, + private batchTechRecordService: BatchTechnicalRecordService, + private trs: TechnicalRecordService, + private route: ActivatedRoute, + private router: Router, + private store: Store + ) { + this.batchTechRecordService.clearBatch(); + this.trs.clearSectionTemplateStates(); + } - get isFormValid(): boolean { - const errors: GlobalError[] = []; + get isFormValid(): boolean { + const errors: GlobalError[] = []; - DynamicFormService.validate(this.form, errors); + DynamicFormService.validate(this.form, errors); - this.globalErrorService.setErrors(errors); + this.globalErrorService.setErrors(errors); - return this.form.valid; - } + return this.form.valid; + } - cancel() { - this.globalErrorService.clearErrors(); - void this.router.navigate(['..'], { relativeTo: this.route }); - } + cancel() { + this.globalErrorService.clearErrors(); + void this.router.navigate(['..'], { relativeTo: this.route }); + } - handleSubmit(type: VehicleTypes): void { - if (!this.isFormValid) { - return; - } - if (type === VehicleTypes.PSV) { - this.batchTechRecordService.setVehicleStatus(StatusCodes.CURRENT); - } else if (type === VehicleTypes.TRL && this.form.value.tes1Tes2 === TrailerFormType.TES2) { - this.batchTechRecordService.setVehicleStatus(StatusCodes.PROVISIONAL); - } + handleSubmit(type: VehicleTypes): void { + if (!this.isFormValid) { + return; + } + if (type === VehicleTypes.PSV) { + this.batchTechRecordService.setVehicleStatus(StatusCodes.CURRENT); + } else if (type === VehicleTypes.TRL && this.form.value.tes1Tes2 === TrailerFormType.TES2) { + this.batchTechRecordService.setVehicleStatus(StatusCodes.PROVISIONAL); + } - this.batchTechRecordService.setVehicleType(type); + this.batchTechRecordService.setVehicleType(type); - this.store - .select(selectTechRecord) - .pipe(take(1)) - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - .subscribe((vehicle) => !vehicle && this.trs.updateEditingTechRecord({ ...vehicle!, techRecord_vehicleType: type } as TechRecordType<'put'>)); + this.store + .select(selectTechRecord) + .pipe(take(1)) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + .subscribe( + (vehicle) => + !vehicle && + this.trs.updateEditingTechRecord({ ...vehicle!, techRecord_vehicleType: type } as TechRecordType<'put'>) + ); - this.trs.generateEditingVehicleTechnicalRecordFromVehicleType(type); + this.trs.generateEditingVehicleTechnicalRecordFromVehicleType(type); - void this.router.navigate([type], { relativeTo: this.route }); - } + void this.router.navigate([type], { relativeTo: this.route }); + } } diff --git a/src/app/features/tech-record/create-batch/create-batch-routing.module.ts b/src/app/features/tech-record/create-batch/create-batch-routing.module.ts index 108faf3131..0f4b59f4c0 100644 --- a/src/app/features/tech-record/create-batch/create-batch-routing.module.ts +++ b/src/app/features/tech-record/create-batch/create-batch-routing.module.ts @@ -3,9 +3,9 @@ import { RouterModule, Routes } from '@angular/router'; import { MsalGuard } from '@azure/msal-angular'; import { RoleGuard } from '@guards/role-guard/roles.guard'; import { Roles } from '@models/roles.enum'; +import { TechRecordCreateBatchRoutes } from '@models/routes.enum'; import { RouterOutletComponent } from '@shared/components/router-outlet/router-outlet.component'; import { techRecordDataResolver } from 'src/app/resolvers/tech-record-data/tech-record-data.resolver'; -import { TechRecordCreateBatchRoutes } from '@models/routes.enum'; import { TechRecordSearchTyresComponent } from '../components/tech-record-search-tyres/tech-record-search-tyres.component'; import { BatchVehicleDetailsComponent } from './components/batch-vehicle-details/batch-vehicle-details.component'; import { BatchVehicleResultsComponent } from './components/batch-vehicle-results/batch-vehicle-results.component'; @@ -13,57 +13,60 @@ import { BatchVehicleTemplateComponent } from './components/batch-vehicle-templa import { SelectVehicleTypeComponent } from './components/select-vehicle-type/select-vehicle-type.component'; const routes: Routes = [ - { - path: '', - component: RouterOutletComponent, - data: { roles: Roles.TechRecordCreate }, - canActivate: [MsalGuard, RoleGuard], - resolve: { - data: techRecordDataResolver, - }, - children: [ - { - path: '', - component: SelectVehicleTypeComponent, - data: { roles: Roles.TechRecordCreate }, - canActivate: [MsalGuard, RoleGuard], - }, - { - path: TechRecordCreateBatchRoutes.RECORD, - component: RouterOutletComponent, - data: { title: 'Batch Record', roles: Roles.TechRecordCreate, isCustomLayout: true }, - children: [ - { - path: '', - component: BatchVehicleTemplateComponent, - data: { - title: 'Batch Record', roles: Roles.TechRecordCreate, isCustomLayout: true, isEditing: true, - }, - }, - { - path: TechRecordCreateBatchRoutes.DETAILS, - component: BatchVehicleDetailsComponent, - data: { title: 'Add batch of vehicles', roles: Roles.TechRecordCreate, isEditing: true }, - }, - { - path: TechRecordCreateBatchRoutes.BATCH_RESULT, - data: { title: 'Batch summary' }, - component: BatchVehicleResultsComponent, - }, - { - path: TechRecordCreateBatchRoutes.TYRE_SEARCH, - component: TechRecordSearchTyresComponent, - data: { title: 'Tyre search', roles: Roles.TechRecordCreate, isEditing: true }, - canActivate: [MsalGuard, RoleGuard], - }, - ], - }, - ], - }, + { + path: '', + component: RouterOutletComponent, + data: { roles: Roles.TechRecordCreate }, + canActivate: [MsalGuard, RoleGuard], + resolve: { + data: techRecordDataResolver, + }, + children: [ + { + path: '', + component: SelectVehicleTypeComponent, + data: { roles: Roles.TechRecordCreate }, + canActivate: [MsalGuard, RoleGuard], + }, + { + path: TechRecordCreateBatchRoutes.RECORD, + component: RouterOutletComponent, + data: { title: 'Batch Record', roles: Roles.TechRecordCreate, isCustomLayout: true }, + children: [ + { + path: '', + component: BatchVehicleTemplateComponent, + data: { + title: 'Batch Record', + roles: Roles.TechRecordCreate, + isCustomLayout: true, + isEditing: true, + }, + }, + { + path: TechRecordCreateBatchRoutes.DETAILS, + component: BatchVehicleDetailsComponent, + data: { title: 'Add batch of vehicles', roles: Roles.TechRecordCreate, isEditing: true }, + }, + { + path: TechRecordCreateBatchRoutes.BATCH_RESULT, + data: { title: 'Batch summary' }, + component: BatchVehicleResultsComponent, + }, + { + path: TechRecordCreateBatchRoutes.TYRE_SEARCH, + component: TechRecordSearchTyresComponent, + data: { title: 'Tyre search', roles: Roles.TechRecordCreate, isEditing: true }, + canActivate: [MsalGuard, RoleGuard], + }, + ], + }, + ], + }, ]; @NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], }) export class CreateBatchRoutingModule {} diff --git a/src/app/features/tech-record/create-batch/create-batch.module.ts b/src/app/features/tech-record/create-batch/create-batch.module.ts index 4c5538a73d..1c600ba160 100644 --- a/src/app/features/tech-record/create-batch/create-batch.module.ts +++ b/src/app/features/tech-record/create-batch/create-batch.module.ts @@ -7,23 +7,28 @@ import { DynamicFormsModule } from '@forms/dynamic-forms.module'; import { SharedModule } from '@shared/shared.module'; import { CreateTechRecordsModule } from '../create/create-tech-records.module'; import { SharedTechRecordsModule } from '../shared-tech-record.module'; -import { BatchVehicleTemplateComponent } from './components/batch-vehicle-template/batch-vehicle-template.component'; -import { CreateBatchRoutingModule } from './create-batch-routing.module'; import { BatchVehicleDetailsComponent } from './components/batch-vehicle-details/batch-vehicle-details.component'; import { BatchVehicleResultsComponent } from './components/batch-vehicle-results/batch-vehicle-results.component'; +import { BatchVehicleTemplateComponent } from './components/batch-vehicle-template/batch-vehicle-template.component'; import { SelectVehicleTypeComponent } from './components/select-vehicle-type/select-vehicle-type.component'; +import { CreateBatchRoutingModule } from './create-batch-routing.module'; @NgModule({ - declarations: [BatchVehicleTemplateComponent, BatchVehicleDetailsComponent, BatchVehicleResultsComponent, SelectVehicleTypeComponent], - imports: [ - CommonModule, - CreateBatchRoutingModule, - SharedTechRecordsModule, - ReactiveFormsModule, - DynamicFormsModule, - RouterModule, - SharedModule, - CreateTechRecordsModule, - ], + declarations: [ + BatchVehicleTemplateComponent, + BatchVehicleDetailsComponent, + BatchVehicleResultsComponent, + SelectVehicleTypeComponent, + ], + imports: [ + CommonModule, + CreateBatchRoutingModule, + SharedTechRecordsModule, + ReactiveFormsModule, + DynamicFormsModule, + RouterModule, + SharedModule, + CreateTechRecordsModule, + ], }) export class CreateBatchModule {} diff --git a/src/app/features/tech-record/create/components/hydrate-new-vehicle-record/hydrate-new-vehicle-record.component.spec.ts b/src/app/features/tech-record/create/components/hydrate-new-vehicle-record/hydrate-new-vehicle-record.component.spec.ts index 2f0cb1ee55..1eae33542b 100644 --- a/src/app/features/tech-record/create/components/hydrate-new-vehicle-record/hydrate-new-vehicle-record.component.spec.ts +++ b/src/app/features/tech-record/create/components/hydrate-new-vehicle-record/hydrate-new-vehicle-record.component.spec.ts @@ -1,7 +1,5 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { - ComponentFixture, fakeAsync, TestBed, tick, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { ActivatedRoute, Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; @@ -9,110 +7,110 @@ import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/ import { provideMockActions } from '@ngrx/effects/testing'; import { Action } from '@ngrx/store'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; +import { UserService } from '@services/user-service/user-service'; import { initialAppState } from '@store/index'; import { selectRouteData } from '@store/router/selectors/router.selectors'; import { createVehicleRecordSuccess } from '@store/technical-records'; -import { firstValueFrom, of, ReplaySubject } from 'rxjs'; -import { UserService } from '@services/user-service/user-service'; +import { ReplaySubject, firstValueFrom, of } from 'rxjs'; import { HydrateNewVehicleRecordComponent } from './hydrate-new-vehicle-record.component'; describe('HydrateNewVehicleRecordComponent', () => { - let component: HydrateNewVehicleRecordComponent; - let fixture: ComponentFixture; - const actions$ = new ReplaySubject(); - let errorService: GlobalErrorService; - let route: ActivatedRoute; - let router: Router; - let store: MockStore; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [HydrateNewVehicleRecordComponent], - providers: [ - provideMockActions(() => actions$), - provideMockStore({ initialState: initialAppState }), - { - provide: UserService, - useValue: { - name$: of('tester'), - }, - }, - ], - imports: [HttpClientTestingModule, RouterTestingModule], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(HydrateNewVehicleRecordComponent); - route = TestBed.inject(ActivatedRoute); - errorService = TestBed.inject(GlobalErrorService); - router = TestBed.inject(Router); - store = TestBed.inject(MockStore); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('get vehicle$', () => { - it('should return the editable vehicle', async () => { - const expectedVehicle = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' }; - - jest.spyOn(store, 'select').mockReturnValue(of(expectedVehicle)); - - const vehicle = await firstValueFrom(component.vehicle$); - expect(vehicle).toEqual(expectedVehicle); - }); - }); - - describe('navigate', () => { - it('should clear all errors', () => { - jest.spyOn(router, 'navigate').mockImplementation(); - - const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); - - component.navigate(); - - expect(clearErrorsSpy).toHaveBeenCalledTimes(1); - }); - // TODO V3 HGV PSV TRL - it('should navigate back to batch results', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - component.navigate(); - - expect(navigateSpy).toHaveBeenCalledWith(['batch-results'], { relativeTo: route }); - }); - }); - - describe('handleSubmit', () => { - it('should not dispatch createVehicleRecord', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - - component.isInvalid = true; - - component.handleSubmit(); - - expect(dispatchSpy).not.toHaveBeenCalled(); - }); - - it('should navigate back', fakeAsync(() => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - store.overrideSelector(selectRouteData, { data: { isEditing: true } }); - - component.handleSubmit(); - - actions$.next( - createVehicleRecordSuccess({ - vehicleTechRecord: { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>, - }), - ); - tick(); - - expect(navigateSpy).toHaveBeenCalledTimes(1); - })); - }); + let component: HydrateNewVehicleRecordComponent; + let fixture: ComponentFixture; + const actions$ = new ReplaySubject(); + let errorService: GlobalErrorService; + let route: ActivatedRoute; + let router: Router; + let store: MockStore; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [HydrateNewVehicleRecordComponent], + providers: [ + provideMockActions(() => actions$), + provideMockStore({ initialState: initialAppState }), + { + provide: UserService, + useValue: { + name$: of('tester'), + }, + }, + ], + imports: [HttpClientTestingModule, RouterTestingModule], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(HydrateNewVehicleRecordComponent); + route = TestBed.inject(ActivatedRoute); + errorService = TestBed.inject(GlobalErrorService); + router = TestBed.inject(Router); + store = TestBed.inject(MockStore); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('get vehicle$', () => { + it('should return the editable vehicle', async () => { + const expectedVehicle = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' }; + + jest.spyOn(store, 'select').mockReturnValue(of(expectedVehicle)); + + const vehicle = await firstValueFrom(component.vehicle$); + expect(vehicle).toEqual(expectedVehicle); + }); + }); + + describe('navigate', () => { + it('should clear all errors', () => { + jest.spyOn(router, 'navigate').mockImplementation(); + + const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); + + component.navigate(); + + expect(clearErrorsSpy).toHaveBeenCalledTimes(1); + }); + // TODO V3 HGV PSV TRL + it('should navigate back to batch results', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + component.navigate(); + + expect(navigateSpy).toHaveBeenCalledWith(['batch-results'], { relativeTo: route }); + }); + }); + + describe('handleSubmit', () => { + it('should not dispatch createVehicleRecord', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + + component.isInvalid = true; + + component.handleSubmit(); + + expect(dispatchSpy).not.toHaveBeenCalled(); + }); + + it('should navigate back', fakeAsync(() => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + store.overrideSelector(selectRouteData, { data: { isEditing: true } }); + + component.handleSubmit(); + + actions$.next( + createVehicleRecordSuccess({ + vehicleTechRecord: { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>, + }) + ); + tick(); + + expect(navigateSpy).toHaveBeenCalledTimes(1); + })); + }); }); diff --git a/src/app/features/tech-record/create/components/hydrate-new-vehicle-record/hydrate-new-vehicle-record.component.ts b/src/app/features/tech-record/create/components/hydrate-new-vehicle-record/hydrate-new-vehicle-record.component.ts index 82d7609346..51444abcbd 100644 --- a/src/app/features/tech-record/create/components/hydrate-new-vehicle-record/hydrate-new-vehicle-record.component.ts +++ b/src/app/features/tech-record/create/components/hydrate-new-vehicle-record/hydrate-new-vehicle-record.component.ts @@ -1,6 +1,4 @@ -import { - Component, OnDestroy, OnInit, ViewChild, -} from '@angular/core'; +import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; @@ -10,125 +8,132 @@ import { Actions, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; import { BatchTechnicalRecordService } from '@services/batch-technical-record/batch-technical-record.service'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; +import { UserService } from '@services/user-service/user-service'; import { - clearADRDetailsBeforeUpdate, - createVehicleRecord, - createVehicleRecordSuccess, - selectTechRecord, updateADRAdditionalExaminerNotes, + clearADRDetailsBeforeUpdate, + createVehicleRecord, + createVehicleRecordSuccess, + selectTechRecord, + updateADRAdditionalExaminerNotes, } from '@store/technical-records'; import { BatchRecord } from '@store/technical-records/reducers/batch-create.reducer'; import { TechnicalRecordServiceState } from '@store/technical-records/reducers/technical-record-service.reducer'; -import { - Observable, Subject, map, take, takeUntil, withLatestFrom, -} from 'rxjs'; -import { UserService } from '@services/user-service/user-service'; +import { Observable, Subject, map, take, takeUntil, withLatestFrom } from 'rxjs'; import { TechRecordSummaryComponent } from '../../../components/tech-record-summary/tech-record-summary.component'; @Component({ - selector: 'app-hydrate-new-vehicle-record', - templateUrl: './hydrate-new-vehicle-record.component.html', + selector: 'app-hydrate-new-vehicle-record', + templateUrl: './hydrate-new-vehicle-record.component.html', }) export class HydrateNewVehicleRecordComponent implements OnDestroy, OnInit { - @ViewChild(TechRecordSummaryComponent) summary?: TechRecordSummaryComponent; - isInvalid = false; - batchForm?: FormGroup; - username = ''; - - private destroy$ = new Subject(); - - constructor( - private actions$: Actions, - private globalErrorService: GlobalErrorService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - private technicalRecordService: TechnicalRecordService, - private batchTechRecordService: BatchTechnicalRecordService, - public userService$: UserService, - ) { } - - ngOnInit(): void { - this.actions$.pipe(ofType(createVehicleRecordSuccess), takeUntil(this.destroy$)).subscribe(({ vehicleTechRecord }) => { - void this.router.navigate([`/tech-records/${vehicleTechRecord.systemNumber}/${vehicleTechRecord.createdTimestamp}`]); - }); - - this.userService$.name$.pipe(takeUntil(this.destroy$)).subscribe((name) => { - this.username = name; - }); - - this.store - .select(selectTechRecord) - .pipe(take(1)) - .subscribe((vehicle) => { - if (!vehicle) { - void this.router.navigate(['..'], { relativeTo: this.route }); - } - }); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - get vehicle$(): Observable { - return this.store.select(selectTechRecord); - } - - get isBatch$(): Observable { - return this.batchTechRecordService.isBatchCreate$; - } - - get batchCount$(): Observable { - return this.batchTechRecordService.batchCount$; - } - - get vehicleTypes(): typeof VehicleTypes { - return VehicleTypes; - } - - navigate(systemNumber?: string, createdTimestamp?: string): void { - this.globalErrorService.clearErrors(); - - if (systemNumber && createdTimestamp) { - void this.router.navigate([`/tech-records/${systemNumber}/${createdTimestamp}`]); - } else { - void this.router.navigate(['batch-results'], { relativeTo: this.route }); - } - } - - handleSubmit(): void { - this.summary?.checkForms(); - - if (this.isInvalid) return; - - this.store.dispatch(updateADRAdditionalExaminerNotes({ username: this.username })); - this.store.dispatch(clearADRDetailsBeforeUpdate()); - this.store - .select(selectTechRecord) - .pipe( - withLatestFrom(this.batchTechRecordService.batchVehicles$), - take(1), - map(([record, batch]) => - (record ? [record as BatchRecord] : []).concat( - batch.map( - (v) => - ({ - ...(record as BatchRecord), - vin: v.vin, - vrms: v.vehicleType !== VehicleTypes.TRL && v.trailerIdOrVrm ? [{ vrm: v.trailerIdOrVrm, isPrimary: true }] : null, - trailerId: v.vehicleType === VehicleTypes.TRL && v.trailerIdOrVrm ? v.trailerIdOrVrm : null, - } as VehicleTechRecordModel), - ), - )), - withLatestFrom(this.isBatch$), - ) - .subscribe(([vehicleList, isBatch]) => { - vehicleList.forEach((vehicle) => { - this.store.dispatch(createVehicleRecord({ vehicle: vehicle as TechRecordType<'put'> })); - }); - this.technicalRecordService.clearSectionTemplateStates(); - if (isBatch) this.navigate(); - }); - } + @ViewChild(TechRecordSummaryComponent) summary?: TechRecordSummaryComponent; + isInvalid = false; + batchForm?: FormGroup; + username = ''; + + private destroy$ = new Subject(); + + constructor( + private actions$: Actions, + private globalErrorService: GlobalErrorService, + private route: ActivatedRoute, + private router: Router, + private store: Store, + private technicalRecordService: TechnicalRecordService, + private batchTechRecordService: BatchTechnicalRecordService, + public userService$: UserService + ) {} + + ngOnInit(): void { + this.actions$ + .pipe(ofType(createVehicleRecordSuccess), takeUntil(this.destroy$)) + .subscribe(({ vehicleTechRecord }) => { + void this.router.navigate([ + `/tech-records/${vehicleTechRecord.systemNumber}/${vehicleTechRecord.createdTimestamp}`, + ]); + }); + + this.userService$.name$.pipe(takeUntil(this.destroy$)).subscribe((name) => { + this.username = name; + }); + + this.store + .select(selectTechRecord) + .pipe(take(1)) + .subscribe((vehicle) => { + if (!vehicle) { + void this.router.navigate(['..'], { relativeTo: this.route }); + } + }); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + get vehicle$(): Observable { + return this.store.select(selectTechRecord); + } + + get isBatch$(): Observable { + return this.batchTechRecordService.isBatchCreate$; + } + + get batchCount$(): Observable { + return this.batchTechRecordService.batchCount$; + } + + get vehicleTypes(): typeof VehicleTypes { + return VehicleTypes; + } + + navigate(systemNumber?: string, createdTimestamp?: string): void { + this.globalErrorService.clearErrors(); + + if (systemNumber && createdTimestamp) { + void this.router.navigate([`/tech-records/${systemNumber}/${createdTimestamp}`]); + } else { + void this.router.navigate(['batch-results'], { relativeTo: this.route }); + } + } + + handleSubmit(): void { + this.summary?.checkForms(); + + if (this.isInvalid) return; + + this.store.dispatch(updateADRAdditionalExaminerNotes({ username: this.username })); + this.store.dispatch(clearADRDetailsBeforeUpdate()); + this.store + .select(selectTechRecord) + .pipe( + withLatestFrom(this.batchTechRecordService.batchVehicles$), + take(1), + map(([record, batch]) => + (record ? [record as BatchRecord] : []).concat( + batch.map( + (v) => + ({ + ...(record as BatchRecord), + vin: v.vin, + vrms: + v.vehicleType !== VehicleTypes.TRL && v.trailerIdOrVrm + ? [{ vrm: v.trailerIdOrVrm, isPrimary: true }] + : null, + trailerId: v.vehicleType === VehicleTypes.TRL && v.trailerIdOrVrm ? v.trailerIdOrVrm : null, + }) as VehicleTechRecordModel + ) + ) + ), + withLatestFrom(this.isBatch$) + ) + .subscribe(([vehicleList, isBatch]) => { + vehicleList.forEach((vehicle) => { + this.store.dispatch(createVehicleRecord({ vehicle: vehicle as TechRecordType<'put'> })); + }); + this.technicalRecordService.clearSectionTemplateStates(); + if (isBatch) this.navigate(); + }); + } } diff --git a/src/app/features/tech-record/create/create-tech-record.component.spec.ts b/src/app/features/tech-record/create/create-tech-record.component.spec.ts index 672bf76d7d..3d7af5f5f1 100644 --- a/src/app/features/tech-record/create/create-tech-record.component.spec.ts +++ b/src/app/features/tech-record/create/create-tech-record.component.spec.ts @@ -15,185 +15,191 @@ import { of } from 'rxjs'; import { CreateTechRecordComponent } from './create-tech-record.component'; describe('CreateNewVehicleRecordComponent', () => { - let component: CreateTechRecordComponent; - let fixture: ComponentFixture; - let errorService: GlobalErrorService; - let route: ActivatedRoute; - let router: Router; - let techRecordService: TechnicalRecordService; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [CreateTechRecordComponent], - imports: [DynamicFormsModule, HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule, SharedModule], - providers: [ - GlobalErrorService, - provideMockStore({ initialState: initialAppState }), - { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, - ], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(CreateTechRecordComponent); - errorService = TestBed.inject(GlobalErrorService); - route = TestBed.inject(ActivatedRoute); - router = TestBed.inject(Router); - techRecordService = TestBed.inject(TechnicalRecordService); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('get vehicleTypeOptions', () => { - it('should return the expected options', () => { - expect(component.vehicleTypeOptions).toBeTruthy(); - }); - }); - - describe('get vehicleStatusOptions', () => { - it('should return the expected options', () => { - expect(component.vehicleStatusOptions).toBeTruthy(); - }); - }); - - describe('get isFormValid', () => { - it('should call validate with the vehicleForm and an empty array', () => { - const validateSpy = jest.spyOn(DynamicFormService, 'validate').mockImplementation(); - const isValid = component.isFormValid; - expect(isValid).toBeDefined(); - expect(validateSpy).toHaveBeenCalledTimes(1); - expect(validateSpy).toHaveBeenCalledWith(component.form, []); - }); - - it('should call setErrors with an empty array', () => { - jest.spyOn(DynamicFormService, 'validate').mockImplementation(() => {}); - const setErrorsSpy = jest.spyOn(errorService, 'setErrors').mockImplementation(); - const isValid = component.isFormValid; - expect(isValid).toBeDefined(); - expect(setErrorsSpy).toHaveBeenCalledTimes(1); - expect(setErrorsSpy).toHaveBeenCalledWith([]); - }); - - it('should return vehicleForm.valid', () => { - const formValid = component.isFormValid; - expect(formValid).toBeFalsy(); - }); - }); - - describe('navigateBack', () => { - it('should clear all errors', () => { - jest.spyOn(router, 'navigate').mockImplementation(); - - const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); - - component.navigateBack(); - - expect(clearErrorsSpy).toHaveBeenCalledTimes(1); - }); - - it('should navigate back to the previous page', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - - component.navigateBack(); - - expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); - }); - }); - - describe('handleSubmit', () => { - it('should do nothing if the form is not valid', async () => { - const formUniqueSpy = jest.spyOn(component, 'isFormValueUnique').mockImplementation(); - await component.handleSubmit(); - expect(formUniqueSpy).toHaveBeenCalledTimes(0); - }); - - it('should do nothing if the form value not unique', () => { - const isFormValid = jest.spyOn(component, 'isFormValid', 'get').mockReturnValue(true); - const updateEditingSpy = jest.spyOn(techRecordService, 'updateEditingTechRecord'); - const navigateSpy = jest.spyOn(router, 'navigate'); - const generateTechREcordSpy = jest.spyOn(techRecordService, 'generateEditingVehicleTechnicalRecordFromVehicleType'); - void component.handleSubmit(); - - expect(isFormValid).toHaveReturned(); - expect(updateEditingSpy).toHaveBeenCalledTimes(0); - expect(generateTechREcordSpy).toHaveBeenCalledTimes(0); - expect(navigateSpy).toHaveBeenCalledTimes(0); - }); - - it('should navigate to hydrate when successful', async () => { - jest.spyOn(component, 'isFormValid', 'get').mockReturnValue(true); - jest.spyOn(component, 'isFormValueUnique').mockImplementation(() => Promise.resolve(true)); - const routerSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - jest.spyOn(techRecordService, 'updateEditingTechRecord'); - - await component.handleSubmit(); - - fixture.detectChanges(); - expect(routerSpy).toHaveBeenCalledWith(['../create/new-record-details'], { relativeTo: route }); - }); - }); - - describe('isVinUnique', () => { - it('should call isUnique with an emptry string and the type of vin', async () => { - const isUniqueSpy = jest.spyOn(techRecordService, 'isUnique').mockImplementation(() => of(true)); - - await component.isVinUnique(); - - expect(isUniqueSpy).toHaveBeenCalledWith('', SEARCH_TYPES.VIN); - }); - - it('should return true when the VIN is unique', async () => { - jest.spyOn(techRecordService, 'isUnique').mockImplementation(() => of(true)); - - const result = await component.isVinUnique(); - - expect(result).toBeTruthy(); - }); - }); - - describe('isVrmUnique', () => { - it('should return true when the VRM is unique', async () => { - jest.spyOn(techRecordService, 'isUnique').mockImplementation(() => of(true)); + let component: CreateTechRecordComponent; + let fixture: ComponentFixture; + let errorService: GlobalErrorService; + let route: ActivatedRoute; + let router: Router; + let techRecordService: TechnicalRecordService; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [CreateTechRecordComponent], + imports: [DynamicFormsModule, HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule, SharedModule], + providers: [ + GlobalErrorService, + provideMockStore({ initialState: initialAppState }), + { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, + ], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(CreateTechRecordComponent); + errorService = TestBed.inject(GlobalErrorService); + route = TestBed.inject(ActivatedRoute); + router = TestBed.inject(Router); + techRecordService = TestBed.inject(TechnicalRecordService); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('get vehicleTypeOptions', () => { + it('should return the expected options', () => { + expect(component.vehicleTypeOptions).toBeTruthy(); + }); + }); + + describe('get vehicleStatusOptions', () => { + it('should return the expected options', () => { + expect(component.vehicleStatusOptions).toBeTruthy(); + }); + }); + + describe('get isFormValid', () => { + it('should call validate with the vehicleForm and an empty array', () => { + const validateSpy = jest.spyOn(DynamicFormService, 'validate').mockImplementation(); + const isValid = component.isFormValid; + expect(isValid).toBeDefined(); + expect(validateSpy).toHaveBeenCalledTimes(1); + expect(validateSpy).toHaveBeenCalledWith(component.form, []); + }); + + it('should call setErrors with an empty array', () => { + jest.spyOn(DynamicFormService, 'validate').mockImplementation(() => {}); + const setErrorsSpy = jest.spyOn(errorService, 'setErrors').mockImplementation(); + const isValid = component.isFormValid; + expect(isValid).toBeDefined(); + expect(setErrorsSpy).toHaveBeenCalledTimes(1); + expect(setErrorsSpy).toHaveBeenCalledWith([]); + }); + + it('should return vehicleForm.valid', () => { + const formValid = component.isFormValid; + expect(formValid).toBeFalsy(); + }); + }); + + describe('navigateBack', () => { + it('should clear all errors', () => { + jest.spyOn(router, 'navigate').mockImplementation(); + + const clearErrorsSpy = jest.spyOn(errorService, 'clearErrors'); + + component.navigateBack(); + + expect(clearErrorsSpy).toHaveBeenCalledTimes(1); + }); + + it('should navigate back to the previous page', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + + component.navigateBack(); + + expect(navigateSpy).toHaveBeenCalledWith(['..'], { relativeTo: route }); + }); + }); + + describe('handleSubmit', () => { + it('should do nothing if the form is not valid', async () => { + const formUniqueSpy = jest.spyOn(component, 'isFormValueUnique').mockImplementation(); + await component.handleSubmit(); + expect(formUniqueSpy).toHaveBeenCalledTimes(0); + }); + + it('should do nothing if the form value not unique', () => { + const isFormValid = jest.spyOn(component, 'isFormValid', 'get').mockReturnValue(true); + const updateEditingSpy = jest.spyOn(techRecordService, 'updateEditingTechRecord'); + const navigateSpy = jest.spyOn(router, 'navigate'); + const generateTechREcordSpy = jest.spyOn( + techRecordService, + 'generateEditingVehicleTechnicalRecordFromVehicleType' + ); + void component.handleSubmit(); + + expect(isFormValid).toHaveReturned(); + expect(updateEditingSpy).toHaveBeenCalledTimes(0); + expect(generateTechREcordSpy).toHaveBeenCalledTimes(0); + expect(navigateSpy).toHaveBeenCalledTimes(0); + }); + + it('should navigate to hydrate when successful', async () => { + jest.spyOn(component, 'isFormValid', 'get').mockReturnValue(true); + jest.spyOn(component, 'isFormValueUnique').mockImplementation(() => Promise.resolve(true)); + const routerSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + jest.spyOn(techRecordService, 'updateEditingTechRecord'); + + await component.handleSubmit(); + + fixture.detectChanges(); + expect(routerSpy).toHaveBeenCalledWith(['../create/new-record-details'], { relativeTo: route }); + }); + }); + + describe('isVinUnique', () => { + it('should call isUnique with an emptry string and the type of vin', async () => { + const isUniqueSpy = jest.spyOn(techRecordService, 'isUnique').mockImplementation(() => of(true)); + + await component.isVinUnique(); + + expect(isUniqueSpy).toHaveBeenCalledWith('', SEARCH_TYPES.VIN); + }); + + it('should return true when the VIN is unique', async () => { + jest.spyOn(techRecordService, 'isUnique').mockImplementation(() => of(true)); + + const result = await component.isVinUnique(); + + expect(result).toBeTruthy(); + }); + }); + + describe('isVrmUnique', () => { + it('should return true when the VRM is unique', async () => { + jest.spyOn(techRecordService, 'isUnique').mockImplementation(() => of(true)); + + const result = await component.isVrmUnique(); + + expect(result).toBeTruthy(); + }); + + it('should call addError when the VRM is not unique', async () => { + jest.spyOn(techRecordService, 'isUnique').mockImplementation(() => of(false)); + const addErrorSpy = jest.spyOn(errorService, 'addError').mockImplementation(); + + const result = await component.isVrmUnique(); - const result = await component.isVrmUnique(); - - expect(result).toBeTruthy(); - }); + expect(addErrorSpy).toHaveBeenCalledWith({ error: 'Vrm not unique', anchorLink: 'input-vrm-or-trailer-id' }); + expect(result).toBeFalsy(); + }); + }); - it('should call addError when the VRM is not unique', async () => { - jest.spyOn(techRecordService, 'isUnique').mockImplementation(() => of(false)); - const addErrorSpy = jest.spyOn(errorService, 'addError').mockImplementation(); + describe('isTrailerIdUnique', () => { + it('should return true when the trailer ID is unique', async () => { + jest.spyOn(techRecordService, 'isUnique').mockImplementation(() => of(true)); + component.techRecord = { techRecord_vehicleType: 'trl' }; - const result = await component.isVrmUnique(); + const result = await component.isTrailerIdUnique(); - expect(addErrorSpy).toHaveBeenCalledWith({ error: 'Vrm not unique', anchorLink: 'input-vrm-or-trailer-id' }); - expect(result).toBeFalsy(); - }); - }); + expect(result).toBeTruthy(); + }); - describe('isTrailerIdUnique', () => { - it('should return true when the trailer ID is unique', async () => { - jest.spyOn(techRecordService, 'isUnique').mockImplementation(() => of(true)); - component.techRecord = { techRecord_vehicleType: 'trl' }; + it('should call addError when the trailer ID is not unique', async () => { + jest.spyOn(techRecordService, 'isUnique').mockImplementation(() => of(false)); + const addErrorSpy = jest.spyOn(errorService, 'addError').mockImplementation(); + component.techRecord = { techRecord_vehicleType: 'trl' }; - const result = await component.isTrailerIdUnique(); + const result = await component.isTrailerIdUnique(); - expect(result).toBeTruthy(); - }); - - it('should call addError when the trailer ID is not unique', async () => { - jest.spyOn(techRecordService, 'isUnique').mockImplementation(() => of(false)); - const addErrorSpy = jest.spyOn(errorService, 'addError').mockImplementation(); - component.techRecord = { techRecord_vehicleType: 'trl' }; - - const result = await component.isTrailerIdUnique(); - - expect(addErrorSpy).toHaveBeenCalledWith({ error: 'TrailerId not unique', anchorLink: 'input-vrm-or-trailer-id' }); - expect(result).toBeFalsy(); - }); - }); + expect(addErrorSpy).toHaveBeenCalledWith({ + error: 'TrailerId not unique', + anchorLink: 'input-vrm-or-trailer-id', + }); + expect(result).toBeFalsy(); + }); + }); }); diff --git a/src/app/features/tech-record/create/create-tech-record.component.ts b/src/app/features/tech-record/create/create-tech-record.component.ts index e16cf3897d..c71dc0e36d 100644 --- a/src/app/features/tech-record/create/create-tech-record.component.ts +++ b/src/app/features/tech-record/create/create-tech-record.component.ts @@ -10,10 +10,7 @@ import { DynamicFormService } from '@forms/services/dynamic-form.service'; import { CustomFormControl, CustomFormGroup, FormNodeTypes } from '@forms/services/dynamic-form.types'; import { CustomValidators } from '@forms/validators/custom-validators'; import { SEARCH_TYPES } from '@models/search-types-enum'; -import { - StatusCodes, V3TechRecordModel, VehicleTypes, - VehiclesOtherThan, -} from '@models/vehicle-tech-record.model'; +import { StatusCodes, V3TechRecordModel, VehicleTypes, VehiclesOtherThan } from '@models/vehicle-tech-record.model'; import { Store } from '@ngrx/store'; import { BatchTechnicalRecordService } from '@services/batch-technical-record/batch-technical-record.service'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; @@ -21,186 +18,199 @@ import { setSpinnerState } from '@store/spinner/actions/spinner.actions'; import { firstValueFrom } from 'rxjs'; @Component({ - selector: 'app-create', - templateUrl: './create-tech-record.component.html', + selector: 'app-create', + templateUrl: './create-tech-record.component.html', }) export class CreateTechRecordComponent implements OnChanges { - techRecord: Partial = {}; - - isDuplicateVinAllowed = false; - isVinUniqueCheckComplete = false; - - vinUnique = false; - vrmUnique = false; - trlUnique = false; - - form = new CustomFormGroup( - { name: 'main-form', type: FormNodeTypes.GROUP }, - { - vin: new CustomFormControl({ name: 'input-vin', label: 'Vin', type: FormNodeTypes.CONTROL }, '', [ - CustomValidators.alphanumeric(), - CustomValidators.validateVinCharacters(), - Validators.minLength(3), - Validators.maxLength(21), - Validators.required, - ]), - vrmTrm: new CustomFormControl({ name: 'input-vrm-or-trailer-id', label: 'VRM/TRM', type: FormNodeTypes.CONTROL }, '', [ - CustomValidators.alphanumeric(), - CustomValidators.notZNumber, - CustomValidators.validateVRMTrailerIdLength('vehicleType'), - Validators.required, - ]), - vehicleStatus: new CustomFormControl( - { name: 'change-vehicle-status-select', label: 'Vehicle status', type: FormNodeTypes.CONTROL }, - StatusCodes.PROVISIONAL, - [Validators.required], - ), - vehicleType: new CustomFormControl({ name: 'change-vehicle-type-select', label: 'Vehicle type', type: FormNodeTypes.CONTROL }, '', [ - Validators.required, - ]), - generateID: new CustomFormControl({ name: 'generate-c-or-z-num', type: FormNodeTypes.CONTROL }, null), - }, - ); - - public vehicleTypeOptions: MultiOptions = [ - { label: 'Heavy goods vehicle (HGV)', value: VehicleTypes.HGV }, - { label: 'Light goods vehicle (LGV)', value: VehicleTypes.LGV }, - { label: 'Public service vehicle (PSV)', value: VehicleTypes.PSV }, - { label: 'Trailer (TRL)', value: VehicleTypes.TRL }, - { label: 'Small Trailer (Small TRL)', value: VehicleTypes.SMALL_TRL }, - { label: 'Car', value: VehicleTypes.CAR }, - { label: 'Motorcycle', value: VehicleTypes.MOTORCYCLE }, - ]; - - constructor( - private globalErrorService: GlobalErrorService, - private technicalRecordService: TechnicalRecordService, - private batchTechRecordService: BatchTechnicalRecordService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - ) { - this.batchTechRecordService.clearBatch(); - this.technicalRecordService.clearSectionTemplateStates(); - } - - ngOnChanges(): void { - this.isVinUniqueCheckComplete = false; - } - - get isFormValid(): boolean { - const errors: GlobalError[] = []; - - DynamicFormService.validate(this.form, errors); - - this.globalErrorService.setErrors(errors); - - return this.form.valid; - } - - get vehicleStatusOptions(): MultiOptions { - return [ - { label: 'Provisional', value: StatusCodes.PROVISIONAL }, - { label: 'Current', value: StatusCodes.CURRENT }, - ]; - } - - get checkboxOptions(): MultiOptions { - return [{ value: true, label: 'Generate a C/T/Z number on submission of the new record' }]; - } - - toggleVrmInput(checked: CheckboxGroupComponent) { - const { vrmTrm } = this.form.controls; - - if (checked.value) { - vrmTrm.removeValidators(Validators.required); - vrmTrm.setValue(null); - vrmTrm.disable(); - } else { - vrmTrm.addValidators(Validators.required); - vrmTrm.setValue(''); - vrmTrm.enable(); - } - } - - navigateBack() { - this.globalErrorService.clearErrors(); - void this.router.navigate(['..'], { relativeTo: this.route }); - } - - async handleSubmit() { - if (!this.isFormValid) { - return; - } - - this.store.dispatch(setSpinnerState({ showSpinner: true })); - - const formValueUnique = await this.isFormValueUnique(); - - this.store.dispatch(setSpinnerState({ showSpinner: false })); - - if (!formValueUnique) { - this.isDuplicateVinAllowed = true; - return; - } - - this.technicalRecordService.updateEditingTechRecord(this.techRecord as TechRecordType<'put'>); - this.technicalRecordService.generateEditingVehicleTechnicalRecordFromVehicleType(this.techRecord.techRecord_vehicleType as VehicleTypes); - this.technicalRecordService.clearSectionTemplateStates(); - await this.router.navigate(['../create/new-record-details'], { relativeTo: this.route }); - } - - async isFormValueUnique() { - const isTrailer = this.form.value.vehicleType === VehicleTypes.TRL; - - this.techRecord.techRecord_vehicleType = this.form.value.vehicleType; - this.techRecord.techRecord_statusCode = this.form.value.vehicleStatus; - - if (!this.isVinUniqueCheckComplete) { - this.vinUnique = await this.isVinUnique(); - } - - if (this.form.controls['generateID'].value) { - return this.vinUnique || this.isDuplicateVinAllowed; - } - - if (isTrailer) { - this.trlUnique = await this.isTrailerIdUnique(); - return (this.vinUnique || this.isDuplicateVinAllowed) && this.trlUnique; - } - this.vrmUnique = await this.isVrmUnique(); - return (this.vinUnique || this.isDuplicateVinAllowed) && this.vrmUnique; - } - - async isVinUnique(): Promise { - this.techRecord.vin = this.form.value.vin; - const isVinUnique = await firstValueFrom(this.technicalRecordService.isUnique(this.techRecord.vin as string, SEARCH_TYPES.VIN)); - this.isVinUniqueCheckComplete = true; - return isVinUnique; - } - - async isVrmUnique() { - (this.techRecord as VehiclesOtherThan<'trl'>).primaryVrm = this.form.value.vrmTrm; - const isVrmUnique = await firstValueFrom( - this.technicalRecordService.isUnique((this.techRecord as VehiclesOtherThan<'trl'>).primaryVrm?.replace(/\s+/g, '') ?? '', SEARCH_TYPES.VRM), - ); - if (!isVrmUnique) { - this.globalErrorService.addError({ error: 'Vrm not unique', anchorLink: 'input-vrm-or-trailer-id' }); - } - return isVrmUnique; - } - - async isTrailerIdUnique() { - if (this.techRecord.techRecord_vehicleType === 'trl') { - this.techRecord.trailerId = this.form.value.vrmTrm; - const isTrailerIdUnique = await firstValueFrom( - this.technicalRecordService.isUnique(this.techRecord.trailerId as string, SEARCH_TYPES.TRAILER_ID), - ); - if (!isTrailerIdUnique) { - this.globalErrorService.addError({ error: 'TrailerId not unique', anchorLink: 'input-vrm-or-trailer-id' }); - } - return isTrailerIdUnique; - } - return false; - } + techRecord: Partial = {}; + + isDuplicateVinAllowed = false; + isVinUniqueCheckComplete = false; + + vinUnique = false; + vrmUnique = false; + trlUnique = false; + + form = new CustomFormGroup( + { name: 'main-form', type: FormNodeTypes.GROUP }, + { + vin: new CustomFormControl({ name: 'input-vin', label: 'Vin', type: FormNodeTypes.CONTROL }, '', [ + CustomValidators.alphanumeric(), + CustomValidators.validateVinCharacters(), + Validators.minLength(3), + Validators.maxLength(21), + Validators.required, + ]), + vrmTrm: new CustomFormControl( + { name: 'input-vrm-or-trailer-id', label: 'VRM/TRM', type: FormNodeTypes.CONTROL }, + '', + [ + CustomValidators.alphanumeric(), + CustomValidators.notZNumber, + CustomValidators.validateVRMTrailerIdLength('vehicleType'), + Validators.required, + ] + ), + vehicleStatus: new CustomFormControl( + { name: 'change-vehicle-status-select', label: 'Vehicle status', type: FormNodeTypes.CONTROL }, + StatusCodes.PROVISIONAL, + [Validators.required] + ), + vehicleType: new CustomFormControl( + { name: 'change-vehicle-type-select', label: 'Vehicle type', type: FormNodeTypes.CONTROL }, + '', + [Validators.required] + ), + generateID: new CustomFormControl({ name: 'generate-c-or-z-num', type: FormNodeTypes.CONTROL }, null), + } + ); + + public vehicleTypeOptions: MultiOptions = [ + { label: 'Heavy goods vehicle (HGV)', value: VehicleTypes.HGV }, + { label: 'Light goods vehicle (LGV)', value: VehicleTypes.LGV }, + { label: 'Public service vehicle (PSV)', value: VehicleTypes.PSV }, + { label: 'Trailer (TRL)', value: VehicleTypes.TRL }, + { label: 'Small Trailer (Small TRL)', value: VehicleTypes.SMALL_TRL }, + { label: 'Car', value: VehicleTypes.CAR }, + { label: 'Motorcycle', value: VehicleTypes.MOTORCYCLE }, + ]; + + constructor( + private globalErrorService: GlobalErrorService, + private technicalRecordService: TechnicalRecordService, + private batchTechRecordService: BatchTechnicalRecordService, + private route: ActivatedRoute, + private router: Router, + private store: Store + ) { + this.batchTechRecordService.clearBatch(); + this.technicalRecordService.clearSectionTemplateStates(); + } + + ngOnChanges(): void { + this.isVinUniqueCheckComplete = false; + } + + get isFormValid(): boolean { + const errors: GlobalError[] = []; + + DynamicFormService.validate(this.form, errors); + + this.globalErrorService.setErrors(errors); + + return this.form.valid; + } + + get vehicleStatusOptions(): MultiOptions { + return [ + { label: 'Provisional', value: StatusCodes.PROVISIONAL }, + { label: 'Current', value: StatusCodes.CURRENT }, + ]; + } + + get checkboxOptions(): MultiOptions { + return [{ value: true, label: 'Generate a C/T/Z number on submission of the new record' }]; + } + + toggleVrmInput(checked: CheckboxGroupComponent) { + const { vrmTrm } = this.form.controls; + + if (checked.value) { + vrmTrm.removeValidators(Validators.required); + vrmTrm.setValue(null); + vrmTrm.disable(); + } else { + vrmTrm.addValidators(Validators.required); + vrmTrm.setValue(''); + vrmTrm.enable(); + } + } + + navigateBack() { + this.globalErrorService.clearErrors(); + void this.router.navigate(['..'], { relativeTo: this.route }); + } + + async handleSubmit() { + if (!this.isFormValid) { + return; + } + + this.store.dispatch(setSpinnerState({ showSpinner: true })); + + const formValueUnique = await this.isFormValueUnique(); + + this.store.dispatch(setSpinnerState({ showSpinner: false })); + + if (!formValueUnique) { + this.isDuplicateVinAllowed = true; + return; + } + + this.technicalRecordService.updateEditingTechRecord(this.techRecord as TechRecordType<'put'>); + this.technicalRecordService.generateEditingVehicleTechnicalRecordFromVehicleType( + this.techRecord.techRecord_vehicleType as VehicleTypes + ); + this.technicalRecordService.clearSectionTemplateStates(); + await this.router.navigate(['../create/new-record-details'], { relativeTo: this.route }); + } + + async isFormValueUnique() { + const isTrailer = this.form.value.vehicleType === VehicleTypes.TRL; + + this.techRecord.techRecord_vehicleType = this.form.value.vehicleType; + this.techRecord.techRecord_statusCode = this.form.value.vehicleStatus; + + if (!this.isVinUniqueCheckComplete) { + this.vinUnique = await this.isVinUnique(); + } + + if (this.form.controls['generateID'].value) { + return this.vinUnique || this.isDuplicateVinAllowed; + } + + if (isTrailer) { + this.trlUnique = await this.isTrailerIdUnique(); + return (this.vinUnique || this.isDuplicateVinAllowed) && this.trlUnique; + } + this.vrmUnique = await this.isVrmUnique(); + return (this.vinUnique || this.isDuplicateVinAllowed) && this.vrmUnique; + } + + async isVinUnique(): Promise { + this.techRecord.vin = this.form.value.vin; + const isVinUnique = await firstValueFrom( + this.technicalRecordService.isUnique(this.techRecord.vin as string, SEARCH_TYPES.VIN) + ); + this.isVinUniqueCheckComplete = true; + return isVinUnique; + } + + async isVrmUnique() { + (this.techRecord as VehiclesOtherThan<'trl'>).primaryVrm = this.form.value.vrmTrm; + const isVrmUnique = await firstValueFrom( + this.technicalRecordService.isUnique( + (this.techRecord as VehiclesOtherThan<'trl'>).primaryVrm?.replace(/\s+/g, '') ?? '', + SEARCH_TYPES.VRM + ) + ); + if (!isVrmUnique) { + this.globalErrorService.addError({ error: 'Vrm not unique', anchorLink: 'input-vrm-or-trailer-id' }); + } + return isVrmUnique; + } + + async isTrailerIdUnique() { + if (this.techRecord.techRecord_vehicleType === 'trl') { + this.techRecord.trailerId = this.form.value.vrmTrm; + const isTrailerIdUnique = await firstValueFrom( + this.technicalRecordService.isUnique(this.techRecord.trailerId as string, SEARCH_TYPES.TRAILER_ID) + ); + if (!isTrailerIdUnique) { + this.globalErrorService.addError({ error: 'TrailerId not unique', anchorLink: 'input-vrm-or-trailer-id' }); + } + return isTrailerIdUnique; + } + return false; + } } diff --git a/src/app/features/tech-record/create/create-tech-records-routing.module.ts b/src/app/features/tech-record/create/create-tech-records-routing.module.ts index 5cfe959056..d5cff87835 100644 --- a/src/app/features/tech-record/create/create-tech-records-routing.module.ts +++ b/src/app/features/tech-record/create/create-tech-records-routing.module.ts @@ -3,46 +3,49 @@ import { RouterModule, Routes } from '@angular/router'; import { MsalGuard } from '@azure/msal-angular'; import { RoleGuard } from '@guards/role-guard/roles.guard'; import { Roles } from '@models/roles.enum'; -import { techRecordDataResolver } from 'src/app/resolvers/tech-record-data/tech-record-data.resolver'; import { TechRecordCreateRoutes } from '@models/routes.enum'; +import { techRecordDataResolver } from 'src/app/resolvers/tech-record-data/tech-record-data.resolver'; import { TechRecordSearchTyresComponent } from '../components/tech-record-search-tyres/tech-record-search-tyres.component'; import { HydrateNewVehicleRecordComponent } from './components/hydrate-new-vehicle-record/hydrate-new-vehicle-record.component'; import { CreateTechRecordComponent } from './create-tech-record.component'; const routes: Routes = [ - { - path: '', - resolve: { data: techRecordDataResolver }, - canActivate: [MsalGuard, RoleGuard], - children: [ - { - path: '', - component: CreateTechRecordComponent, - data: { roles: Roles.TechRecordCreate }, - }, - { - path: TechRecordCreateRoutes.NEW_RECORD_DETAILS, - children: [ - { - path: '', - component: HydrateNewVehicleRecordComponent, - data: { - title: 'New record details', roles: Roles.TechRecordCreate, isCustomLayout: true, isEditing: true, - }, - }, - { - path: TechRecordCreateRoutes.TYRE_SEARCH, - component: TechRecordSearchTyresComponent, - data: { title: 'Tyre search', roles: Roles.TechRecordCreate, isEditing: true }, - }, - ], - }, - ], - }, + { + path: '', + resolve: { data: techRecordDataResolver }, + canActivate: [MsalGuard, RoleGuard], + children: [ + { + path: '', + component: CreateTechRecordComponent, + data: { roles: Roles.TechRecordCreate }, + }, + { + path: TechRecordCreateRoutes.NEW_RECORD_DETAILS, + children: [ + { + path: '', + component: HydrateNewVehicleRecordComponent, + data: { + title: 'New record details', + roles: Roles.TechRecordCreate, + isCustomLayout: true, + isEditing: true, + }, + }, + { + path: TechRecordCreateRoutes.TYRE_SEARCH, + component: TechRecordSearchTyresComponent, + data: { title: 'Tyre search', roles: Roles.TechRecordCreate, isEditing: true }, + }, + ], + }, + ], + }, ]; @NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], }) export class CreateTechRecordsRoutingModule {} diff --git a/src/app/features/tech-record/create/create-tech-records.module.ts b/src/app/features/tech-record/create/create-tech-records.module.ts index e6a68f4f90..af4b25a772 100644 --- a/src/app/features/tech-record/create/create-tech-records.module.ts +++ b/src/app/features/tech-record/create/create-tech-records.module.ts @@ -11,16 +11,16 @@ import { CreateTechRecordComponent } from './create-tech-record.component'; import { CreateTechRecordsRoutingModule } from './create-tech-records-routing.module'; @NgModule({ - declarations: [CreateTechRecordComponent, HydrateNewVehicleRecordComponent], - imports: [ - CommonModule, - CreateTechRecordsRoutingModule, - ReactiveFormsModule, - DynamicFormsModule, - RouterModule, - SharedModule, - TechRecordsModule, - SharedTechRecordsModule, - ], + declarations: [CreateTechRecordComponent, HydrateNewVehicleRecordComponent], + imports: [ + CommonModule, + CreateTechRecordsRoutingModule, + ReactiveFormsModule, + DynamicFormsModule, + RouterModule, + SharedModule, + TechRecordsModule, + SharedTechRecordsModule, + ], }) export class CreateTechRecordsModule {} diff --git a/src/app/features/tech-record/shared-tech-record.module.ts b/src/app/features/tech-record/shared-tech-record.module.ts index 37e1f3cd94..95cb64495b 100644 --- a/src/app/features/tech-record/shared-tech-record.module.ts +++ b/src/app/features/tech-record/shared-tech-record.module.ts @@ -6,8 +6,8 @@ import { SharedModule } from '@shared/shared.module'; import { TechRecordSummaryComponent } from './components/tech-record-summary/tech-record-summary.component'; @NgModule({ - declarations: [TechRecordSummaryComponent], - imports: [CommonModule, FormsModule, ReactiveFormsModule, DynamicFormsModule, SharedModule], - exports: [TechRecordSummaryComponent], + declarations: [TechRecordSummaryComponent], + imports: [CommonModule, FormsModule, ReactiveFormsModule, DynamicFormsModule, SharedModule], + exports: [TechRecordSummaryComponent], }) export class SharedTechRecordsModule {} diff --git a/src/app/features/tech-record/tech-record-routing.module.ts b/src/app/features/tech-record/tech-record-routing.module.ts index e56d706ea7..b5aa506c77 100644 --- a/src/app/features/tech-record/tech-record-routing.module.ts +++ b/src/app/features/tech-record/tech-record-routing.module.ts @@ -4,247 +4,230 @@ import { MsalGuard } from '@azure/msal-angular'; import { CancelEditTechGuard } from '@guards/cancel-edit-tech/cancel-edit-tech.guard'; import { RoleGuard } from '@guards/role-guard/roles.guard'; import { Roles } from '@models/roles.enum'; +import { TechRecordRoutes } from '@models/routes.enum'; import { ReasonForEditing } from '@models/vehicle-tech-record.model'; import { techRecordCleanResolver } from 'src/app/resolvers/tech-record-clean/tech-record-clean.resolver'; import { techRecordDataResolver } from 'src/app/resolvers/tech-record-data/tech-record-data.resolver'; import { techRecordValidateResolver } from 'src/app/resolvers/tech-record-validate/tech-record-validate.resolver'; import { techRecordViewResolver } from 'src/app/resolvers/tech-record-view/tech-record-view.resolver'; -import { TechRecordRoutes } from '@models/routes.enum'; -import { - AdrGenerateCertificateComponent, -} from './components/adr-generate-certificate/adr-generate-certificate.component'; -import { - TechRecordAmendReasonComponent, -} from './components/tech-record-amend-reason/tech-record-amend-reason.component'; +import { AdrGenerateCertificateComponent } from './components/adr-generate-certificate/adr-generate-certificate.component'; +import { TechRecordAmendReasonComponent } from './components/tech-record-amend-reason/tech-record-amend-reason.component'; import { AmendVinComponent } from './components/tech-record-amend-vin/tech-record-amend-vin.component'; -import { - AmendVrmReasonComponent, -} from './components/tech-record-amend-vrm-reason/tech-record-amend-vrm-reason.component'; +import { AmendVrmReasonComponent } from './components/tech-record-amend-vrm-reason/tech-record-amend-vrm-reason.component'; import { AmendVrmComponent } from './components/tech-record-amend-vrm/tech-record-amend-vrm.component'; -import { - TechRecordChangeStatusComponent, -} from './components/tech-record-change-status/tech-record-change-status.component'; +import { TechRecordChangeStatusComponent } from './components/tech-record-change-status/tech-record-change-status.component'; import { ChangeVehicleTypeComponent } from './components/tech-record-change-type/tech-record-change-type.component'; -import { - TechRecordChangeVisibilityComponent, -} from './components/tech-record-change-visibility/tech-record-change-visibility.component'; -import { - GenerateLetterComponent, -} from './components/tech-record-generate-letter/tech-record-generate-letter.component'; +import { TechRecordChangeVisibilityComponent } from './components/tech-record-change-visibility/tech-record-change-visibility.component'; +import { TechRecordEditAdditionalExaminerNoteComponent } from './components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component'; +import { GenerateLetterComponent } from './components/tech-record-generate-letter/tech-record-generate-letter.component'; import { GeneratePlateComponent } from './components/tech-record-generate-plate/tech-record-generate-plate.component'; -import { - TechRecordSearchTyresComponent, -} from './components/tech-record-search-tyres/tech-record-search-tyres.component'; -import { - TechRecordSummaryChangesComponent, -} from './components/tech-record-summary-changes/tech-record-summary-changes.component'; +import { TechRecordSearchTyresComponent } from './components/tech-record-search-tyres/tech-record-search-tyres.component'; +import { TechRecordSummaryChangesComponent } from './components/tech-record-summary-changes/tech-record-summary-changes.component'; import { TechRecordUnarchiveComponent } from './components/tech-record-unarchive/tech-record-unarchive-component'; import { TechRecordComponent } from './tech-record.component'; -import { - TechRecordEditAdditionalExaminerNoteComponent, -} from './components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component'; const routes: Routes = [ - { - path: '', - component: TechRecordComponent, - data: { roles: Roles.TechRecordView, isCustomLayout: true }, - canActivateChild: [MsalGuard, RoleGuard], - canActivate: [CancelEditTechGuard], - resolve: { - load: techRecordViewResolver, - data: techRecordDataResolver, - }, - }, - { - path: TechRecordRoutes.CORRECT_ERROR, - component: TechRecordComponent, - data: { - roles: Roles.TechRecordAmend, - isEditing: true, - reason: ReasonForEditing.CORRECTING_AN_ERROR, - isCustomLayout: true, - }, - canActivate: [MsalGuard, RoleGuard], - resolve: { - techRecord: techRecordViewResolver, - load: techRecordValidateResolver, - clean: techRecordCleanResolver, - }, - }, - { - path: TechRecordRoutes.NOTIFIABLE_ALTERATION_NEEDED, - component: TechRecordComponent, - data: { - roles: Roles.TechRecordAmend, - isEditing: true, - reason: ReasonForEditing.NOTIFIABLE_ALTERATION_NEEDED, - isCustomLayout: true, - }, - canActivate: [MsalGuard, RoleGuard], - resolve: { - techRecord: techRecordViewResolver, - load: techRecordValidateResolver, - clean: techRecordCleanResolver, - }, - }, + { + path: '', + component: TechRecordComponent, + data: { roles: Roles.TechRecordView, isCustomLayout: true }, + canActivateChild: [MsalGuard, RoleGuard], + canActivate: [CancelEditTechGuard], + resolve: { + load: techRecordViewResolver, + data: techRecordDataResolver, + }, + }, + { + path: TechRecordRoutes.CORRECT_ERROR, + component: TechRecordComponent, + data: { + roles: Roles.TechRecordAmend, + isEditing: true, + reason: ReasonForEditing.CORRECTING_AN_ERROR, + isCustomLayout: true, + }, + canActivate: [MsalGuard, RoleGuard], + resolve: { + techRecord: techRecordViewResolver, + load: techRecordValidateResolver, + clean: techRecordCleanResolver, + }, + }, + { + path: TechRecordRoutes.NOTIFIABLE_ALTERATION_NEEDED, + component: TechRecordComponent, + data: { + roles: Roles.TechRecordAmend, + isEditing: true, + reason: ReasonForEditing.NOTIFIABLE_ALTERATION_NEEDED, + isCustomLayout: true, + }, + canActivate: [MsalGuard, RoleGuard], + resolve: { + techRecord: techRecordViewResolver, + load: techRecordValidateResolver, + clean: techRecordCleanResolver, + }, + }, - { - path: TechRecordRoutes.CHANGE_VIN, - component: AmendVinComponent, - data: { title: 'Change VIN', roles: Roles.TechRecordAmend }, - canActivate: [MsalGuard, RoleGuard], - }, - { - path: TechRecordRoutes.CHANGE_VRM, - component: AmendVrmReasonComponent, - data: { title: 'Change VRM', roles: Roles.TechRecordAmend, isEditing: true }, - canActivate: [MsalGuard, RoleGuard], - }, - { - path: TechRecordRoutes.REASON_TO_CHANGE_VRM, - component: AmendVrmComponent, - data: { title: 'Change VRM', roles: Roles.TechRecordAmend, isEditing: true }, - canActivate: [MsalGuard, RoleGuard], - }, - { - path: TechRecordRoutes.GENERATE_PLATE, - component: GeneratePlateComponent, - data: { title: 'Generate plate', roles: Roles.TechRecordAmend }, - canActivate: [MsalGuard, RoleGuard], - resolve: { load: techRecordViewResolver }, - }, - { - path: TechRecordRoutes.GENERATE_LETTER, - component: GenerateLetterComponent, - data: { title: 'Generate letter', roles: Roles.TechRecordAmend }, - canActivate: [MsalGuard, RoleGuard], - resolve: { load: techRecordViewResolver }, - }, - { - path: TechRecordRoutes.AMEND_REASON, - component: TechRecordAmendReasonComponent, - data: { roles: Roles.TechRecordAmend }, - canActivate: [MsalGuard, RoleGuard], - }, - { - path: TechRecordRoutes.CHANGE_STATUS, - component: TechRecordChangeStatusComponent, - data: { title: 'Promote or Archive Tech Record', roles: Roles.TechRecordArchive }, - canActivate: [MsalGuard, RoleGuard], - resolve: { load: techRecordViewResolver }, - }, - { - path: TechRecordRoutes.UNARCHIVE_RECORD, - component: TechRecordUnarchiveComponent, - data: { title: 'Unarchive Record', roles: Roles.TechRecordUnarchive }, - canActivate: [MsalGuard, RoleGuard], - resolve: { load: techRecordViewResolver }, - }, - { - path: TechRecordRoutes.CHANGE_VEHICLE_TYPE, - component: ChangeVehicleTypeComponent, - data: { title: 'Change vehicle type', roles: Roles.TechRecordAmend, isEditing: true }, - canActivate: [MsalGuard, RoleGuard], - resolve: { techRecord: techRecordViewResolver }, - }, - { - path: TechRecordRoutes.CHANGE_VTA_VISIBILITY, - component: TechRecordChangeVisibilityComponent, - data: { roles: Roles.TechRecordAmend }, - canActivate: [MsalGuard, RoleGuard], - resolve: { techRecord: techRecordViewResolver }, - }, - { - path: TechRecordRoutes.CORRECT_ERROR_TYRE_SEARCH, - component: TechRecordSearchTyresComponent, - data: { - title: 'Tyre search', - roles: Roles.TechRecordAmend, - isEditing: true, - reason: ReasonForEditing.CORRECTING_AN_ERROR, - }, - canActivate: [MsalGuard, RoleGuard], - resolve: { techRecord: techRecordViewResolver }, - }, - { - path: TechRecordRoutes.CORRECT_ERROR_CHANGE_SUMMARY, - component: TechRecordSummaryChangesComponent, - data: { - roles: Roles.TechRecordAmend, - isEditing: true, - }, - canActivate: [MsalGuard, RoleGuard], - }, - { - path: TechRecordRoutes.CORRECT_ERROR_EDIT_ADDITIONAL_EXAMINER_NOTE, - component: TechRecordEditAdditionalExaminerNoteComponent, - data: { - title: 'Edit Additional Examiner Note', - roles: Roles.TechRecordAmend, - isEditing: true, - reason: ReasonForEditing.CORRECTING_AN_ERROR, - }, - canActivate: [MsalGuard, RoleGuard], - resolve: { techRecord: techRecordViewResolver }, - }, - { - path: TechRecordRoutes.NOTIFIABLE_ALTERATION_NEEDED_CHANGE_SUMMARY, - component: TechRecordSummaryChangesComponent, - data: { - roles: Roles.TechRecordAmend, - isEditing: true, - }, - canActivate: [MsalGuard, RoleGuard], - }, - { - path: TechRecordRoutes.NOTIFIABLE_ALTERATION_NEEDED_TYRE_SEARCH, - component: TechRecordSearchTyresComponent, - data: { - title: 'Tyre search', - roles: Roles.TechRecordAmend, - isEditing: true, - reason: ReasonForEditing.NOTIFIABLE_ALTERATION_NEEDED, - }, - canActivate: [MsalGuard, RoleGuard], - resolve: { techRecord: techRecordViewResolver }, - }, - { - path: TechRecordRoutes.NOTIFIABLE_ALTERNATION_NEEDED_EDIT_ADDITIONAL_EXAMINER_NOTE, - component: TechRecordEditAdditionalExaminerNoteComponent, - data: { - title: 'Edit Additional Examiner Note', - roles: Roles.TechRecordAmend, - isEditing: true, - reason: ReasonForEditing.NOTIFIABLE_ALTERATION_NEEDED, - }, - canActivate: [MsalGuard, RoleGuard], - resolve: { techRecord: techRecordViewResolver }, - }, - { - path: TechRecordRoutes.TEST_RECORDS, - data: { title: 'Test record', roles: Roles.TestResultView }, - canActivate: [MsalGuard, RoleGuard], - resolve: { techRecord: techRecordViewResolver }, - loadChildren: () => import('../test-records/amend/amend-test-records.module').then((m) => m.AmendTestRecordsModule), - }, - { - path: TechRecordRoutes.CREATE_TEST, - data: { title: 'Create Contingency test', roles: Roles.TestResultCreateContingency }, - canActivate: [MsalGuard, RoleGuard], - resolve: { techRecord: techRecordViewResolver }, - loadChildren: () => import('../test-records/create/create-test-records.module').then((m) => m.CreateTestRecordsModule), - }, - { - path: TechRecordRoutes.ADR_CERTIFICATE, - component: AdrGenerateCertificateComponent, - data: { title: 'Generate ADR Certificate', roles: Roles.TestResultCreateDeskAssessment }, - canActivate: [MsalGuard, RoleGuard], - }, + { + path: TechRecordRoutes.CHANGE_VIN, + component: AmendVinComponent, + data: { title: 'Change VIN', roles: Roles.TechRecordAmend }, + canActivate: [MsalGuard, RoleGuard], + }, + { + path: TechRecordRoutes.CHANGE_VRM, + component: AmendVrmReasonComponent, + data: { title: 'Change VRM', roles: Roles.TechRecordAmend, isEditing: true }, + canActivate: [MsalGuard, RoleGuard], + }, + { + path: TechRecordRoutes.REASON_TO_CHANGE_VRM, + component: AmendVrmComponent, + data: { title: 'Change VRM', roles: Roles.TechRecordAmend, isEditing: true }, + canActivate: [MsalGuard, RoleGuard], + }, + { + path: TechRecordRoutes.GENERATE_PLATE, + component: GeneratePlateComponent, + data: { title: 'Generate plate', roles: Roles.TechRecordAmend }, + canActivate: [MsalGuard, RoleGuard], + resolve: { load: techRecordViewResolver }, + }, + { + path: TechRecordRoutes.GENERATE_LETTER, + component: GenerateLetterComponent, + data: { title: 'Generate letter', roles: Roles.TechRecordAmend }, + canActivate: [MsalGuard, RoleGuard], + resolve: { load: techRecordViewResolver }, + }, + { + path: TechRecordRoutes.AMEND_REASON, + component: TechRecordAmendReasonComponent, + data: { roles: Roles.TechRecordAmend }, + canActivate: [MsalGuard, RoleGuard], + }, + { + path: TechRecordRoutes.CHANGE_STATUS, + component: TechRecordChangeStatusComponent, + data: { title: 'Promote or Archive Tech Record', roles: Roles.TechRecordArchive }, + canActivate: [MsalGuard, RoleGuard], + resolve: { load: techRecordViewResolver }, + }, + { + path: TechRecordRoutes.UNARCHIVE_RECORD, + component: TechRecordUnarchiveComponent, + data: { title: 'Unarchive Record', roles: Roles.TechRecordUnarchive }, + canActivate: [MsalGuard, RoleGuard], + resolve: { load: techRecordViewResolver }, + }, + { + path: TechRecordRoutes.CHANGE_VEHICLE_TYPE, + component: ChangeVehicleTypeComponent, + data: { title: 'Change vehicle type', roles: Roles.TechRecordAmend, isEditing: true }, + canActivate: [MsalGuard, RoleGuard], + resolve: { techRecord: techRecordViewResolver }, + }, + { + path: TechRecordRoutes.CHANGE_VTA_VISIBILITY, + component: TechRecordChangeVisibilityComponent, + data: { roles: Roles.TechRecordAmend }, + canActivate: [MsalGuard, RoleGuard], + resolve: { techRecord: techRecordViewResolver }, + }, + { + path: TechRecordRoutes.CORRECT_ERROR_TYRE_SEARCH, + component: TechRecordSearchTyresComponent, + data: { + title: 'Tyre search', + roles: Roles.TechRecordAmend, + isEditing: true, + reason: ReasonForEditing.CORRECTING_AN_ERROR, + }, + canActivate: [MsalGuard, RoleGuard], + resolve: { techRecord: techRecordViewResolver }, + }, + { + path: TechRecordRoutes.CORRECT_ERROR_CHANGE_SUMMARY, + component: TechRecordSummaryChangesComponent, + data: { + roles: Roles.TechRecordAmend, + isEditing: true, + }, + canActivate: [MsalGuard, RoleGuard], + }, + { + path: TechRecordRoutes.CORRECT_ERROR_EDIT_ADDITIONAL_EXAMINER_NOTE, + component: TechRecordEditAdditionalExaminerNoteComponent, + data: { + title: 'Edit Additional Examiner Note', + roles: Roles.TechRecordAmend, + isEditing: true, + reason: ReasonForEditing.CORRECTING_AN_ERROR, + }, + canActivate: [MsalGuard, RoleGuard], + resolve: { techRecord: techRecordViewResolver }, + }, + { + path: TechRecordRoutes.NOTIFIABLE_ALTERATION_NEEDED_CHANGE_SUMMARY, + component: TechRecordSummaryChangesComponent, + data: { + roles: Roles.TechRecordAmend, + isEditing: true, + }, + canActivate: [MsalGuard, RoleGuard], + }, + { + path: TechRecordRoutes.NOTIFIABLE_ALTERATION_NEEDED_TYRE_SEARCH, + component: TechRecordSearchTyresComponent, + data: { + title: 'Tyre search', + roles: Roles.TechRecordAmend, + isEditing: true, + reason: ReasonForEditing.NOTIFIABLE_ALTERATION_NEEDED, + }, + canActivate: [MsalGuard, RoleGuard], + resolve: { techRecord: techRecordViewResolver }, + }, + { + path: TechRecordRoutes.NOTIFIABLE_ALTERNATION_NEEDED_EDIT_ADDITIONAL_EXAMINER_NOTE, + component: TechRecordEditAdditionalExaminerNoteComponent, + data: { + title: 'Edit Additional Examiner Note', + roles: Roles.TechRecordAmend, + isEditing: true, + reason: ReasonForEditing.NOTIFIABLE_ALTERATION_NEEDED, + }, + canActivate: [MsalGuard, RoleGuard], + resolve: { techRecord: techRecordViewResolver }, + }, + { + path: TechRecordRoutes.TEST_RECORDS, + data: { title: 'Test record', roles: Roles.TestResultView }, + canActivate: [MsalGuard, RoleGuard], + resolve: { techRecord: techRecordViewResolver }, + loadChildren: () => import('../test-records/amend/amend-test-records.module').then((m) => m.AmendTestRecordsModule), + }, + { + path: TechRecordRoutes.CREATE_TEST, + data: { title: 'Create Contingency test', roles: Roles.TestResultCreateContingency }, + canActivate: [MsalGuard, RoleGuard], + resolve: { techRecord: techRecordViewResolver }, + loadChildren: () => + import('../test-records/create/create-test-records.module').then((m) => m.CreateTestRecordsModule), + }, + { + path: TechRecordRoutes.ADR_CERTIFICATE, + component: AdrGenerateCertificateComponent, + data: { title: 'Generate ADR Certificate', roles: Roles.TestResultCreateDeskAssessment }, + canActivate: [MsalGuard, RoleGuard], + }, ]; @NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], }) -export class TechRecordsRoutingModule { } +export class TechRecordsRoutingModule {} diff --git a/src/app/features/tech-record/tech-record.component.spec.ts b/src/app/features/tech-record/tech-record.component.spec.ts index d2b443c28a..ed7b0aa8bf 100644 --- a/src/app/features/tech-record/tech-record.component.spec.ts +++ b/src/app/features/tech-record/tech-record.component.spec.ts @@ -1,59 +1,59 @@ +import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MockStore, provideMockStore } from '@ngrx/store/testing'; -import { initialAppState, State } from '@store/.'; +import { ActivatedRouteSnapshot } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { selectRouteNestedParams } from '@store/router/selectors/router.selectors'; -import { Roles } from '@models/roles.enum'; import { GlobalError } from '@core/components/global-error/global-error.interface'; -import { ActivatedRouteSnapshot } from '@angular/router'; +import { Roles } from '@models/roles.enum'; +import { MockStore, provideMockStore } from '@ngrx/store/testing'; +import { State, initialAppState } from '@store/.'; +import { selectRouteNestedParams } from '@store/router/selectors/router.selectors'; import { TechRecordComponent } from './tech-record.component'; describe('TechRecordComponent', () => { - let component: TechRecordComponent; - let fixture: ComponentFixture; - let store: MockStore; + let component: TechRecordComponent; + let fixture: ComponentFixture; + let store: MockStore; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [RouterTestingModule, HttpClientTestingModule], - declarations: [TechRecordComponent], - providers: [provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [RouterTestingModule, HttpClientTestingModule], + declarations: [TechRecordComponent], + providers: [provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); - beforeEach(() => { - store = TestBed.inject(MockStore); - store.overrideSelector(selectRouteNestedParams, { vin: '123456' }); + beforeEach(() => { + store = TestBed.inject(MockStore); + store.overrideSelector(selectRouteNestedParams, { vin: '123456' }); - fixture = TestBed.createComponent(TechRecordComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(TechRecordComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it('should return roles', () => { - const { roles } = component; + it('should return roles', () => { + const { roles } = component; - expect(roles).toBe(Roles); - }); + expect(roles).toBe(Roles); + }); - it('should return error', () => { - const expectedError: GlobalError = { error: 'some error', anchorLink: 'expected' }; + it('should return error', () => { + const expectedError: GlobalError = { error: 'some error', anchorLink: 'expected' }; - const expectedResult = component.getErrorByName([expectedError], expectedError.anchorLink ?? ''); + const expectedResult = component.getErrorByName([expectedError], expectedError.anchorLink ?? ''); - expect(expectedResult).toBe(expectedError); - }); + expect(expectedResult).toBe(expectedError); + }); - it('reuse strategy should be set to false', () => { - const snapshot = {} as ActivatedRouteSnapshot; + it('reuse strategy should be set to false', () => { + const snapshot = {} as ActivatedRouteSnapshot; - const expectedResult = (component['router']).routeReuseStrategy.shouldReuseRoute(snapshot, snapshot); + const expectedResult = component['router'].routeReuseStrategy.shouldReuseRoute(snapshot, snapshot); - expect(expectedResult).toBeFalsy(); - }); + expect(expectedResult).toBeFalsy(); + }); }); diff --git a/src/app/features/tech-record/tech-record.component.ts b/src/app/features/tech-record/tech-record.component.ts index f87a0bf1cc..683a3717e5 100644 --- a/src/app/features/tech-record/tech-record.component.ts +++ b/src/app/features/tech-record/tech-record.component.ts @@ -7,38 +7,38 @@ import { TechnicalRecordService } from '@services/technical-record/technical-rec import { take } from 'rxjs'; @Component({ - selector: 'app-tech-record', - templateUrl: './tech-record.component.html', + selector: 'app-tech-record', + templateUrl: './tech-record.component.html', }) export class TechRecordComponent implements OnInit { - systemNumber?: string; - createdTimestamp?: string; + systemNumber?: string; + createdTimestamp?: string; - constructor( - private techRecordService: TechnicalRecordService, - private router: Router, - public errorService: GlobalErrorService, - private route: ActivatedRoute, - ) { - this.router.routeReuseStrategy.shouldReuseRoute = () => false; - } + constructor( + private techRecordService: TechnicalRecordService, + private router: Router, + public errorService: GlobalErrorService, + private route: ActivatedRoute + ) { + this.router.routeReuseStrategy.shouldReuseRoute = () => false; + } - ngOnInit(): void { - this.route.params.pipe(take(1)).subscribe((params) => { - this.systemNumber = params['systemNumber']; - this.createdTimestamp = params['createdTimestamp']; - }); - } + ngOnInit(): void { + this.route.params.pipe(take(1)).subscribe((params) => { + this.systemNumber = params['systemNumber']; + this.createdTimestamp = params['createdTimestamp']; + }); + } - get techRecord$() { - return this.techRecordService.techRecord$; - } + get techRecord$() { + return this.techRecordService.techRecord$; + } - get roles() { - return Roles; - } + get roles() { + return Roles; + } - getErrorByName(errors: GlobalError[], name: string): GlobalError | undefined { - return errors.find((error) => error.anchorLink === name); - } + getErrorByName(errors: GlobalError[], name: string): GlobalError | undefined { + return errors.find((error) => error.anchorLink === name); + } } diff --git a/src/app/features/tech-record/tech-record.module.ts b/src/app/features/tech-record/tech-record.module.ts index 34c34563bf..74fa05f3c1 100644 --- a/src/app/features/tech-record/tech-record.module.ts +++ b/src/app/features/tech-record/tech-record.module.ts @@ -3,57 +3,62 @@ import { NgModule } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { DynamicFormsModule } from '@forms/dynamic-forms.module'; import { SharedModule } from '@shared/shared.module'; +import { AdrGenerateCertificateComponent } from './components/adr-generate-certificate/adr-generate-certificate.component'; import { EditTechRecordButtonComponent } from './components/edit-tech-record-button/edit-tech-record-button.component'; import { TechRecordAmendReasonComponent } from './components/tech-record-amend-reason/tech-record-amend-reason.component'; import { AmendVinComponent } from './components/tech-record-amend-vin/tech-record-amend-vin.component'; +import { AmendVrmReasonComponent } from './components/tech-record-amend-vrm-reason/tech-record-amend-vrm-reason.component'; import { AmendVrmComponent } from './components/tech-record-amend-vrm/tech-record-amend-vrm.component'; import { TechRecordChangeStatusComponent } from './components/tech-record-change-status/tech-record-change-status.component'; -import { TechRecordUnarchiveComponent } from './components/tech-record-unarchive/tech-record-unarchive-component'; import { ChangeVehicleTypeComponent } from './components/tech-record-change-type/tech-record-change-type.component'; import { TechRecordChangeVisibilityComponent } from './components/tech-record-change-visibility/tech-record-change-visibility.component'; +import { TechRecordEditAdditionalExaminerNoteComponent } from './components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component'; import { GenerateLetterComponent } from './components/tech-record-generate-letter/tech-record-generate-letter.component'; import { GeneratePlateComponent } from './components/tech-record-generate-plate/tech-record-generate-plate.component'; import { TechRecordHistoryComponent } from './components/tech-record-history/tech-record-history.component'; import { TechRecordSearchTyresComponent } from './components/tech-record-search-tyres/tech-record-search-tyres.component'; +import { TechRecordSummaryChangesComponent } from './components/tech-record-summary-changes/tech-record-summary-changes.component'; import { TechRecordTitleComponent } from './components/tech-record-title/tech-record-title.component'; +import { TechRecordUnarchiveComponent } from './components/tech-record-unarchive/tech-record-unarchive-component'; import { TechRouterOutletComponent } from './components/tech-router-outlet/tech-router-outlet.component'; import { TestRecordSummaryComponent } from './components/test-record-summary/test-record-summary.component'; import { VehicleTechnicalRecordComponent } from './components/vehicle-technical-record/vehicle-technical-record.component'; import { SharedTechRecordsModule } from './shared-tech-record.module'; import { TechRecordsRoutingModule } from './tech-record-routing.module'; import { TechRecordComponent } from './tech-record.component'; -import { AmendVrmReasonComponent } from './components/tech-record-amend-vrm-reason/tech-record-amend-vrm-reason.component'; -import { TechRecordSummaryChangesComponent } from './components/tech-record-summary-changes/tech-record-summary-changes.component'; -import { AdrGenerateCertificateComponent } from './components/adr-generate-certificate/adr-generate-certificate.component'; -import { - TechRecordEditAdditionalExaminerNoteComponent, -} from './components/tech-record-edit-additional-examiner-note/tech-record-edit-additional-examiner-note.component'; @NgModule({ - declarations: [ - AmendVinComponent, - AmendVrmComponent, - AmendVrmReasonComponent, - ChangeVehicleTypeComponent, - EditTechRecordButtonComponent, - TechRecordAmendReasonComponent, - TechRecordComponent, - TechRecordChangeStatusComponent, - TechRecordUnarchiveComponent, - TechRecordChangeVisibilityComponent, - GeneratePlateComponent, - GenerateLetterComponent, - TechRecordHistoryComponent, - TechRecordSearchTyresComponent, - TechRecordTitleComponent, - TechRecordEditAdditionalExaminerNoteComponent, - TechRouterOutletComponent, - TestRecordSummaryComponent, - VehicleTechnicalRecordComponent, - TechRecordSummaryChangesComponent, - AdrGenerateCertificateComponent, - ], - imports: [CommonModule, DynamicFormsModule, ReactiveFormsModule, SharedModule, TechRecordsRoutingModule, SharedTechRecordsModule], - exports: [EditTechRecordButtonComponent, TechRecordTitleComponent], + declarations: [ + AmendVinComponent, + AmendVrmComponent, + AmendVrmReasonComponent, + ChangeVehicleTypeComponent, + EditTechRecordButtonComponent, + TechRecordAmendReasonComponent, + TechRecordComponent, + TechRecordChangeStatusComponent, + TechRecordUnarchiveComponent, + TechRecordChangeVisibilityComponent, + GeneratePlateComponent, + GenerateLetterComponent, + TechRecordHistoryComponent, + TechRecordSearchTyresComponent, + TechRecordTitleComponent, + TechRecordEditAdditionalExaminerNoteComponent, + TechRouterOutletComponent, + TestRecordSummaryComponent, + VehicleTechnicalRecordComponent, + TechRecordSummaryChangesComponent, + AdrGenerateCertificateComponent, + ], + imports: [ + CommonModule, + DynamicFormsModule, + ReactiveFormsModule, + SharedModule, + TechRecordsRoutingModule, + SharedTechRecordsModule, + ], + exports: [EditTechRecordButtonComponent, TechRecordTitleComponent], }) export class TechRecordsModule {} diff --git a/src/app/features/test-records/amend/amend-test-records-routing.module.ts b/src/app/features/test-records/amend/amend-test-records-routing.module.ts index b1d61e86b9..121155f7a1 100644 --- a/src/app/features/test-records/amend/amend-test-records-routing.module.ts +++ b/src/app/features/test-records/amend/amend-test-records-routing.module.ts @@ -21,136 +21,140 @@ import { TestRouterOutletComponent } from './views/test-router-outlet/test-route import { TestTypeSelectWrapperComponent } from './views/test-type-select-wrapper/test-type-select-wrapper.component'; const routes: Routes = [ - { - path: '', - component: TestRouterOutletComponent, - resolve: { load: testResultResolver, testTypeTaxonomy: testTypeTaxonomyResolver }, - children: [ - { - path: '', - component: TestResultSummaryComponent, - }, - { - path: TestRecordAmendRoutes.AMEND_TEST, - component: TestRouterOutletComponent, - data: { title: 'Amend test record', roles: Roles.TestResultAmend }, - canActivate: [RoleGuard], - children: [ - { - path: '', - component: TestAmendReasonComponent, - }, - { - path: TestRecordAmendRoutes.INCORRECT_TEST_TYPE, - component: TestRouterOutletComponent, - data: { title: 'Select a test type', roles: Roles.TestResultAmend }, - resolve: { testTypeTaxonomy: testTypeTaxonomyResolver }, - canActivate: [RoleGuard], - children: [ - { - path: '', - component: TestTypeSelectWrapperComponent, - }, - ], - }, - { - path: TestRecordAmendRoutes.TEST_DETAILS, - component: TestRouterOutletComponent, - data: { title: 'Test details', roles: Roles.TestResultAmend }, - resolve: { load: testResultResolver, testTypeTaxonomy: testTypeTaxonomyResolver, defectTaxonomy: defectsTaxonomyResolver }, - canActivate: [RoleGuard], - canDeactivate: [CancelEditTestGuard], - children: [ - { - path: '', - component: TestRecordComponent, - }, - { - path: TestRecordAmendRoutes.DEFECT, - component: DefectComponent, - data: { title: 'Defect', roles: Roles.TestResultAmend, isEditing: true }, - canActivate: [RoleGuard], - }, - { - path: TestRecordAmendRoutes.SELECT_DEFECT, - component: TestRouterOutletComponent, - data: { title: 'Select defect', roles: Roles.TestResultAmend }, - canActivate: [RoleGuard], - children: [ - { - path: '', - component: DefectSelectComponent, - canActivate: [RoleGuard], - }, - { - path: TestRecordAmendRoutes.SELECT_DEFECT_REFERENCE, - component: DefectComponent, - data: { title: 'Defect', roles: Roles.TestResultAmend, isEditing: true }, - canActivate: [RoleGuard], - }, - ], - }, - { - path: TestRecordAmendRoutes.REQUIRED_STANDARD, - component: RequiredStandardComponent, - data: { title: 'Required Standard', roles: Roles.TestResultAmend, isEditing: true }, - canActivate: [RoleGuard], - }, - { - path: TestRecordAmendRoutes.SELECT_REQUIRED_STANDARD, - component: TestRouterOutletComponent, - resolve: { RequiredStandards: requiredStandardsResolver }, - data: { title: 'Select Required Standard', roles: Roles.TestResultAmend }, - children: [ - { - path: '', - component: RequiredStandardSelectComponent, - canActivate: [RoleGuard], - }, - { - path: TestRecordAmendRoutes.REQUIRED_STANDARD_REF, - component: RequiredStandardComponent, - data: { title: 'Required Standard', roles: Roles.TestResultAmend, isEditing: true }, - canActivate: [RoleGuard], - }, - ], - }, - ], - }, - ], - }, - { - path: TestRecordAmendRoutes.AMENDED_TEST, - component: AmendedTestRecordComponent, - data: { title: 'Amended test result', roles: Roles.TestResultView }, - canActivate: [RoleGuard], - }, - { - path: TestRecordAmendRoutes.CANCEL_TEST, - component: ConfirmCancellationComponent, - data: { title: 'Cancel test result', roles: Roles.TestResultAmend }, - canActivate: [RoleGuard], - }, - { - path: TestRecordAmendRoutes.DEFECT, - component: DefectComponent, - data: { title: 'Defect', roles: Roles.TestResultView, isEditing: false }, - resolve: { load: testResultResolver }, - canActivate: [RoleGuard], - }, - { - path: TestRecordAmendRoutes.REQUIRED_STANDARD, - component: RequiredStandardComponent, - data: { title: 'Required Standard', roles: Roles.TestResultView, isEditing: false }, - resolve: { load: testResultResolver }, - canActivate: [RoleGuard], - }, - ], - }, + { + path: '', + component: TestRouterOutletComponent, + resolve: { load: testResultResolver, testTypeTaxonomy: testTypeTaxonomyResolver }, + children: [ + { + path: '', + component: TestResultSummaryComponent, + }, + { + path: TestRecordAmendRoutes.AMEND_TEST, + component: TestRouterOutletComponent, + data: { title: 'Amend test record', roles: Roles.TestResultAmend }, + canActivate: [RoleGuard], + children: [ + { + path: '', + component: TestAmendReasonComponent, + }, + { + path: TestRecordAmendRoutes.INCORRECT_TEST_TYPE, + component: TestRouterOutletComponent, + data: { title: 'Select a test type', roles: Roles.TestResultAmend }, + resolve: { testTypeTaxonomy: testTypeTaxonomyResolver }, + canActivate: [RoleGuard], + children: [ + { + path: '', + component: TestTypeSelectWrapperComponent, + }, + ], + }, + { + path: TestRecordAmendRoutes.TEST_DETAILS, + component: TestRouterOutletComponent, + data: { title: 'Test details', roles: Roles.TestResultAmend }, + resolve: { + load: testResultResolver, + testTypeTaxonomy: testTypeTaxonomyResolver, + defectTaxonomy: defectsTaxonomyResolver, + }, + canActivate: [RoleGuard], + canDeactivate: [CancelEditTestGuard], + children: [ + { + path: '', + component: TestRecordComponent, + }, + { + path: TestRecordAmendRoutes.DEFECT, + component: DefectComponent, + data: { title: 'Defect', roles: Roles.TestResultAmend, isEditing: true }, + canActivate: [RoleGuard], + }, + { + path: TestRecordAmendRoutes.SELECT_DEFECT, + component: TestRouterOutletComponent, + data: { title: 'Select defect', roles: Roles.TestResultAmend }, + canActivate: [RoleGuard], + children: [ + { + path: '', + component: DefectSelectComponent, + canActivate: [RoleGuard], + }, + { + path: TestRecordAmendRoutes.SELECT_DEFECT_REFERENCE, + component: DefectComponent, + data: { title: 'Defect', roles: Roles.TestResultAmend, isEditing: true }, + canActivate: [RoleGuard], + }, + ], + }, + { + path: TestRecordAmendRoutes.REQUIRED_STANDARD, + component: RequiredStandardComponent, + data: { title: 'Required Standard', roles: Roles.TestResultAmend, isEditing: true }, + canActivate: [RoleGuard], + }, + { + path: TestRecordAmendRoutes.SELECT_REQUIRED_STANDARD, + component: TestRouterOutletComponent, + resolve: { RequiredStandards: requiredStandardsResolver }, + data: { title: 'Select Required Standard', roles: Roles.TestResultAmend }, + children: [ + { + path: '', + component: RequiredStandardSelectComponent, + canActivate: [RoleGuard], + }, + { + path: TestRecordAmendRoutes.REQUIRED_STANDARD_REF, + component: RequiredStandardComponent, + data: { title: 'Required Standard', roles: Roles.TestResultAmend, isEditing: true }, + canActivate: [RoleGuard], + }, + ], + }, + ], + }, + ], + }, + { + path: TestRecordAmendRoutes.AMENDED_TEST, + component: AmendedTestRecordComponent, + data: { title: 'Amended test result', roles: Roles.TestResultView }, + canActivate: [RoleGuard], + }, + { + path: TestRecordAmendRoutes.CANCEL_TEST, + component: ConfirmCancellationComponent, + data: { title: 'Cancel test result', roles: Roles.TestResultAmend }, + canActivate: [RoleGuard], + }, + { + path: TestRecordAmendRoutes.DEFECT, + component: DefectComponent, + data: { title: 'Defect', roles: Roles.TestResultView, isEditing: false }, + resolve: { load: testResultResolver }, + canActivate: [RoleGuard], + }, + { + path: TestRecordAmendRoutes.REQUIRED_STANDARD, + component: RequiredStandardComponent, + data: { title: 'Required Standard', roles: Roles.TestResultView, isEditing: false }, + resolve: { load: testResultResolver }, + canActivate: [RoleGuard], + }, + ], + }, ]; @NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], }) export class AmendTestRecordsRoutingModule {} diff --git a/src/app/features/test-records/amend/amend-test-records.module.ts b/src/app/features/test-records/amend/amend-test-records.module.ts index 164f22bc8d..309c79a697 100644 --- a/src/app/features/test-records/amend/amend-test-records.module.ts +++ b/src/app/features/test-records/amend/amend-test-records.module.ts @@ -16,17 +16,25 @@ import { TestRouterOutletComponent } from './views/test-router-outlet/test-route import { TestTypeSelectWrapperComponent } from './views/test-type-select-wrapper/test-type-select-wrapper.component'; @NgModule({ - declarations: [ - AmendTestComponent, - AmendedTestRecordComponent, - ConfirmCancellationComponent, - TestAmendmentHistoryComponent, - TestAmendReasonComponent, - TestRecordComponent, - TestResultSummaryComponent, - TestRouterOutletComponent, - TestTypeSelectWrapperComponent, - ], - imports: [AmendTestRecordsRoutingModule, CommonModule, DynamicFormsModule, FormsModule, ReactiveFormsModule, SharedModule, TestRecordsModule], + declarations: [ + AmendTestComponent, + AmendedTestRecordComponent, + ConfirmCancellationComponent, + TestAmendmentHistoryComponent, + TestAmendReasonComponent, + TestRecordComponent, + TestResultSummaryComponent, + TestRouterOutletComponent, + TestTypeSelectWrapperComponent, + ], + imports: [ + AmendTestRecordsRoutingModule, + CommonModule, + DynamicFormsModule, + FormsModule, + ReactiveFormsModule, + SharedModule, + TestRecordsModule, + ], }) export class AmendTestRecordsModule {} diff --git a/src/app/features/test-records/amend/components/test-amendment-history/test-amendment-history.component.spec.ts b/src/app/features/test-records/amend/components/test-amendment-history/test-amendment-history.component.spec.ts index 307a6dd127..860d107029 100644 --- a/src/app/features/test-records/amend/components/test-amendment-history/test-amendment-history.component.spec.ts +++ b/src/app/features/test-records/amend/components/test-amendment-history/test-amendment-history.component.spec.ts @@ -1,7 +1,5 @@ import { formatDate } from '@angular/common'; -import { - ComponentFixture, fakeAsync, TestBed, tick, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { RouterTestingModule } from '@angular/router/testing'; import { mockTestResult, mockTestResultArchived } from '@mocks/mock-test-result'; @@ -9,120 +7,128 @@ import { createMockTestResult } from '@mocks/test-result.mock'; import { TestResultModel } from '@models/test-results/test-result.model'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { DefaultNullOrEmpty } from '@shared/pipes/default-null-or-empty/default-null-or-empty.pipe'; -import { initialAppState, State } from '@store/.'; +import { State, initialAppState } from '@store/.'; import { selectedTestSortedAmendmentHistory } from '@store/test-records'; import { TestAmendmentHistoryComponent } from './test-amendment-history.component'; describe('TestAmendmentHistoryComponent', () => { - let component: TestAmendmentHistoryComponent; - let fixture: ComponentFixture; - let store: MockStore; - const pipe = new DefaultNullOrEmpty(); - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TestAmendmentHistoryComponent, DefaultNullOrEmpty], - imports: [RouterTestingModule], - providers: [provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(TestAmendmentHistoryComponent); - component = fixture.componentInstance; - store = TestBed.inject(MockStore); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('Created By', () => { - it('should return testerName entry if createdByName does not exist', () => { - const data = mockTestResultArchived(); - data.createdByName = undefined as unknown as string; - const name = component.getCreatedByName(data); - - expect(name).toBe(data.testerName); - }); - - it('should return testerName entry if createdByName is empty', () => { - const data = { ...mockTestResultArchived(), createdByName: '' }; - const name = component.getCreatedByName(data as TestResultModel); - - expect(name).toBe(data.testerName); - }); - - it('should return createdByName if createdByName not is empty', () => { - const name = component.getCreatedByName(mockTestResult()); - - expect(name).toBe(mockTestResult().createdByName); - expect(name).not.toEqual(mockTestResult().testerName); - }); - }); - - describe('Table', () => { - it('should render on the DOM', () => { - component.testRecord = mockTestResult(); - fixture.detectChanges(); - - const heading = fixture.debugElement.query(By.css('.govuk-table__caption')); - expect(heading).toBeTruthy(); - expect(heading.nativeElement.innerHTML).toContain('Test record amendment history'); - - const table = fixture.debugElement.query(By.css('.govuk-table__body')); - expect(table).toBeTruthy(); - }); - - describe('Table sorting', () => { - beforeEach(() => { - component.testRecord = createMockTestResult({ - createdAt: '2020-01-01T00:00:00.000Z', - reasonForCreation: 'reasonForCreation', - createdByName: 'Tester Man', - testHistory: [ - createMockTestResult({ - createdAt: new Date('2020-01-01').toISOString(), - createdByName: '_', - }), - ], - }); - fixture.detectChanges(); - }); - - it('should have first row be the current record', () => { - const rows = fixture.debugElement.queryAll(By.css('.govuk-table__row')); - expect(rows[0]).toBeTruthy(); - const cells = fixture.debugElement.queryAll(By.css('.govuk-table__cell')); - expect(cells[0].nativeElement.innerHTML).toBe(pipe.transform(component.testRecord?.reasonForCreation)); - expect(cells[1].nativeElement.innerHTML).toBe(component.testRecord?.createdByName); - expect(cells[2].nativeElement.innerHTML).toBe(formatDate(component.testRecord?.createdAt as string, 'MMM d, yyyy', 'en')); - expect(cells[3].nativeElement.innerHTML).toBe(''); - }); - - it('should have the second row be the first entry from amendement version history', fakeAsync(() => { - store.overrideSelector(selectedTestSortedAmendmentHistory, component.testRecord?.testHistory ?? []); - tick(); - fixture.detectChanges(); - const cells = fixture.debugElement.queryAll(By.css('.govuk-table__cell')); - expect(cells[4].nativeElement.innerHTML).toBe(pipe.transform(component.testRecord?.testHistory?.[0].reasonForCreation)); - expect(cells[5].nativeElement.innerHTML).toBe(pipe.transform(component.testRecord?.testHistory?.[0].createdByName)); - expect(cells[6].nativeElement.innerHTML).toBe(formatDate(component.testRecord?.testHistory?.[0].createdAt as string, 'MMM d, yyyy', 'en')); - expect(cells[7].nativeElement.innerHTML).toContain('View'); - })); - }); - - it('should have links to view amended records', fakeAsync(() => { - component.testRecord = mockTestResult(); - store.overrideSelector(selectedTestSortedAmendmentHistory, component.testRecord.testHistory ?? []); - tick(); - fixture.detectChanges(); - - const links = fixture.debugElement.queryAll(By.css('a')); - - links.forEach((e) => expect(e.nativeElement.innerHTML).toBe('View')); - expect(links).toHaveLength(component.testRecord?.testHistory?.length ?? 0); - })); - }); + let component: TestAmendmentHistoryComponent; + let fixture: ComponentFixture; + let store: MockStore; + const pipe = new DefaultNullOrEmpty(); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TestAmendmentHistoryComponent, DefaultNullOrEmpty], + imports: [RouterTestingModule], + providers: [provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(TestAmendmentHistoryComponent); + component = fixture.componentInstance; + store = TestBed.inject(MockStore); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('Created By', () => { + it('should return testerName entry if createdByName does not exist', () => { + const data = mockTestResultArchived(); + data.createdByName = undefined as unknown as string; + const name = component.getCreatedByName(data); + + expect(name).toBe(data.testerName); + }); + + it('should return testerName entry if createdByName is empty', () => { + const data = { ...mockTestResultArchived(), createdByName: '' }; + const name = component.getCreatedByName(data as TestResultModel); + + expect(name).toBe(data.testerName); + }); + + it('should return createdByName if createdByName not is empty', () => { + const name = component.getCreatedByName(mockTestResult()); + + expect(name).toBe(mockTestResult().createdByName); + expect(name).not.toEqual(mockTestResult().testerName); + }); + }); + + describe('Table', () => { + it('should render on the DOM', () => { + component.testRecord = mockTestResult(); + fixture.detectChanges(); + + const heading = fixture.debugElement.query(By.css('.govuk-table__caption')); + expect(heading).toBeTruthy(); + expect(heading.nativeElement.innerHTML).toContain('Test record amendment history'); + + const table = fixture.debugElement.query(By.css('.govuk-table__body')); + expect(table).toBeTruthy(); + }); + + describe('Table sorting', () => { + beforeEach(() => { + component.testRecord = createMockTestResult({ + createdAt: '2020-01-01T00:00:00.000Z', + reasonForCreation: 'reasonForCreation', + createdByName: 'Tester Man', + testHistory: [ + createMockTestResult({ + createdAt: new Date('2020-01-01').toISOString(), + createdByName: '_', + }), + ], + }); + fixture.detectChanges(); + }); + + it('should have first row be the current record', () => { + const rows = fixture.debugElement.queryAll(By.css('.govuk-table__row')); + expect(rows[0]).toBeTruthy(); + const cells = fixture.debugElement.queryAll(By.css('.govuk-table__cell')); + expect(cells[0].nativeElement.innerHTML).toBe(pipe.transform(component.testRecord?.reasonForCreation)); + expect(cells[1].nativeElement.innerHTML).toBe(component.testRecord?.createdByName); + expect(cells[2].nativeElement.innerHTML).toBe( + formatDate(component.testRecord?.createdAt as string, 'MMM d, yyyy', 'en') + ); + expect(cells[3].nativeElement.innerHTML).toBe(''); + }); + + it('should have the second row be the first entry from amendement version history', fakeAsync(() => { + store.overrideSelector(selectedTestSortedAmendmentHistory, component.testRecord?.testHistory ?? []); + tick(); + fixture.detectChanges(); + const cells = fixture.debugElement.queryAll(By.css('.govuk-table__cell')); + expect(cells[4].nativeElement.innerHTML).toBe( + pipe.transform(component.testRecord?.testHistory?.[0].reasonForCreation) + ); + expect(cells[5].nativeElement.innerHTML).toBe( + pipe.transform(component.testRecord?.testHistory?.[0].createdByName) + ); + expect(cells[6].nativeElement.innerHTML).toBe( + formatDate(component.testRecord?.testHistory?.[0].createdAt as string, 'MMM d, yyyy', 'en') + ); + expect(cells[7].nativeElement.innerHTML).toContain('View'); + })); + }); + + it('should have links to view amended records', fakeAsync(() => { + component.testRecord = mockTestResult(); + store.overrideSelector(selectedTestSortedAmendmentHistory, component.testRecord.testHistory ?? []); + tick(); + fixture.detectChanges(); + + const links = fixture.debugElement.queryAll(By.css('a')); + + links.forEach((e) => expect(e.nativeElement.innerHTML).toBe('View')); + expect(links).toHaveLength(component.testRecord?.testHistory?.length ?? 0); + })); + }); }); diff --git a/src/app/features/test-records/amend/components/test-amendment-history/test-amendment-history.component.ts b/src/app/features/test-records/amend/components/test-amendment-history/test-amendment-history.component.ts index d199e04dd1..f100592c22 100644 --- a/src/app/features/test-records/amend/components/test-amendment-history/test-amendment-history.component.ts +++ b/src/app/features/test-records/amend/components/test-amendment-history/test-amendment-history.component.ts @@ -1,23 +1,23 @@ import { Component, Input } from '@angular/core'; import { TestResultModel } from '@models/test-results/test-result.model'; -import { select, Store } from '@ngrx/store'; +import { Store, select } from '@ngrx/store'; import { selectedTestSortedAmendmentHistory } from '@store/test-records/selectors/test-records.selectors'; import { Observable } from 'rxjs/internal/Observable'; @Component({ - selector: 'app-test-amendment-history', - templateUrl: './test-amendment-history.component.html', + selector: 'app-test-amendment-history', + templateUrl: './test-amendment-history.component.html', }) export class TestAmendmentHistoryComponent { - @Input() testRecord: TestResultModel | undefined; + @Input() testRecord: TestResultModel | undefined; - constructor(private store: Store) {} + constructor(private store: Store) {} - getCreatedByName(testResult: TestResultModel | undefined) { - return testResult?.createdByName || testResult?.testerName; - } + getCreatedByName(testResult: TestResultModel | undefined) { + return testResult?.createdByName || testResult?.testerName; + } - get sortedTestHistory$(): Observable { - return this.store.pipe(select(selectedTestSortedAmendmentHistory)); - } + get sortedTestHistory$(): Observable { + return this.store.pipe(select(selectedTestSortedAmendmentHistory)); + } } diff --git a/src/app/features/test-records/amend/views/amend-test/amend-test.component.spec.ts b/src/app/features/test-records/amend/views/amend-test/amend-test.component.spec.ts index 048477a7b1..fe9413a5fd 100644 --- a/src/app/features/test-records/amend/views/amend-test/amend-test.component.spec.ts +++ b/src/app/features/test-records/amend/views/amend-test/amend-test.component.spec.ts @@ -3,23 +3,23 @@ import { RouterTestingModule } from '@angular/router/testing'; import { AmendTestComponent } from './amend-test.component'; describe('AmendTestComponent', () => { - let component: AmendTestComponent; - let fixture: ComponentFixture; + let component: AmendTestComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AmendTestComponent], - imports: [RouterTestingModule], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AmendTestComponent], + imports: [RouterTestingModule], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(AmendTestComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(AmendTestComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/features/test-records/amend/views/amend-test/amend-test.component.ts b/src/app/features/test-records/amend/views/amend-test/amend-test.component.ts index dad7e0e1ab..b359ca2fce 100644 --- a/src/app/features/test-records/amend/views/amend-test/amend-test.component.ts +++ b/src/app/features/test-records/amend/views/amend-test/amend-test.component.ts @@ -1,8 +1,8 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; @Component({ - selector: 'app-amend-test', - templateUrl: './amend-test.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-amend-test', + templateUrl: './amend-test.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class AmendTestComponent {} diff --git a/src/app/features/test-records/amend/views/amended-test-record/amended-test-record.component.spec.ts b/src/app/features/test-records/amend/views/amended-test-record/amended-test-record.component.spec.ts index e7e50c7811..016ac13173 100644 --- a/src/app/features/test-records/amend/views/amended-test-record/amended-test-record.component.spec.ts +++ b/src/app/features/test-records/amend/views/amended-test-record/amended-test-record.component.spec.ts @@ -1,5 +1,5 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { ComponentFixture, inject, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed, inject } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { ApiModule as TestResultsApiModule } from '@api/test-results'; import { DynamicFormsModule } from '@forms/dynamic-forms.module'; @@ -10,7 +10,7 @@ import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { TestRecordsService } from '@services/test-records/test-records.service'; import { UserService } from '@services/user-service/user-service'; import { SharedModule } from '@shared/shared.module'; -import { initialAppState, State } from '@store/.'; +import { State, initialAppState } from '@store/.'; import { selectAmendedDefectData, selectedAmendedTestResultState } from '@store/test-records'; import { of } from 'rxjs'; import { BaseTestRecordComponent } from '../../../components/base-test-record/base-test-record.component'; @@ -18,47 +18,50 @@ import { VehicleHeaderComponent } from '../../../components/vehicle-header/vehic import { AmendedTestRecordComponent } from './amended-test-record.component'; describe('AmendedTestRecordComponent', () => { - let component: AmendedTestRecordComponent; - let fixture: ComponentFixture; - let store: MockStore; + let component: AmendedTestRecordComponent; + let fixture: ComponentFixture; + let store: MockStore; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AmendedTestRecordComponent, BaseTestRecordComponent, VehicleHeaderComponent], - imports: [HttpClientTestingModule, SharedModule, DynamicFormsModule, TestResultsApiModule, RouterTestingModule], - providers: [ - TestRecordsService, - provideMockStore({ initialState: initialAppState }), - { - provide: UserService, - useValue: { - roles$: of([Roles.TestResultView]), - }, - }, - ], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AmendedTestRecordComponent, BaseTestRecordComponent, VehicleHeaderComponent], + imports: [HttpClientTestingModule, SharedModule, DynamicFormsModule, TestResultsApiModule, RouterTestingModule], + providers: [ + TestRecordsService, + provideMockStore({ initialState: initialAppState }), + { + provide: UserService, + useValue: { + roles$: of([Roles.TestResultView]), + }, + }, + ], + }).compileComponents(); + }); - beforeEach(() => { - store = TestBed.inject(MockStore); - store.overrideSelector(selectedAmendedTestResultState, mockTestResult()); - store.overrideSelector(selectAmendedDefectData, mockDefectList()); + beforeEach(() => { + store = TestBed.inject(MockStore); + store.overrideSelector(selectedAmendedTestResultState, mockTestResult()); + store.overrideSelector(selectAmendedDefectData, mockDefectList()); - fixture = TestBed.createComponent(AmendedTestRecordComponent); - component = fixture.componentInstance; - }); + fixture = TestBed.createComponent(AmendedTestRecordComponent); + component = fixture.componentInstance; + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it('sets class properties on component init', inject([TestRecordsService], (testRecordsService: TestRecordsService) => { - const amendedTestResultSpy = jest.spyOn(testRecordsService, 'amendedTestResult$', 'get'); - const amendedDefectDataSpy = jest.spyOn(testRecordsService, 'amendedDefectData$', 'get'); + it('sets class properties on component init', inject( + [TestRecordsService], + (testRecordsService: TestRecordsService) => { + const amendedTestResultSpy = jest.spyOn(testRecordsService, 'amendedTestResult$', 'get'); + const amendedDefectDataSpy = jest.spyOn(testRecordsService, 'amendedDefectData$', 'get'); - fixture.detectChanges(); + fixture.detectChanges(); - expect(amendedTestResultSpy).toHaveBeenCalled(); - expect(amendedDefectDataSpy).toHaveBeenCalled(); - })); + expect(amendedTestResultSpy).toHaveBeenCalled(); + expect(amendedDefectDataSpy).toHaveBeenCalled(); + } + )); }); diff --git a/src/app/features/test-records/amend/views/amended-test-record/amended-test-record.component.ts b/src/app/features/test-records/amend/views/amended-test-record/amended-test-record.component.ts index ac7785512e..b2cb3fec0b 100644 --- a/src/app/features/test-records/amend/views/amended-test-record/amended-test-record.component.ts +++ b/src/app/features/test-records/amend/views/amended-test-record/amended-test-record.component.ts @@ -3,22 +3,22 @@ import { FormNode } from '@forms/services/dynamic-form.types'; import { TestResultDefects } from '@models/test-results/test-result-defects.model'; import { TestResultModel } from '@models/test-results/test-result.model'; import { TestRecordsService } from '@services/test-records/test-records.service'; -import { firstValueFrom, Observable, of } from 'rxjs'; +import { Observable, firstValueFrom, of } from 'rxjs'; @Component({ - selector: 'app-amended-test-record', - templateUrl: './amended-test-record.component.html', + selector: 'app-amended-test-record', + templateUrl: './amended-test-record.component.html', }) export class AmendedTestRecordComponent implements OnInit { - testResult$: Observable = of(undefined); - defects$: Observable = of(undefined); - sectionTemplates$: Observable = of(undefined); + testResult$: Observable = of(undefined); + defects$: Observable = of(undefined); + sectionTemplates$: Observable = of(undefined); - constructor(private testRecordsService: TestRecordsService) {} + constructor(private testRecordsService: TestRecordsService) {} - async ngOnInit() { - this.testResult$ = this.testRecordsService.amendedTestResult$; - this.defects$ = this.testRecordsService.amendedDefectData$; - this.testRecordsService.editingTestResult((await firstValueFrom(this.testResult$)) as TestResultModel); - } + async ngOnInit() { + this.testResult$ = this.testRecordsService.amendedTestResult$; + this.defects$ = this.testRecordsService.amendedDefectData$; + this.testRecordsService.editingTestResult((await firstValueFrom(this.testResult$)) as TestResultModel); + } } diff --git a/src/app/features/test-records/amend/views/confirm-cancellation/confirm-cancellation.component.spec.ts b/src/app/features/test-records/amend/views/confirm-cancellation/confirm-cancellation.component.spec.ts index 1515b96ab3..06e655e7ad 100644 --- a/src/app/features/test-records/amend/views/confirm-cancellation/confirm-cancellation.component.spec.ts +++ b/src/app/features/test-records/amend/views/confirm-cancellation/confirm-cancellation.component.spec.ts @@ -14,33 +14,33 @@ import { VehicleHeaderComponent } from '../../../components/vehicle-header/vehic import { ConfirmCancellationComponent } from './confirm-cancellation.component'; describe('ConfirmCancellationComponent', () => { - let component: ConfirmCancellationComponent; - let fixture: ComponentFixture; + let component: ConfirmCancellationComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ConfirmCancellationComponent, VehicleHeaderComponent], - imports: [DynamicFormsModule, HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule, SharedModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - provideMockActions(() => new ReplaySubject()), - { - provide: TestRecordsService, - useValue: { - cancelTest: () => {}, - }, - }, - ], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ConfirmCancellationComponent, VehicleHeaderComponent], + imports: [DynamicFormsModule, HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule, SharedModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + provideMockActions(() => new ReplaySubject()), + { + provide: TestRecordsService, + useValue: { + cancelTest: () => {}, + }, + }, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(ConfirmCancellationComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(ConfirmCancellationComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/features/test-records/amend/views/confirm-cancellation/confirm-cancellation.component.ts b/src/app/features/test-records/amend/views/confirm-cancellation/confirm-cancellation.component.ts index c2eae84324..499dc4390f 100644 --- a/src/app/features/test-records/amend/views/confirm-cancellation/confirm-cancellation.component.ts +++ b/src/app/features/test-records/amend/views/confirm-cancellation/confirm-cancellation.component.ts @@ -10,66 +10,64 @@ import { Store, select } from '@ngrx/store'; import { TestRecordsService } from '@services/test-records/test-records.service'; import { selectRouteNestedParams } from '@store/router/selectors/router.selectors'; import { selectedTestResultState, updateTestResultSuccess } from '@store/test-records'; -import { - Observable, Subject, map, takeUntil, -} from 'rxjs'; +import { Observable, Subject, map, takeUntil } from 'rxjs'; @Component({ - selector: 'app-confirm-cancellation', - templateUrl: './confirm-cancellation.component.html', + selector: 'app-confirm-cancellation', + templateUrl: './confirm-cancellation.component.html', }) export class ConfirmCancellationComponent implements OnDestroy { - form = new CustomFormGroup( - { name: 'cancellation-reason', type: FormNodeTypes.GROUP }, - { reason: new CustomFormControl({ name: 'reason', type: FormNodeTypes.CONTROL }, undefined, [Validators.required]) }, - ); + form = new CustomFormGroup( + { name: 'cancellation-reason', type: FormNodeTypes.GROUP }, + { reason: new CustomFormControl({ name: 'reason', type: FormNodeTypes.CONTROL }, undefined, [Validators.required]) } + ); - private destroy$ = new Subject(); + private destroy$ = new Subject(); - constructor( - private actions$: Actions, - private errorService: GlobalErrorService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - private testRecordsService: TestRecordsService, - private globalErrorService: GlobalErrorService, - private location: Location, - ) { - this.actions$.pipe(ofType(updateTestResultSuccess), takeUntil(this.destroy$)).subscribe(() => { - void this.router.navigate(['../../../../..'], { relativeTo: this.route }); - }); - } + constructor( + private actions$: Actions, + private errorService: GlobalErrorService, + private route: ActivatedRoute, + private router: Router, + private store: Store, + private testRecordsService: TestRecordsService, + private globalErrorService: GlobalErrorService, + private location: Location + ) { + this.actions$.pipe(ofType(updateTestResultSuccess), takeUntil(this.destroy$)).subscribe(() => { + void this.router.navigate(['../../../../..'], { relativeTo: this.route }); + }); + } - ngOnDestroy(): void { - this.errorService.clearErrors(); - this.destroy$.next(); - this.destroy$.complete(); - } + ngOnDestroy(): void { + this.errorService.clearErrors(); + this.destroy$.next(); + this.destroy$.complete(); + } - navigateBack() { - this.globalErrorService.clearErrors(); - this.location.back(); - } + navigateBack() { + this.globalErrorService.clearErrors(); + this.location.back(); + } - get testResult$(): Observable { - return this.store.pipe(select(selectedTestResultState)); - } + get testResult$(): Observable { + return this.store.pipe(select(selectedTestResultState)); + } - get testNumber$(): Observable { - return this.store.pipe( - select(selectRouteNestedParams), - map((params) => params['testNumber']), - ); - } + get testNumber$(): Observable { + return this.store.pipe( + select(selectRouteNestedParams), + map((params) => params['testNumber']) + ); + } - handleSubmit() { - if (!this.form.valid) return; + handleSubmit() { + if (!this.form.valid) return; - const reason: string = this.form.get('reason')?.value; + const reason: string = this.form.get('reason')?.value; - this.testRecordsService.cleanTestResult(); + this.testRecordsService.cleanTestResult(); - this.testRecordsService.cancelTest(reason); - } + this.testRecordsService.cancelTest(reason); + } } diff --git a/src/app/features/test-records/amend/views/test-amend-reason/test-amend-reason.component.spec.ts b/src/app/features/test-records/amend/views/test-amend-reason/test-amend-reason.component.spec.ts index 74445ba60e..edf4e17d4c 100644 --- a/src/app/features/test-records/amend/views/test-amend-reason/test-amend-reason.component.spec.ts +++ b/src/app/features/test-records/amend/views/test-amend-reason/test-amend-reason.component.spec.ts @@ -6,38 +6,38 @@ import { DynamicFormsModule } from '@forms/dynamic-forms.module'; import { TestAmendReasonComponent } from './test-amend-reason.component'; describe('TestAmendReasonComponent', () => { - let component: TestAmendReasonComponent; - let fixture: ComponentFixture; - let router: Router; - let route: ActivatedRoute; + let component: TestAmendReasonComponent; + let fixture: ComponentFixture; + let router: Router; + let route: ActivatedRoute; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TestAmendReasonComponent], - imports: [RouterTestingModule, DynamicFormsModule, ReactiveFormsModule], - }).compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TestAmendReasonComponent], + imports: [RouterTestingModule, DynamicFormsModule, ReactiveFormsModule], + }).compileComponents(); - router = TestBed.inject(Router); - route = TestBed.inject(ActivatedRoute); - }); + router = TestBed.inject(Router); + route = TestBed.inject(ActivatedRoute); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TestAmendReasonComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(TestAmendReasonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it.each([ - ['incorrect-test-type', 1], - ['amend-test-details', 2], - ])('should navigate to %s on submit when reason is %n', (path, reason) => { - const navigateSpy = jest.spyOn(router, 'navigate').mockReturnValue(Promise.resolve(true)); - component.form.setValue({ reason }); - component.handleSubmit(); - expect(navigateSpy).toHaveBeenCalledWith([path], { relativeTo: route }); - }); + it.each([ + ['incorrect-test-type', 1], + ['amend-test-details', 2], + ])('should navigate to %s on submit when reason is %n', (path, reason) => { + const navigateSpy = jest.spyOn(router, 'navigate').mockReturnValue(Promise.resolve(true)); + component.form.setValue({ reason }); + component.handleSubmit(); + expect(navigateSpy).toHaveBeenCalledWith([path], { relativeTo: route }); + }); }); diff --git a/src/app/features/test-records/amend/views/test-amend-reason/test-amend-reason.component.ts b/src/app/features/test-records/amend/views/test-amend-reason/test-amend-reason.component.ts index c00b14343d..2a3bc33f05 100644 --- a/src/app/features/test-records/amend/views/test-amend-reason/test-amend-reason.component.ts +++ b/src/app/features/test-records/amend/views/test-amend-reason/test-amend-reason.component.ts @@ -1,39 +1,44 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; -import { - CustomFormControl, CustomFormGroup, FormNodeOption, FormNodeTypes, -} from '@forms/services/dynamic-form.types'; +import { CustomFormControl, CustomFormGroup, FormNodeOption, FormNodeTypes } from '@forms/services/dynamic-form.types'; @Component({ - selector: 'app-test-amend-reason', - templateUrl: './test-amend-reason.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-test-amend-reason', + templateUrl: './test-amend-reason.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class TestAmendReasonComponent { - private routes: Record = { 1: 'incorrect-test-type', 2: 'amend-test-details' }; + private routes: Record = { 1: 'incorrect-test-type', 2: 'amend-test-details' }; - reasons: Array> = [ - { label: 'The test type is incorrect', value: 1 }, - { label: 'The test details are incorrect', value: 2, hint: 'Change test location, assessor, test details, defects, and results.' }, - ]; + reasons: Array> = [ + { label: 'The test type is incorrect', value: 1 }, + { + label: 'The test details are incorrect', + value: 2, + hint: 'Change test location, assessor, test details, defects, and results.', + }, + ]; - form: CustomFormGroup; + form: CustomFormGroup; - constructor(private router: Router, private route: ActivatedRoute) { - this.form = new CustomFormGroup( - { name: 'reasonForAmend', type: FormNodeTypes.GROUP }, - { - reason: new CustomFormControl({ name: 'reason', type: FormNodeTypes.CONTROL }, 2, [Validators.required]), - }, - ); - } + constructor( + private router: Router, + private route: ActivatedRoute + ) { + this.form = new CustomFormGroup( + { name: 'reasonForAmend', type: FormNodeTypes.GROUP }, + { + reason: new CustomFormControl({ name: 'reason', type: FormNodeTypes.CONTROL }, 2, [Validators.required]), + } + ); + } - handleSubmit() { - const reason: number = this.form.get('reason')?.value; + handleSubmit() { + const reason: number = this.form.get('reason')?.value; - if (this.form.valid && reason) { - void this.router.navigate([this.routes[`${reason}`]], { relativeTo: this.route }); - } - } + if (this.form.valid && reason) { + void this.router.navigate([this.routes[`${reason}`]], { relativeTo: this.route }); + } + } } diff --git a/src/app/features/test-records/amend/views/test-record/test-record.component.spec.ts b/src/app/features/test-records/amend/views/test-record/test-record.component.spec.ts index 48e8ff98fe..421664d132 100644 --- a/src/app/features/test-records/amend/views/test-record/test-record.component.spec.ts +++ b/src/app/features/test-records/amend/views/test-record/test-record.component.spec.ts @@ -1,8 +1,6 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { DebugElement } from '@angular/core'; -import { - ComponentFixture, fakeAsync, TestBed, tick, waitForAsync, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick, waitForAsync } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { Params } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; @@ -18,12 +16,10 @@ import { TechnicalRecordService } from '@services/technical-record/technical-rec import { TestRecordsService } from '@services/test-records/test-records.service'; import { UserService } from '@services/user-service/user-service'; import { SharedModule } from '@shared/shared.module'; -import { initialAppState, State } from '@store/.'; +import { State, initialAppState } from '@store/.'; import { routeEditable, selectRouteData, selectRouteNestedParams } from '@store/router/selectors/router.selectors'; -import { - initialTestResultsState, isTestTypeKeySame, sectionTemplates, testResultInEdit, -} from '@store/test-records'; -import { of, ReplaySubject } from 'rxjs'; +import { initialTestResultsState, isTestTypeKeySame, sectionTemplates, testResultInEdit } from '@store/test-records'; +import { ReplaySubject, of } from 'rxjs'; import { DynamicFormsModule } from '../../../../../forms/dynamic-forms.module'; import { BaseTestRecordComponent } from '../../../components/base-test-record/base-test-record.component'; import { VehicleHeaderComponent } from '../../../components/vehicle-header/vehicle-header.component'; @@ -31,195 +27,202 @@ import { TestAmendmentHistoryComponent } from '../../components/test-amendment-h import { TestRecordComponent } from './test-record.component'; describe('TestRecordComponent', () => { - let component: TestRecordComponent; - let fixture: ComponentFixture; - let el: DebugElement; - let store: MockStore; - let testRecordsService: TestRecordsService; - const actions$ = new ReplaySubject(); - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [BaseTestRecordComponent, TestAmendmentHistoryComponent, TestRecordComponent, VehicleHeaderComponent], - imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule, TestResultsApiModule, SharedModule], - providers: [ - TestRecordsService, - provideMockStore({ initialState: initialAppState }), - RouterService, - provideMockActions(() => actions$), - { - provide: UserService, - useValue: { - roles$: of(['TestResult.Amend']), - }, - }, - TechnicalRecordService, - ], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(TestRecordComponent); - component = fixture.componentInstance; - el = fixture.debugElement; - store = TestBed.inject(MockStore); - store.overrideSelector(routeEditable, false); - testRecordsService = TestBed.inject(TestRecordsService); - - store.resetSelectors(); - store.overrideSelector(selectRouteNestedParams, { testResultId: '1', testNumber: 'foo' } as Params); - store.overrideSelector(selectRouteData, { isEditing: false }); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should not display anything when there is no data', waitForAsync(() => { - component.testResult$ = of(undefined); - - fixture.detectChanges(); - - expect(fixture.debugElement.query(By.css('h1'))).toBeNull(); - })); - - describe('button actions', () => { - beforeEach(() => { - jest - .spyOn(testRecordsService, 'testResult$', 'get') - .mockReturnValue(of({ vehicleType: 'psv', testTypes: [{ testTypeId: '1' }] } as TestResultModel)); - }); - - it('should display review button when edit query param is true', waitForAsync(() => { - store.overrideSelector(routeEditable, true); - jest.spyOn(component, 'isTestTypeGroupEditable$', 'get').mockReturnValue(of(true)); - - fixture.detectChanges(); - expect(el.query(By.css('button#review-test-result'))).toBeTruthy(); - })); - - it('should run handleSave when save button is clicked', waitForAsync(() => { - store.overrideSelector(routeEditable, true); - component.testMode = TestModeEnum.View; - - jest.spyOn(component, 'isTestTypeGroupEditable$', 'get').mockReturnValue(of(true)); - - fixture.detectChanges(); - - const saveSpy = jest.spyOn(component, 'handleSave'); - el.query(By.css('button#save-test-result')).nativeElement.click(); - expect(saveSpy).toHaveBeenCalledTimes(1); - })); - - it('should run handleReview when review button is clicked', waitForAsync(() => { - store.overrideSelector(routeEditable, true); - - jest.spyOn(component, 'isTestTypeGroupEditable$', 'get').mockReturnValue(of(true)); - - fixture.detectChanges(); - - const reviewSpy = jest.spyOn(component, 'handleReview'); - el.query(By.css('button#review-test-result')).nativeElement.click(); - expect(reviewSpy).toHaveBeenCalledTimes(1); - })); - }); - - describe('TestRecordComponent.prototype.handleSave.name', () => { - beforeEach(() => { - store.setState({ - ...initialAppState, - testRecords: { - ...initialTestResultsState, - ids: ['1'], - entities: { 1: { testTypes: [{ testNumber: 'foo' }] } as TestResultModel }, - editingTestResult: { testTypes: [{ testNumber: 'foo' }] } as TestResultModel, - }, - }); - }); - - it('should return without calling updateTestResultState if forms are clean', fakeAsync(async () => { - store.overrideSelector(isTestTypeKeySame('testTypeId'), true); - const updateTestResultStateSpy = jest.spyOn(testRecordsService, 'updateTestResult'); - await component.handleSave(); - expect(updateTestResultStateSpy).not.toHaveBeenCalled(); - })); - - it('should return without calling updateTestResultState if any forms are invalid', fakeAsync(async () => { - const updateTestResultStateSpy = jest.spyOn(testRecordsService, 'updateTestResult'); - component.isAnyFormDirty = jest.fn().mockReturnValue(true); - component.isAnyFormInvalid = jest.fn().mockReturnValue(true); - await component.handleSave(); - expect(updateTestResultStateSpy).not.toHaveBeenCalled(); - })); - - it('should call updateTestResult with value of all forms merged into one', async () => { - fixture.detectChanges(); - const updateTestResultStateSpy = jest.spyOn(testRecordsService, 'updateTestResult').mockImplementation(() => true); - const testRecord = { testResultId: '1', testTypes: [{ testTypeId: '2' }] } as TestResultModel; - store.overrideSelector(isTestTypeKeySame('testTypeId'), false); - store.overrideSelector(testResultInEdit, testRecord); - store.overrideSelector(sectionTemplates, Object.values(masterTpl.psv['testTypesGroup1'] ?? '')); - - component.isAnyFormDirty = jest.fn().mockReturnValue(true); - component.isAnyFormInvalid = jest.fn().mockReturnValue(false); - - await component.handleSave(); - - fixture.detectChanges(); - expect(updateTestResultStateSpy).toHaveBeenCalledTimes(1); - expect(updateTestResultStateSpy).toHaveBeenCalledWith(testRecord); - }); - }); - - describe('Render banner', () => { - beforeEach(() => { - jest - .spyOn(testRecordsService, 'testResult$', 'get') - .mockReturnValue(of({ vehicleType: 'psv', testTypes: [{ testTypeId: '1' }] } as TestResultModel)); - }); - - it('should render the banner if the test type id is not supported', waitForAsync(() => { - jest.spyOn(component, 'isTestTypeGroupEditable$', 'get').mockReturnValue(of(false)); - fixture.detectChanges(); - const banner = el.query(By.css('div.govuk-notification-banner')); - expect(banner).toBeTruthy(); - })); - - it('should not render the banner if the test type id is supported', fakeAsync(() => { - jest.spyOn(component, 'isTestTypeGroupEditable$', 'get').mockReturnValue(of(true)); - tick(); - fixture.detectChanges(); - const banner = el.query(By.css('div.govuk-notification-banner')); - expect(banner).toBeNull(); - })); - }); - - it('should set testMode to be view when has errors is false', async () => { - expect(component.testMode).toEqual(TestModeEnum.Edit); - - const errorsSpy = jest.spyOn(component, 'hasErrors').mockReturnValue(Promise.resolve(false)); - await component.handleReview(); - - expect(errorsSpy).toHaveBeenCalledTimes(1); - - expect(component.testMode).toEqual(TestModeEnum.View); - }); - - it('should not set testMode to be view when has errors is true', async () => { - expect(component.testMode).toEqual(TestModeEnum.Edit); - - const errorsSpy = jest.spyOn(component, 'hasErrors').mockReturnValue(Promise.resolve(true)); - await component.handleReview(); - - expect(errorsSpy).toHaveBeenCalledTimes(1); - - expect(component.testMode).toEqual(TestModeEnum.Edit); - }); - - it('should set testMode back to edit', () => { - component.testMode = TestModeEnum.View; - component.handleCancel(); - - expect(component.testMode).toEqual(TestModeEnum.Edit); - }); + let component: TestRecordComponent; + let fixture: ComponentFixture; + let el: DebugElement; + let store: MockStore; + let testRecordsService: TestRecordsService; + const actions$ = new ReplaySubject(); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BaseTestRecordComponent, + TestAmendmentHistoryComponent, + TestRecordComponent, + VehicleHeaderComponent, + ], + imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule, TestResultsApiModule, SharedModule], + providers: [ + TestRecordsService, + provideMockStore({ initialState: initialAppState }), + RouterService, + provideMockActions(() => actions$), + { + provide: UserService, + useValue: { + roles$: of(['TestResult.Amend']), + }, + }, + TechnicalRecordService, + ], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(TestRecordComponent); + component = fixture.componentInstance; + el = fixture.debugElement; + store = TestBed.inject(MockStore); + store.overrideSelector(routeEditable, false); + testRecordsService = TestBed.inject(TestRecordsService); + + store.resetSelectors(); + store.overrideSelector(selectRouteNestedParams, { testResultId: '1', testNumber: 'foo' } as Params); + store.overrideSelector(selectRouteData, { isEditing: false }); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should not display anything when there is no data', waitForAsync(() => { + component.testResult$ = of(undefined); + + fixture.detectChanges(); + + expect(fixture.debugElement.query(By.css('h1'))).toBeNull(); + })); + + describe('button actions', () => { + beforeEach(() => { + jest + .spyOn(testRecordsService, 'testResult$', 'get') + .mockReturnValue(of({ vehicleType: 'psv', testTypes: [{ testTypeId: '1' }] } as TestResultModel)); + }); + + it('should display review button when edit query param is true', waitForAsync(() => { + store.overrideSelector(routeEditable, true); + jest.spyOn(component, 'isTestTypeGroupEditable$', 'get').mockReturnValue(of(true)); + + fixture.detectChanges(); + expect(el.query(By.css('button#review-test-result'))).toBeTruthy(); + })); + + it('should run handleSave when save button is clicked', waitForAsync(() => { + store.overrideSelector(routeEditable, true); + component.testMode = TestModeEnum.View; + + jest.spyOn(component, 'isTestTypeGroupEditable$', 'get').mockReturnValue(of(true)); + + fixture.detectChanges(); + + const saveSpy = jest.spyOn(component, 'handleSave'); + el.query(By.css('button#save-test-result')).nativeElement.click(); + expect(saveSpy).toHaveBeenCalledTimes(1); + })); + + it('should run handleReview when review button is clicked', waitForAsync(() => { + store.overrideSelector(routeEditable, true); + + jest.spyOn(component, 'isTestTypeGroupEditable$', 'get').mockReturnValue(of(true)); + + fixture.detectChanges(); + + const reviewSpy = jest.spyOn(component, 'handleReview'); + el.query(By.css('button#review-test-result')).nativeElement.click(); + expect(reviewSpy).toHaveBeenCalledTimes(1); + })); + }); + + describe('TestRecordComponent.prototype.handleSave.name', () => { + beforeEach(() => { + store.setState({ + ...initialAppState, + testRecords: { + ...initialTestResultsState, + ids: ['1'], + entities: { 1: { testTypes: [{ testNumber: 'foo' }] } as TestResultModel }, + editingTestResult: { testTypes: [{ testNumber: 'foo' }] } as TestResultModel, + }, + }); + }); + + it('should return without calling updateTestResultState if forms are clean', fakeAsync(async () => { + store.overrideSelector(isTestTypeKeySame('testTypeId'), true); + const updateTestResultStateSpy = jest.spyOn(testRecordsService, 'updateTestResult'); + await component.handleSave(); + expect(updateTestResultStateSpy).not.toHaveBeenCalled(); + })); + + it('should return without calling updateTestResultState if any forms are invalid', fakeAsync(async () => { + const updateTestResultStateSpy = jest.spyOn(testRecordsService, 'updateTestResult'); + component.isAnyFormDirty = jest.fn().mockReturnValue(true); + component.isAnyFormInvalid = jest.fn().mockReturnValue(true); + await component.handleSave(); + expect(updateTestResultStateSpy).not.toHaveBeenCalled(); + })); + + it('should call updateTestResult with value of all forms merged into one', async () => { + fixture.detectChanges(); + const updateTestResultStateSpy = jest + .spyOn(testRecordsService, 'updateTestResult') + .mockImplementation(() => true); + const testRecord = { testResultId: '1', testTypes: [{ testTypeId: '2' }] } as TestResultModel; + store.overrideSelector(isTestTypeKeySame('testTypeId'), false); + store.overrideSelector(testResultInEdit, testRecord); + store.overrideSelector(sectionTemplates, Object.values(masterTpl.psv['testTypesGroup1'] ?? '')); + + component.isAnyFormDirty = jest.fn().mockReturnValue(true); + component.isAnyFormInvalid = jest.fn().mockReturnValue(false); + + await component.handleSave(); + + fixture.detectChanges(); + expect(updateTestResultStateSpy).toHaveBeenCalledTimes(1); + expect(updateTestResultStateSpy).toHaveBeenCalledWith(testRecord); + }); + }); + + describe('Render banner', () => { + beforeEach(() => { + jest + .spyOn(testRecordsService, 'testResult$', 'get') + .mockReturnValue(of({ vehicleType: 'psv', testTypes: [{ testTypeId: '1' }] } as TestResultModel)); + }); + + it('should render the banner if the test type id is not supported', waitForAsync(() => { + jest.spyOn(component, 'isTestTypeGroupEditable$', 'get').mockReturnValue(of(false)); + fixture.detectChanges(); + const banner = el.query(By.css('div.govuk-notification-banner')); + expect(banner).toBeTruthy(); + })); + + it('should not render the banner if the test type id is supported', fakeAsync(() => { + jest.spyOn(component, 'isTestTypeGroupEditable$', 'get').mockReturnValue(of(true)); + tick(); + fixture.detectChanges(); + const banner = el.query(By.css('div.govuk-notification-banner')); + expect(banner).toBeNull(); + })); + }); + + it('should set testMode to be view when has errors is false', async () => { + expect(component.testMode).toEqual(TestModeEnum.Edit); + + const errorsSpy = jest.spyOn(component, 'hasErrors').mockReturnValue(Promise.resolve(false)); + await component.handleReview(); + + expect(errorsSpy).toHaveBeenCalledTimes(1); + + expect(component.testMode).toEqual(TestModeEnum.View); + }); + + it('should not set testMode to be view when has errors is true', async () => { + expect(component.testMode).toEqual(TestModeEnum.Edit); + + const errorsSpy = jest.spyOn(component, 'hasErrors').mockReturnValue(Promise.resolve(true)); + await component.handleReview(); + + expect(errorsSpy).toHaveBeenCalledTimes(1); + + expect(component.testMode).toEqual(TestModeEnum.Edit); + }); + + it('should set testMode back to edit', () => { + component.testMode = TestModeEnum.View; + component.handleCancel(); + + expect(component.testMode).toEqual(TestModeEnum.Edit); + }); }); diff --git a/src/app/features/test-records/amend/views/test-record/test-record.component.ts b/src/app/features/test-records/amend/views/test-record/test-record.component.ts index a903c86903..1b377356b4 100644 --- a/src/app/features/test-records/amend/views/test-record/test-record.component.ts +++ b/src/app/features/test-records/amend/views/test-record/test-record.component.ts @@ -1,6 +1,4 @@ -import { - Component, OnDestroy, OnInit, ViewChild, -} from '@angular/core'; +import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalError } from '@core/components/global-error/global-error.interface'; @@ -15,162 +13,169 @@ import { RouterService } from '@services/router/router.service'; import { TestRecordsService } from '@services/test-records/test-records.service'; import { updateTestResultSuccess } from '@store/test-records'; import cloneDeep from 'lodash.clonedeep'; -import { - Observable, Subject, combineLatest, filter, firstValueFrom, map, of, switchMap, take, takeUntil, -} from 'rxjs'; +import { Observable, Subject, combineLatest, filter, firstValueFrom, map, of, switchMap, take, takeUntil } from 'rxjs'; import { BaseTestRecordComponent } from '../../../components/base-test-record/base-test-record.component'; @Component({ - selector: 'app-test-records', - templateUrl: './test-record.component.html', + selector: 'app-test-records', + templateUrl: './test-record.component.html', }) export class TestRecordComponent implements OnInit, OnDestroy { - @ViewChild(BaseTestRecordComponent) private baseTestRecordComponent?: BaseTestRecordComponent; - - private destroy$ = new Subject(); - - testResult$: Observable = of(undefined); - sectionTemplates$: Observable = of(undefined); - testMode = TestModeEnum.Edit; - - constructor( - private actions$: Actions, - private errorService: GlobalErrorService, - private route: ActivatedRoute, - private router: Router, - private routerService: RouterService, - private testRecordsService: TestRecordsService, - ) { - this.router.routeReuseStrategy.shouldReuseRoute = () => false; - } - - ngOnInit(): void { - this.testResult$ = this.testRecordsService.editingTestResult$.pipe( - switchMap((editingTestResult) => (editingTestResult ? of(editingTestResult) : this.testRecordsService.testResult$)), - ); - this.sectionTemplates$ = this.testRecordsService.sectionTemplates$; - - this.actions$.pipe(ofType(updateTestResultSuccess), takeUntil(this.destroy$)).subscribe(() => { - void this.router.navigate(['../..'], { relativeTo: this.route.parent }); - }); - - combineLatest([this.testResult$, this.routerService.getQueryParam$('testType'), this.testRecordsService.sectionTemplates$]) - .pipe( - take(1), - filter(([testResult]) => !!testResult), - ) - .subscribe(([testResult, testType, sectionTemplates]) => { - if (!sectionTemplates && testResult) { - testResult.reasonForCreation = ''; - this.testRecordsService.editingTestResult(testResult); - } - if (testType && testType !== testResult?.testTypes[0].testTypeId) { - this.testRecordsService.testTypeChange(testType); - } - }); - } - - ngOnDestroy(): void { - this.errorService.clearErrors(); - - this.destroy$.next(); - this.destroy$.complete(); - } - - public get Roles() { - return Roles; - } - - /** - * Merge all section form values into one testResult and trigger action to update testResult. - * @returns void - */ - async handleSave(): Promise { - if (await this.hasErrors()) { - return; - } - - this.testRecordsService.cleanTestResult(); - - const testResult = await firstValueFrom(this.testResult$); - const testResultClone = cloneDeep(testResult) as TestResultModel; - - this.testRecordsService.updateTestResult(testResultClone); - } - - async handleReview(): Promise { - if (await this.hasErrors()) { - return; - } - - this.testMode = TestModeEnum.View; - } - - async hasErrors(): Promise { - const errors: GlobalError[] = []; - const forms = []; - - if (this.baseTestRecordComponent) { - const { sections, defects } = this.baseTestRecordComponent; - if (sections) { - sections.forEach((section) => { - forms.push(section.form); - }); - } - - if (defects) { - forms.push(defects.form); - } - } - - // if all forms are not marked as dirty, return - if (!this.isAnyFormDirty(forms) && (await firstValueFrom(this.testRecordsService.isSameTestTypeId$))) { - return true; - } - - forms.forEach((form) => { - DynamicFormService.validate(form, errors); - }); - - if (errors.length > 0) { - this.errorService.setErrors(errors); - } - - if (this.isAnyFormInvalid(forms)) { - return true; - } - - return false; - } - - handleCancel() { - this.testMode = this.testMode === TestModeEnum.Cancel || this.testMode === TestModeEnum.View ? TestModeEnum.Edit : TestModeEnum.Cancel; - } - - handleConfirmCancel() { - void this.router.navigate(['../..'], { relativeTo: this.route.parent }); - } - - get isTestTypeGroupEditable$(): Observable { - return this.testRecordsService.isTestTypeGroupEditable$; - } - - handleNewTestResult(testResult: TestResultModel) { - this.testRecordsService.updateEditingTestResult(testResult); - } - - isAnyFormDirty(forms: Array) { - return forms.some((form) => form.dirty); - } - - isAnyFormInvalid(forms: Array) { - return forms.some((form) => form.invalid); - } - get testNumber$(): Observable { - return this.routerService.routeNestedParams$.pipe(map((params) => params['testNumber'])); - } - - public get TestModeEnum(): typeof TestModeEnum { - return TestModeEnum; - } + @ViewChild(BaseTestRecordComponent) private baseTestRecordComponent?: BaseTestRecordComponent; + + private destroy$ = new Subject(); + + testResult$: Observable = of(undefined); + sectionTemplates$: Observable = of(undefined); + testMode = TestModeEnum.Edit; + + constructor( + private actions$: Actions, + private errorService: GlobalErrorService, + private route: ActivatedRoute, + private router: Router, + private routerService: RouterService, + private testRecordsService: TestRecordsService + ) { + this.router.routeReuseStrategy.shouldReuseRoute = () => false; + } + + ngOnInit(): void { + this.testResult$ = this.testRecordsService.editingTestResult$.pipe( + switchMap((editingTestResult) => + editingTestResult ? of(editingTestResult) : this.testRecordsService.testResult$ + ) + ); + this.sectionTemplates$ = this.testRecordsService.sectionTemplates$; + + this.actions$.pipe(ofType(updateTestResultSuccess), takeUntil(this.destroy$)).subscribe(() => { + void this.router.navigate(['../..'], { relativeTo: this.route.parent }); + }); + + combineLatest([ + this.testResult$, + this.routerService.getQueryParam$('testType'), + this.testRecordsService.sectionTemplates$, + ]) + .pipe( + take(1), + filter(([testResult]) => !!testResult) + ) + .subscribe(([testResult, testType, sectionTemplates]) => { + if (!sectionTemplates && testResult) { + testResult.reasonForCreation = ''; + this.testRecordsService.editingTestResult(testResult); + } + if (testType && testType !== testResult?.testTypes[0].testTypeId) { + this.testRecordsService.testTypeChange(testType); + } + }); + } + + ngOnDestroy(): void { + this.errorService.clearErrors(); + + this.destroy$.next(); + this.destroy$.complete(); + } + + public get Roles() { + return Roles; + } + + /** + * Merge all section form values into one testResult and trigger action to update testResult. + * @returns void + */ + async handleSave(): Promise { + if (await this.hasErrors()) { + return; + } + + this.testRecordsService.cleanTestResult(); + + const testResult = await firstValueFrom(this.testResult$); + const testResultClone = cloneDeep(testResult) as TestResultModel; + + this.testRecordsService.updateTestResult(testResultClone); + } + + async handleReview(): Promise { + if (await this.hasErrors()) { + return; + } + + this.testMode = TestModeEnum.View; + } + + async hasErrors(): Promise { + const errors: GlobalError[] = []; + const forms = []; + + if (this.baseTestRecordComponent) { + const { sections, defects } = this.baseTestRecordComponent; + if (sections) { + sections.forEach((section) => { + forms.push(section.form); + }); + } + + if (defects) { + forms.push(defects.form); + } + } + + // if all forms are not marked as dirty, return + if (!this.isAnyFormDirty(forms) && (await firstValueFrom(this.testRecordsService.isSameTestTypeId$))) { + return true; + } + + forms.forEach((form) => { + DynamicFormService.validate(form, errors); + }); + + if (errors.length > 0) { + this.errorService.setErrors(errors); + } + + if (this.isAnyFormInvalid(forms)) { + return true; + } + + return false; + } + + handleCancel() { + this.testMode = + this.testMode === TestModeEnum.Cancel || this.testMode === TestModeEnum.View + ? TestModeEnum.Edit + : TestModeEnum.Cancel; + } + + handleConfirmCancel() { + void this.router.navigate(['../..'], { relativeTo: this.route.parent }); + } + + get isTestTypeGroupEditable$(): Observable { + return this.testRecordsService.isTestTypeGroupEditable$; + } + + handleNewTestResult(testResult: TestResultModel) { + this.testRecordsService.updateEditingTestResult(testResult); + } + + isAnyFormDirty(forms: Array) { + return forms.some((form) => form.dirty); + } + + isAnyFormInvalid(forms: Array) { + return forms.some((form) => form.invalid); + } + get testNumber$(): Observable { + return this.routerService.routeNestedParams$.pipe(map((params) => params['testNumber'])); + } + + public get TestModeEnum(): typeof TestModeEnum { + return TestModeEnum; + } } diff --git a/src/app/features/test-records/amend/views/test-result-summary/test-result-summary.component.spec.ts b/src/app/features/test-records/amend/views/test-result-summary/test-result-summary.component.spec.ts index 794b080c22..bc78d8f21b 100644 --- a/src/app/features/test-records/amend/views/test-result-summary/test-result-summary.component.spec.ts +++ b/src/app/features/test-records/amend/views/test-result-summary/test-result-summary.component.spec.ts @@ -13,24 +13,29 @@ import { VehicleHeaderComponent } from '../../../components/vehicle-header/vehic import { TestResultSummaryComponent } from './test-result-summary.component'; describe('TestResultSummaryComponent', () => { - let component: TestResultSummaryComponent; - let fixture: ComponentFixture; + let component: TestResultSummaryComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TestResultSummaryComponent, VehicleHeaderComponent, NumberPlateComponent, TagComponent], - imports: [RouterTestingModule, HttpClientTestingModule, TestResultsApiModule], - providers: [provideMockStore({ initialState: initialAppState }), TestRecordsService, TechnicalRecordService, RouterService], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TestResultSummaryComponent, VehicleHeaderComponent, NumberPlateComponent, TagComponent], + imports: [RouterTestingModule, HttpClientTestingModule, TestResultsApiModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + TestRecordsService, + TechnicalRecordService, + RouterService, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TestResultSummaryComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(TestResultSummaryComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/features/test-records/amend/views/test-result-summary/test-result-summary.component.ts b/src/app/features/test-records/amend/views/test-result-summary/test-result-summary.component.ts index e739d32bf3..8c0dff8681 100644 --- a/src/app/features/test-records/amend/views/test-result-summary/test-result-summary.component.ts +++ b/src/app/features/test-records/amend/views/test-result-summary/test-result-summary.component.ts @@ -2,33 +2,33 @@ import { Component, OnInit } from '@angular/core'; import { FormNode } from '@forms/services/dynamic-form.types'; import { TestResultModel } from '@models/test-results/test-result.model'; import { TestRecordsService } from '@services/test-records/test-records.service'; -import { - Observable, of, skipWhile, switchMap, take, -} from 'rxjs'; +import { Observable, of, skipWhile, switchMap, take } from 'rxjs'; @Component({ - selector: 'app-test-result-summary', - templateUrl: './test-result-summary.component.html', - styleUrls: ['./test-result-summary.component.scss'], + selector: 'app-test-result-summary', + templateUrl: './test-result-summary.component.html', + styleUrls: ['./test-result-summary.component.scss'], }) export class TestResultSummaryComponent implements OnInit { - testResult$: Observable = of(undefined); - sectionTemplates$: Observable = of(undefined); + testResult$: Observable = of(undefined); + sectionTemplates$: Observable = of(undefined); - constructor(private testRecordsService: TestRecordsService) {} + constructor(private testRecordsService: TestRecordsService) {} - ngOnInit(): void { - this.testResult$ = this.testRecordsService.editingTestResult$.pipe( - switchMap((editingTestResult) => (editingTestResult ? of(editingTestResult) : this.testRecordsService.testResult$)), - ); + ngOnInit(): void { + this.testResult$ = this.testRecordsService.editingTestResult$.pipe( + switchMap((editingTestResult) => + editingTestResult ? of(editingTestResult) : this.testRecordsService.testResult$ + ) + ); - this.testResult$ - .pipe( - skipWhile((testResult) => !testResult), - take(1), - ) - .subscribe((testResult) => this.testRecordsService.editingTestResult(testResult as TestResultModel)); + this.testResult$ + .pipe( + skipWhile((testResult) => !testResult), + take(1) + ) + .subscribe((testResult) => this.testRecordsService.editingTestResult(testResult as TestResultModel)); - this.sectionTemplates$ = this.testRecordsService.sectionTemplates$; - } + this.sectionTemplates$ = this.testRecordsService.sectionTemplates$; + } } diff --git a/src/app/features/test-records/amend/views/test-router-outlet/test-router-outlet.component.spec.ts b/src/app/features/test-records/amend/views/test-router-outlet/test-router-outlet.component.spec.ts index 4da59bb9c3..d1d8bd0c1c 100644 --- a/src/app/features/test-records/amend/views/test-router-outlet/test-router-outlet.component.spec.ts +++ b/src/app/features/test-records/amend/views/test-router-outlet/test-router-outlet.component.spec.ts @@ -3,23 +3,23 @@ import { RouterTestingModule } from '@angular/router/testing'; import { TestRouterOutletComponent } from './test-router-outlet.component'; describe('TestRouterOutletComponent', () => { - let component: TestRouterOutletComponent; - let fixture: ComponentFixture; + let component: TestRouterOutletComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TestRouterOutletComponent], - imports: [RouterTestingModule], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TestRouterOutletComponent], + imports: [RouterTestingModule], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TestRouterOutletComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(TestRouterOutletComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/features/test-records/amend/views/test-router-outlet/test-router-outlet.component.ts b/src/app/features/test-records/amend/views/test-router-outlet/test-router-outlet.component.ts index 9427a72c5b..8ae25e17ef 100644 --- a/src/app/features/test-records/amend/views/test-router-outlet/test-router-outlet.component.ts +++ b/src/app/features/test-records/amend/views/test-router-outlet/test-router-outlet.component.ts @@ -1,8 +1,8 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; @Component({ - selector: 'app-test-router-outlet', - templateUrl: './test-router-outlet.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-test-router-outlet', + templateUrl: './test-router-outlet.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class TestRouterOutletComponent {} diff --git a/src/app/features/test-records/amend/views/test-type-select-wrapper/test-type-select-wrapper.component.spec.ts b/src/app/features/test-records/amend/views/test-type-select-wrapper/test-type-select-wrapper.component.spec.ts index 2ee5166276..600dc57755 100644 --- a/src/app/features/test-records/amend/views/test-type-select-wrapper/test-type-select-wrapper.component.spec.ts +++ b/src/app/features/test-records/amend/views/test-type-select-wrapper/test-type-select-wrapper.component.spec.ts @@ -1,51 +1,51 @@ +import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ActivatedRoute, Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { TestType } from '@api/test-types'; +import { provideMockStore } from '@ngrx/store/testing'; import { TestTypesService } from '@services/test-types/test-types.service'; -import { of } from 'rxjs'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; import { State, initialAppState } from '@store/index'; -import { provideMockStore } from '@ngrx/store/testing'; +import { of } from 'rxjs'; import { TestTypeSelectComponent } from '../../../components/test-type-select/test-type-select.component'; import { TestTypeSelectWrapperComponent } from './test-type-select-wrapper.component'; describe('TestTypeSelectWrapperComponent', () => { - let component: TestTypeSelectWrapperComponent; - let fixture: ComponentFixture; - let router: Router; - let route: ActivatedRoute; + let component: TestTypeSelectWrapperComponent; + let fixture: ComponentFixture; + let router: Router; + let route: ActivatedRoute; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TestTypeSelectWrapperComponent, TestTypeSelectComponent], - imports: [RouterTestingModule, HttpClientTestingModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - { provide: TestTypesService, useValue: { selectAllTestTypes$: of([]), testTypeIdChanged: () => {} } }, - ], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TestTypeSelectWrapperComponent, TestTypeSelectComponent], + imports: [RouterTestingModule, HttpClientTestingModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + { provide: TestTypesService, useValue: { selectAllTestTypes$: of([]), testTypeIdChanged: () => {} } }, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TestTypeSelectWrapperComponent); - component = fixture.componentInstance; - router = TestBed.inject(Router); - route = TestBed.inject(ActivatedRoute); - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(TestTypeSelectWrapperComponent); + component = fixture.componentInstance; + router = TestBed.inject(Router); + route = TestBed.inject(ActivatedRoute); + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it('should navigate to sibling path "amend-test-details"', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockReturnValue(Promise.resolve(true)); - component.handleTestTypeSelection({ id: '1' } as TestType); - expect(navigateSpy).toHaveBeenCalledWith(['..', 'amend-test-details'], { - queryParams: { testType: '1' }, - queryParamsHandling: 'merge', - relativeTo: route, - }); - }); + it('should navigate to sibling path "amend-test-details"', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockReturnValue(Promise.resolve(true)); + component.handleTestTypeSelection({ id: '1' } as TestType); + expect(navigateSpy).toHaveBeenCalledWith(['..', 'amend-test-details'], { + queryParams: { testType: '1' }, + queryParamsHandling: 'merge', + relativeTo: route, + }); + }); }); diff --git a/src/app/features/test-records/amend/views/test-type-select-wrapper/test-type-select-wrapper.component.ts b/src/app/features/test-records/amend/views/test-type-select-wrapper/test-type-select-wrapper.component.ts index 36be430806..e7b6c5bcef 100644 --- a/src/app/features/test-records/amend/views/test-type-select-wrapper/test-type-select-wrapper.component.ts +++ b/src/app/features/test-records/amend/views/test-type-select-wrapper/test-type-select-wrapper.component.ts @@ -3,18 +3,21 @@ import { ActivatedRoute, Router } from '@angular/router'; import { TestType } from '@api/test-types'; @Component({ - selector: 'app-test-type-select-wrapper', - templateUrl: './test-type-select-wrapper.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-test-type-select-wrapper', + templateUrl: './test-type-select-wrapper.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class TestTypeSelectWrapperComponent { - constructor(private router: Router, private route: ActivatedRoute) {} + constructor( + private router: Router, + private route: ActivatedRoute + ) {} - handleTestTypeSelection(testType: TestType) { - void this.router.navigate(['..', 'amend-test-details'], { - queryParams: { testType: testType.id }, - queryParamsHandling: 'merge', - relativeTo: this.route, - }); - } + handleTestTypeSelection(testType: TestType) { + void this.router.navigate(['..', 'amend-test-details'], { + queryParams: { testType: testType.id }, + queryParamsHandling: 'merge', + relativeTo: this.route, + }); + } } diff --git a/src/app/features/test-records/components/base-test-record/base-test-record.component.spec.ts b/src/app/features/test-records/components/base-test-record/base-test-record.component.spec.ts index f148213333..f4b6bd5bff 100644 --- a/src/app/features/test-records/components/base-test-record/base-test-record.component.spec.ts +++ b/src/app/features/test-records/components/base-test-record/base-test-record.component.spec.ts @@ -2,7 +2,11 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { QueryList } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; -import { DefaultService as CreateTestResultsService, GetTestResultsService, UpdateTestResultsService } from '@api/test-results'; +import { + DefaultService as CreateTestResultsService, + GetTestResultsService, + UpdateTestResultsService, +} from '@api/test-results'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { DynamicFormGroupComponent } from '@forms/components/dynamic-form-group/dynamic-form-group.component'; import { DynamicFormsModule } from '@forms/dynamic-forms.module'; @@ -24,93 +28,103 @@ import { VehicleHeaderComponent } from '../vehicle-header/vehicle-header.compone import { BaseTestRecordComponent } from './base-test-record.component'; describe('BaseTestRecordComponent', () => { - let component: BaseTestRecordComponent; - let fixture: ComponentFixture; + let component: BaseTestRecordComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [BaseTestRecordComponent, DefaultNullOrEmpty, VehicleHeaderComponent], - imports: [DynamicFormsModule, HttpClientTestingModule, SharedModule, RouterTestingModule], - providers: [ - RouterService, - GlobalErrorService, - provideMockStore({ initialState: initialAppState }), - TestTypesService, - TechnicalRecordService, - UpdateTestResultsService, - GetTestResultsService, - CreateTestResultsService, - { - provide: UserService, - useValue: { - roles$: of([Roles.TestResultCreateContingency, Roles.TestResultAmend]), - }, - }, - ], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BaseTestRecordComponent, DefaultNullOrEmpty, VehicleHeaderComponent], + imports: [DynamicFormsModule, HttpClientTestingModule, SharedModule, RouterTestingModule], + providers: [ + RouterService, + GlobalErrorService, + provideMockStore({ initialState: initialAppState }), + TestTypesService, + TechnicalRecordService, + UpdateTestResultsService, + GetTestResultsService, + CreateTestResultsService, + { + provide: UserService, + useValue: { + roles$: of([Roles.TestResultCreateContingency, Roles.TestResultAmend]), + }, + }, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(BaseTestRecordComponent); - component = fixture.componentInstance; - component.testResult = { vin: 'ABC002', testTypes: [{ testResult: resultOfTestEnum.fail }] } as TestResultModel; - jest.clearAllMocks(); - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(BaseTestRecordComponent); + component = fixture.componentInstance; + component.testResult = { vin: 'ABC002', testTypes: [{ testResult: resultOfTestEnum.fail }] } as TestResultModel; + jest.clearAllMocks(); + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - describe('BaseTestRecordComponent.prototype.handleFormChange.name', () => { - it('should emit the new test result', (done) => { - const event = { vin: 'ABC001' } as TestResultModel; - const expectedValue = { vin: 'ABC001' }; + describe('BaseTestRecordComponent.prototype.handleFormChange.name', () => { + it('should emit the new test result', (done) => { + const event = { vin: 'ABC001' } as TestResultModel; + const expectedValue = { vin: 'ABC001' }; - component.newTestResult.subscribe((testResult) => { - expect(testResult).toEqual(expectedValue); - done(); - }); + component.newTestResult.subscribe((testResult) => { + expect(testResult).toEqual(expectedValue); + done(); + }); - component.handleFormChange(event); - }); - }); + component.handleFormChange(event); + }); + }); - describe('validateEuVehicleCategory', () => { - it('should call the validate function of eu vehicle category', () => { - component.sections = [{ form: new CustomFormGroup({ name: 'vehicleSection', type: FormNodeTypes.GROUP, children: [] }, {}) }, - { - form: new CustomFormGroup({ - name: 'testSection', - type: FormNodeTypes.GROUP, - children: [], - }, {}), - }] as unknown as QueryList; + describe('validateEuVehicleCategory', () => { + it('should call the validate function of eu vehicle category', () => { + component.sections = [ + { form: new CustomFormGroup({ name: 'vehicleSection', type: FormNodeTypes.GROUP, children: [] }, {}) }, + { + form: new CustomFormGroup( + { + name: 'testSection', + type: FormNodeTypes.GROUP, + children: [], + }, + {} + ), + }, + ] as unknown as QueryList; - const spy = jest.spyOn(DynamicFormService, 'validateControl'); - spy.mockImplementation(() => undefined); + const spy = jest.spyOn(DynamicFormService, 'validateControl'); + spy.mockImplementation(() => undefined); - component.validateEuVehicleCategory('test'); + component.validateEuVehicleCategory('test'); - expect(spy).toHaveBeenCalledTimes(1); - }); + expect(spy).toHaveBeenCalledTimes(1); + }); - it('should not call the validate function of eu vehicle category', () => { - component.sections = [{ form: new CustomFormGroup({ name: 'anotherTestSection', type: FormNodeTypes.GROUP, children: [] }, {}) }, - { - form: new CustomFormGroup({ - name: 'testSection', - type: FormNodeTypes.GROUP, - children: [], - }, {}), - }] as unknown as QueryList; + it('should not call the validate function of eu vehicle category', () => { + component.sections = [ + { form: new CustomFormGroup({ name: 'anotherTestSection', type: FormNodeTypes.GROUP, children: [] }, {}) }, + { + form: new CustomFormGroup( + { + name: 'testSection', + type: FormNodeTypes.GROUP, + children: [], + }, + {} + ), + }, + ] as unknown as QueryList; - const spy = jest.spyOn(DynamicFormService, 'validateControl'); - spy.mockImplementation(() => undefined); + const spy = jest.spyOn(DynamicFormService, 'validateControl'); + spy.mockImplementation(() => undefined); - component.validateEuVehicleCategory('test'); + component.validateEuVehicleCategory('test'); - expect(spy).toHaveBeenCalledTimes(0); - }); - }); + expect(spy).toHaveBeenCalledTimes(0); + }); + }); }); diff --git a/src/app/features/test-records/components/base-test-record/base-test-record.component.ts b/src/app/features/test-records/components/base-test-record/base-test-record.component.ts index d267609e2b..ea1e1d6afc 100644 --- a/src/app/features/test-records/components/base-test-record/base-test-record.component.ts +++ b/src/app/features/test-records/components/base-test-record/base-test-record.component.ts @@ -1,5 +1,12 @@ import { - AfterViewInit, Component, EventEmitter, Input, Output, QueryList, ViewChild, ViewChildren, + AfterViewInit, + Component, + EventEmitter, + Input, + Output, + QueryList, + ViewChild, + ViewChildren, } from '@angular/core'; import { GlobalError } from '@core/components/global-error/global-error.interface'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; @@ -24,94 +31,94 @@ import merge from 'lodash.merge'; import { Observable, map } from 'rxjs'; @Component({ - selector: 'app-base-test-record[testResult]', - templateUrl: './base-test-record.component.html', - styleUrls: ['./base-test-record.component.scss'], + selector: 'app-base-test-record[testResult]', + templateUrl: './base-test-record.component.html', + styleUrls: ['./base-test-record.component.scss'], }) export class BaseTestRecordComponent implements AfterViewInit { - @ViewChildren(DynamicFormGroupComponent) sections?: QueryList; - @ViewChild(DefectsComponent) defects?: DefectsComponent; - @ViewChild(CustomDefectsComponent) customDefects?: CustomDefectsComponent; - @ViewChild(RequiredStandardsComponent) requiredStandards?: RequiredStandardsComponent; - - @Input() testResult!: TestResultModel; - @Input() isEditing = false; - @Input() expandSections = false; - @Input() isReview = false; - - @Output() newTestResult = new EventEmitter(); - - techRecord$: Observable; - constructor( - private defectsStore: Store, - private routerService: RouterService, - private testRecordsService: TestRecordsService, - private store: Store, - private globalErrorService: GlobalErrorService, - ) { - this.techRecord$ = this.store.select(selectTechRecord); - } - - ngAfterViewInit(): void { - this.handleFormChange({}); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - handleFormChange(event: any) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let latestTest: any; - this.sections?.forEach((section) => { - const { form } = section; - latestTest = merge(latestTest, form.getCleanValue(form)); - }); - const defectsValue = this.defects?.form.getCleanValue(this.defects?.form); - const customDefectsValue = this.customDefects?.form.getCleanValue(this.customDefects?.form); - const requiredStandardsValue = this.requiredStandards?.form.getCleanValue(this.requiredStandards?.form); - - latestTest = merge(latestTest, defectsValue, customDefectsValue, requiredStandardsValue, event); - - if (latestTest && Object.keys(latestTest).length > 0) { - this.newTestResult.emit(latestTest as TestResultModel); - } - } - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - validateEuVehicleCategory(_event: unknown) { - this.sections?.forEach((section) => { - const { form } = section; - if (form.meta.name === 'vehicleSection') { - const errors: GlobalError[] = []; - DynamicFormService.validateControl(form.get('euVehicleCategory') as CustomFormControl, errors); - this.globalErrorService.setErrors(errors); - } - }); - } - - getDefects$(type: VehicleTypes): Observable { - return this.defectsStore.select(filteredDefects(type)); - } - - get isTestTypeGroupEditable$(): Observable { - return this.testRecordsService.isTestTypeGroupEditable$; - } - - get roles(): typeof Roles { - return Roles; - } - - get statuses(): typeof TestResultStatus { - return TestResultStatus; - } - - get sectionTemplates$(): Observable { - return this.testRecordsService.sectionTemplates$; - } - - get resultOfTest(): resultOfTestEnum { - return this.testResult?.testTypes[0].testResult; - } - - get testNumber$(): Observable { - return this.routerService.routeNestedParams$.pipe(map((params) => params['testNumber'])); - } + @ViewChildren(DynamicFormGroupComponent) sections?: QueryList; + @ViewChild(DefectsComponent) defects?: DefectsComponent; + @ViewChild(CustomDefectsComponent) customDefects?: CustomDefectsComponent; + @ViewChild(RequiredStandardsComponent) requiredStandards?: RequiredStandardsComponent; + + @Input() testResult!: TestResultModel; + @Input() isEditing = false; + @Input() expandSections = false; + @Input() isReview = false; + + @Output() newTestResult = new EventEmitter(); + + techRecord$: Observable; + constructor( + private defectsStore: Store, + private routerService: RouterService, + private testRecordsService: TestRecordsService, + private store: Store, + private globalErrorService: GlobalErrorService + ) { + this.techRecord$ = this.store.select(selectTechRecord); + } + + ngAfterViewInit(): void { + this.handleFormChange({}); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + handleFormChange(event: any) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let latestTest: any; + this.sections?.forEach((section) => { + const { form } = section; + latestTest = merge(latestTest, form.getCleanValue(form)); + }); + const defectsValue = this.defects?.form.getCleanValue(this.defects?.form); + const customDefectsValue = this.customDefects?.form.getCleanValue(this.customDefects?.form); + const requiredStandardsValue = this.requiredStandards?.form.getCleanValue(this.requiredStandards?.form); + + latestTest = merge(latestTest, defectsValue, customDefectsValue, requiredStandardsValue, event); + + if (latestTest && Object.keys(latestTest).length > 0) { + this.newTestResult.emit(latestTest as TestResultModel); + } + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + validateEuVehicleCategory(_event: unknown) { + this.sections?.forEach((section) => { + const { form } = section; + if (form.meta.name === 'vehicleSection') { + const errors: GlobalError[] = []; + DynamicFormService.validateControl(form.get('euVehicleCategory') as CustomFormControl, errors); + this.globalErrorService.setErrors(errors); + } + }); + } + + getDefects$(type: VehicleTypes): Observable { + return this.defectsStore.select(filteredDefects(type)); + } + + get isTestTypeGroupEditable$(): Observable { + return this.testRecordsService.isTestTypeGroupEditable$; + } + + get roles(): typeof Roles { + return Roles; + } + + get statuses(): typeof TestResultStatus { + return TestResultStatus; + } + + get sectionTemplates$(): Observable { + return this.testRecordsService.sectionTemplates$; + } + + get resultOfTest(): resultOfTestEnum { + return this.testResult?.testTypes[0].testResult; + } + + get testNumber$(): Observable { + return this.routerService.routeNestedParams$.pipe(map((params) => params['testNumber'])); + } } diff --git a/src/app/features/test-records/components/test-type-select/test-type-select.component.spec.ts b/src/app/features/test-records/components/test-type-select/test-type-select.component.spec.ts index 6046fb2cd8..240dea8a36 100644 --- a/src/app/features/test-records/components/test-type-select/test-type-select.component.spec.ts +++ b/src/app/features/test-records/components/test-type-select/test-type-select.component.spec.ts @@ -10,67 +10,67 @@ import { of } from 'rxjs'; import { TestTypeSelectComponent } from './test-type-select.component'; describe('TestTypeSelectComponent', () => { - let component: TestTypeSelectComponent; - let fixture: ComponentFixture; + let component: TestTypeSelectComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TestTypeSelectComponent], - imports: [RouterTestingModule, HttpClientTestingModule], - providers: [ - DynamicFormService, - provideMockStore({ initialState: initialAppState }), - { provide: TestTypesService, useValue: { selectAllTestTypes$: of([]), testTypeIdChanged: () => {} } }, - ], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TestTypeSelectComponent], + imports: [RouterTestingModule, HttpClientTestingModule], + providers: [ + DynamicFormService, + provideMockStore({ initialState: initialAppState }), + { provide: TestTypesService, useValue: { selectAllTestTypes$: of([]), testTypeIdChanged: () => {} } }, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TestTypeSelectComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(TestTypeSelectComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it('should return testType id', () => { - expect(component.tackByFn(0, createMockTestTypeCategory({ id: '1' }))).toBe('1'); - }); + it('should return testType id', () => { + expect(component.tackByFn(0, createMockTestTypeCategory({ id: '1' }))).toBe('1'); + }); - it('should return true if prop nextTestTypesOrCategories exists', () => { - expect(component.hasNext(createMockTestTypeCategory({ nextTestTypesOrCategories: [] }))).toBeTruthy(); - expect(component.hasNext(createMockTestTypeCategory())).toBeFalsy(); - }); + it('should return true if prop nextTestTypesOrCategories exists', () => { + expect(component.hasNext(createMockTestTypeCategory({ nextTestTypesOrCategories: [] }))).toBeTruthy(); + expect(component.hasNext(createMockTestTypeCategory())).toBeFalsy(); + }); - it('should return true if category with given id exists in array', () => { - component.categories = new Array(3).fill(0).map((id) => createMockTestTypeCategory({ id: `${id + 1}` })); - expect(component.isSelected('1')).toBeTruthy(); - expect(component.isSelected('4')).toBeFalsy(); - }); + it('should return true if category with given id exists in array', () => { + component.categories = new Array(3).fill(0).map((id) => createMockTestTypeCategory({ id: `${id + 1}` })); + expect(component.isSelected('1')).toBeTruthy(); + expect(component.isSelected('4')).toBeFalsy(); + }); - describe('TestTypeSelectComponent.prototype.handleCategory.name', () => { - it('should emit selected testType through testTypeSelected', (done) => { - component.testTypeSelected.subscribe((val) => { - expect(val.id).toBe('1'); - done(); - }); - component.categories = new Array(3).fill(0).map((id) => createMockTestTypeCategory({ id: `${id + 1}` })); - component.handleCategory(createMockTestTypeCategory({ id: '1' }), 0); - }); + describe('TestTypeSelectComponent.prototype.handleCategory.name', () => { + it('should emit selected testType through testTypeSelected', (done) => { + component.testTypeSelected.subscribe((val) => { + expect(val.id).toBe('1'); + done(); + }); + component.categories = new Array(3).fill(0).map((id) => createMockTestTypeCategory({ id: `${id + 1}` })); + component.handleCategory(createMockTestTypeCategory({ id: '1' }), 0); + }); - it('should push a new category into categories', () => { - component.categories = new Array(2).fill(0).map((id) => createMockTestTypeCategory({ id: `${id + 1}` })); - component.handleCategory(createMockTestTypeCategory({ id: '3', nextTestTypesOrCategories: [] }), 2); - expect(component.categories).toHaveLength(3); - }); + it('should push a new category into categories', () => { + component.categories = new Array(2).fill(0).map((id) => createMockTestTypeCategory({ id: `${id + 1}` })); + component.handleCategory(createMockTestTypeCategory({ id: '3', nextTestTypesOrCategories: [] }), 2); + expect(component.categories).toHaveLength(3); + }); - it('should replace last category for given categories', () => { - component.categories = new Array(2).fill(0).map((id) => createMockTestTypeCategory({ id: `${id + 1}` })); - component.handleCategory(createMockTestTypeCategory({ id: '3', nextTestTypesOrCategories: [] }), 1); - expect(component.categories).toHaveLength(2); - expect(component.categories[1].id).toBe('3'); - }); - }); + it('should replace last category for given categories', () => { + component.categories = new Array(2).fill(0).map((id) => createMockTestTypeCategory({ id: `${id + 1}` })); + component.handleCategory(createMockTestTypeCategory({ id: '3', nextTestTypesOrCategories: [] }), 1); + expect(component.categories).toHaveLength(2); + expect(component.categories[1].id).toBe('3'); + }); + }); }); diff --git a/src/app/features/test-records/components/test-type-select/test-type-select.component.ts b/src/app/features/test-records/components/test-type-select/test-type-select.component.ts index 1b05a6d36e..5ac8fcb55c 100644 --- a/src/app/features/test-records/components/test-type-select/test-type-select.component.ts +++ b/src/app/features/test-records/components/test-type-select/test-type-select.component.ts @@ -1,6 +1,4 @@ -import { - Component, EventEmitter, OnInit, Output, -} from '@angular/core'; +import { Component, EventEmitter, OnInit, Output } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { TestType, TestTypeCategory, TestTypesTaxonomy } from '@api/test-types'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; @@ -8,53 +6,52 @@ import { TestTypesService } from '@services/test-types/test-types.service'; import { Observable } from 'rxjs'; @Component({ - selector: 'app-test-type-select', - templateUrl: './test-type-select.component.html', - styleUrls: ['./test-type-select.component.scss'], + selector: 'app-test-type-select', + templateUrl: './test-type-select.component.html', + styleUrls: ['./test-type-select.component.scss'], }) export class TestTypeSelectComponent implements OnInit { - @Output() testTypeSelected = new EventEmitter(); - - categories: Array = []; - - constructor( - private testTypesService: TestTypesService, - private technicalRecordService: TechnicalRecordService, - private router: Router, - private route: ActivatedRoute, - ) {} - ngOnInit(): void { - - this.technicalRecordService.techRecordHistory$.subscribe((recordHistory) => { - if (!recordHistory) { - void this.router.navigate(['../../'], { relativeTo: this.route.parent }); - } - }); - } - - get selectAllTestTypes$(): Observable { - return this.testTypesService.selectAllTestTypes$; - } - - tackByFn(i: number, testType: TestType | TestTypeCategory) { - return testType.id; - } - - handleCategory(category: TestType | TestTypeCategory, i: number) { - this.categories.length = i; - - if (Object.prototype.hasOwnProperty.call(category, 'nextTestTypesOrCategories')) { - this.categories.push(category as TestTypeCategory); - } else { - this.testTypeSelected.emit(category); - } - } - - hasNext(category: TestType | TestTypeCategory) { - return Object.prototype.hasOwnProperty.call(category, 'nextTestTypesOrCategories'); - } - - isSelected(id: string) { - return this.categories.map((t) => t.id).includes(id); - } + @Output() testTypeSelected = new EventEmitter(); + + categories: Array = []; + + constructor( + private testTypesService: TestTypesService, + private technicalRecordService: TechnicalRecordService, + private router: Router, + private route: ActivatedRoute + ) {} + ngOnInit(): void { + this.technicalRecordService.techRecordHistory$.subscribe((recordHistory) => { + if (!recordHistory) { + void this.router.navigate(['../../'], { relativeTo: this.route.parent }); + } + }); + } + + get selectAllTestTypes$(): Observable { + return this.testTypesService.selectAllTestTypes$; + } + + tackByFn(i: number, testType: TestType | TestTypeCategory) { + return testType.id; + } + + handleCategory(category: TestType | TestTypeCategory, i: number) { + this.categories.length = i; + + if (Object.prototype.hasOwnProperty.call(category, 'nextTestTypesOrCategories')) { + this.categories.push(category as TestTypeCategory); + } else { + this.testTypeSelected.emit(category); + } + } + + hasNext(category: TestType | TestTypeCategory) { + return Object.prototype.hasOwnProperty.call(category, 'nextTestTypesOrCategories'); + } + + isSelected(id: string) { + return this.categories.map((t) => t.id).includes(id); + } } diff --git a/src/app/features/test-records/components/vehicle-header/vehicle-header.component.spec.ts b/src/app/features/test-records/components/vehicle-header/vehicle-header.component.spec.ts index 5fda510aa2..6332718574 100644 --- a/src/app/features/test-records/components/vehicle-header/vehicle-header.component.spec.ts +++ b/src/app/features/test-records/components/vehicle-header/vehicle-header.component.spec.ts @@ -1,99 +1,99 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; import { TestTypesService } from '@api/test-types'; +import { V3TechRecordModel, VehicleConfigurations, VehicleTypes } from '@models/vehicle-tech-record.model'; import { provideMockStore } from '@ngrx/store/testing'; import { ResultOfTestService } from '@services/result-of-test/result-of-test.service'; +import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { SharedModule } from '@shared/shared.module'; import { initialAppState } from '@store/.'; -import { VehicleTypes, VehicleConfigurations, V3TechRecordModel } from '@models/vehicle-tech-record.model'; -import { RouterTestingModule } from '@angular/router/testing'; -import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { of } from 'rxjs'; import { VehicleHeaderComponent } from './vehicle-header.component'; const mockTechnicalRecordService = { - get techRecord$() { - return of({ systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' }); - }, + get techRecord$() { + return of({ systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' }); + }, }; describe('VehicleHeaderComponent', () => { - let component: VehicleHeaderComponent; - let fixture: ComponentFixture; + let component: VehicleHeaderComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [VehicleHeaderComponent], - imports: [SharedModule, HttpClientTestingModule, RouterTestingModule], - providers: [ - TestTypesService, - provideMockStore({ initialState: initialAppState }), - ResultOfTestService, - { provide: TechnicalRecordService, useValue: mockTechnicalRecordService }, - ], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [VehicleHeaderComponent], + imports: [SharedModule, HttpClientTestingModule, RouterTestingModule], + providers: [ + TestTypesService, + provideMockStore({ initialState: initialAppState }), + ResultOfTestService, + { provide: TechnicalRecordService, useValue: mockTechnicalRecordService }, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(VehicleHeaderComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(VehicleHeaderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it('should combine the odometer reading', () => { - expect(component.combinedOdometerReading('1234', 'kilometres')).toBe('1234 km'); - }); + it('should combine the odometer reading', () => { + expect(component.combinedOdometerReading('1234', 'kilometres')).toBe('1234 km'); + }); - it('should display the unit if the reading is undefined', () => { - expect(component.combinedOdometerReading(undefined, 'kilometres')).toBe(' km'); - }); + it('should display the unit if the reading is undefined', () => { + expect(component.combinedOdometerReading(undefined, 'kilometres')).toBe(' km'); + }); - it('should display the reading if the unit is undefined', () => { - expect(component.combinedOdometerReading('1234', undefined)).toBe('1234 '); - }); + it('should display the reading if the unit is undefined', () => { + expect(component.combinedOdometerReading('1234', undefined)).toBe('1234 '); + }); - it('should display the correct data based on vehicle type', () => { - const mockRecord = { - techRecord_vehicleConfiguration: VehicleConfigurations.RIGID, - techRecord_bodyMake: 'testBody', - techRecord_bodyModel: 'testBodyModel', - techRecord_chassisMake: 'testChassis', - techRecord_chassisModel: 'testChassisModel', - techRecord_make: 'testHGV', - techRecord_model: 'testHGVModel', - } as unknown as V3TechRecordModel; + it('should display the correct data based on vehicle type', () => { + const mockRecord = { + techRecord_vehicleConfiguration: VehicleConfigurations.RIGID, + techRecord_bodyMake: 'testBody', + techRecord_bodyModel: 'testBodyModel', + techRecord_chassisMake: 'testChassis', + techRecord_chassisModel: 'testChassisModel', + techRecord_make: 'testHGV', + techRecord_model: 'testHGVModel', + } as unknown as V3TechRecordModel; - expect(component.getVehicleDescription(mockRecord, VehicleTypes.TRL)).toBe('rigid'); - expect(component.getVehicleDescription(mockRecord, VehicleTypes.PSV)).toBe('testBody-testBodyModel'); - expect(component.getVehicleDescription(mockRecord, VehicleTypes.HGV)).toBe('testHGV-testHGVModel'); - }); + expect(component.getVehicleDescription(mockRecord, VehicleTypes.TRL)).toBe('rigid'); + expect(component.getVehicleDescription(mockRecord, VehicleTypes.PSV)).toBe('testBody-testBodyModel'); + expect(component.getVehicleDescription(mockRecord, VehicleTypes.HGV)).toBe('testHGV-testHGVModel'); + }); - it('should display an empty string if all required data cannot be retrieved', () => { - const mockRecord = { - techRecord_bodyMake: '', - techRecord_bodyModel: 'testBodyModel', - techRecord_chassisMake: '', - techRecord_chassisModel: 'testChassisModel', - techRecord_make: '', - techRecord_model: 'testHGVModel', - } as unknown as V3TechRecordModel; + it('should display an empty string if all required data cannot be retrieved', () => { + const mockRecord = { + techRecord_bodyMake: '', + techRecord_bodyModel: 'testBodyModel', + techRecord_chassisMake: '', + techRecord_chassisModel: 'testChassisModel', + techRecord_make: '', + techRecord_model: 'testHGVModel', + } as unknown as V3TechRecordModel; - expect(component.getVehicleDescription(mockRecord, VehicleTypes.TRL)).toBeFalsy(); - expect(component.getVehicleDescription(mockRecord, VehicleTypes.PSV)).toBeFalsy(); - expect(component.getVehicleDescription(mockRecord, VehicleTypes.HGV)).toBeFalsy(); - }); + expect(component.getVehicleDescription(mockRecord, VehicleTypes.TRL)).toBeFalsy(); + expect(component.getVehicleDescription(mockRecord, VehicleTypes.PSV)).toBeFalsy(); + expect(component.getVehicleDescription(mockRecord, VehicleTypes.HGV)).toBeFalsy(); + }); - it('should display "Unknown Vehicle Type" if vehicle type is unknown/undefined', () => { - const mockRecord = { - techRecord_bodyMake: 'testBodyMake', - techRecord_bodyModel: 'testBodyModel', - techRecord_chassisMake: 'testChassisMake', - techRecord_chassisModel: 'testChassisModel', - } as unknown as V3TechRecordModel; - expect(component.getVehicleDescription(mockRecord, undefined)).toBe('Unknown Vehicle Type'); - }); + it('should display "Unknown Vehicle Type" if vehicle type is unknown/undefined', () => { + const mockRecord = { + techRecord_bodyMake: 'testBodyMake', + techRecord_bodyModel: 'testBodyModel', + techRecord_chassisMake: 'testChassisMake', + techRecord_chassisModel: 'testChassisModel', + } as unknown as V3TechRecordModel; + expect(component.getVehicleDescription(mockRecord, undefined)).toBe('Unknown Vehicle Type'); + }); }); diff --git a/src/app/features/test-records/components/vehicle-header/vehicle-header.component.ts b/src/app/features/test-records/components/vehicle-header/vehicle-header.component.ts index 1f4c447c39..56a16cd209 100644 --- a/src/app/features/test-records/components/vehicle-header/vehicle-header.component.ts +++ b/src/app/features/test-records/components/vehicle-header/vehicle-header.component.ts @@ -14,92 +14,98 @@ import { techRecord } from '@store/technical-records'; import { Observable } from 'rxjs'; @Component({ - selector: 'app-vehicle-header', - templateUrl: './vehicle-header.component.html', - styleUrls: ['./vehicle-header.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-vehicle-header', + templateUrl: './vehicle-header.component.html', + styleUrls: ['./vehicle-header.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class VehicleHeaderComponent { - @Input() isEditing = false; - @Input() testResult?: TestResultModel | null; - @Input() testNumber?: string | null; - @Input() isReview = false; + @Input() isEditing = false; + @Input() testResult?: TestResultModel | null; + @Input() testNumber?: string | null; + @Input() isReview = false; - constructor(private testTypesService: TestTypesService, private techRecordService: TechnicalRecordService, private store: Store) {} + constructor( + private testTypesService: TestTypesService, + private techRecordService: TechnicalRecordService, + private store: Store + ) {} - get test(): TestType | undefined { - return this.testResult?.testTypes?.find((t) => this.testNumber === t.testNumber); - } + get test(): TestType | undefined { + return this.testResult?.testTypes?.find((t) => this.testNumber === t.testNumber); + } - get selectAllTestTypes$(): Observable { - return this.testTypesService.selectAllTestTypes$; - } + get selectAllTestTypes$(): Observable { + return this.testTypesService.selectAllTestTypes$; + } - combinedOdometerReading(reading: string | undefined, unit: string | undefined) { - return `${reading ?? ''} ${(unit && (unit === 'kilometres' ? 'km' : 'mi')) ?? ''}`; - } + combinedOdometerReading(reading: string | undefined, unit: string | undefined) { + return `${reading ?? ''} ${(unit && (unit === 'kilometres' ? 'km' : 'mi')) ?? ''}`; + } - get techRecord$(): Observable { - return this.store.select(techRecord); - } + get techRecord$(): Observable { + return this.store.select(techRecord); + } - get vehicleTypes() { - return VehicleTypes; - } + get vehicleTypes() { + return VehicleTypes; + } - get referenceDataType() { - return ReferenceDataResourceType; - } + get referenceDataType() { + return ReferenceDataResourceType; + } - get resultOfTest(): string | undefined { - return this.testResult?.testStatus === TestResultStatus.CANCELLED ? TestResultStatus.CANCELLED : this.testResult?.testTypes[0].testResult; - } + get resultOfTest(): string | undefined { + return this.testResult?.testStatus === TestResultStatus.CANCELLED + ? TestResultStatus.CANCELLED + : this.testResult?.testTypes[0].testResult; + } - get tagType(): TagTypes { - switch (this.resultOfTest) { - case resultOfTestEnum.pass: - return TagType.GREEN; - case resultOfTestEnum.prs: - return TagType.BLUE; - case resultOfTestEnum.fail: - return TagType.RED; - case TestResultStatus.CANCELLED: - return TagType.YELLOW; - default: - return TagType.ORANGE; - } - } + get tagType(): TagTypes { + switch (this.resultOfTest) { + case resultOfTestEnum.pass: + return TagType.GREEN; + case resultOfTestEnum.prs: + return TagType.BLUE; + case resultOfTestEnum.fail: + return TagType.RED; + case TestResultStatus.CANCELLED: + return TagType.YELLOW; + default: + return TagType.ORANGE; + } + } - get testCode(): string | undefined { - const testCode = this.testResult?.testTypes[0].testCode; - return testCode ? `(${testCode})` : ''; - } + get testCode(): string | undefined { + const testCode = this.testResult?.testTypes[0].testCode; + return testCode ? `(${testCode})` : ''; + } - // eslint-disable-next-line @typescript-eslint/no-shadow - getVehicleDescription(techRecord: V3TechRecordModel, vehicleType: VehicleTypes | undefined) { - switch (vehicleType) { - case VehicleTypes.TRL: - return (techRecord as TechRecordType).techRecord_vehicleConfiguration ?? ''; - case VehicleTypes.PSV: - return (techRecord as TechRecordType).techRecord_bodyMake - && (techRecord as TechRecordType).techRecord_bodyModel - ? `${(techRecord as TechRecordType).techRecord_bodyMake ?? ''}-${ - (techRecord as TechRecordType).techRecord_bodyModel ?? '' - }` - : ''; - case VehicleTypes.HGV: - return (techRecord as TechRecordType).techRecord_make - && (techRecord as TechRecordType).techRecord_model - ? `${(techRecord as TechRecordType).techRecord_make ?? ''}-${ - (techRecord as TechRecordType).techRecord_model ?? '' - }` - : ''; - case VehicleTypes.MOTORCYCLE: - case VehicleTypes.LGV: - case VehicleTypes.CAR: - return ''; - default: - return 'Unknown Vehicle Type'; - } - } + // eslint-disable-next-line @typescript-eslint/no-shadow + getVehicleDescription(techRecord: V3TechRecordModel, vehicleType: VehicleTypes | undefined) { + switch (vehicleType) { + case VehicleTypes.TRL: + return (techRecord as TechRecordType).techRecord_vehicleConfiguration ?? ''; + case VehicleTypes.PSV: + return (techRecord as TechRecordType).techRecord_bodyMake && + (techRecord as TechRecordType).techRecord_bodyModel + ? `${(techRecord as TechRecordType).techRecord_bodyMake ?? ''}-${ + (techRecord as TechRecordType).techRecord_bodyModel ?? '' + }` + : ''; + case VehicleTypes.HGV: + return (techRecord as TechRecordType).techRecord_make && + (techRecord as TechRecordType).techRecord_model + ? `${(techRecord as TechRecordType).techRecord_make ?? ''}-${ + (techRecord as TechRecordType).techRecord_model ?? '' + }` + : ''; + case VehicleTypes.MOTORCYCLE: + case VehicleTypes.LGV: + case VehicleTypes.CAR: + return ''; + default: + return 'Unknown Vehicle Type'; + } + } } diff --git a/src/app/features/test-records/create/create-test-records-routing.module.ts b/src/app/features/test-records/create/create-test-records-routing.module.ts index f3687d34ee..791467732d 100644 --- a/src/app/features/test-records/create/create-test-records-routing.module.ts +++ b/src/app/features/test-records/create/create-test-records-routing.module.ts @@ -6,99 +6,103 @@ import { DefectComponent } from '@forms/custom-sections/defect/defect.component' import { RequiredStandardComponent } from '@forms/custom-sections/required-standard/required-standard.component'; import { RoleGuard } from '@guards/role-guard/roles.guard'; import { Roles } from '@models/roles.enum'; +import { TestRecordCreateRoutes } from '@models/routes.enum'; import { contingencyTestResolver } from 'src/app/resolvers/contingency-test/contingency-test.resolver'; import { defectsTaxonomyResolver } from 'src/app/resolvers/defects-taxonomy/defects-taxonomy.resolver'; import { requiredStandardsResolver } from 'src/app/resolvers/required-standards/required-standards.resolver'; import { testStationsResolver } from 'src/app/resolvers/test-stations/test-stations.resolver'; import { testTypeTaxonomyResolver } from 'src/app/resolvers/test-type-taxonomy/test-type-taxonomy.resolver'; -import { TestRecordCreateRoutes } from '@models/routes.enum'; import { CreateTestRecordComponent } from './views/create-test-record/create-test-record.component'; import { CreateTestTypeComponent } from './views/create-test-type/create-test-type.component'; import { TestRouterOutletComponent } from './views/test-router-outlet/test-router-outlet.component'; const routes: Routes = [ - { - path: '', - component: TestRouterOutletComponent, - resolve: { contingencyTest: contingencyTestResolver }, - children: [ - { - path: '', - redirectTo: 'type', - }, - { - path: TestRecordCreateRoutes.TYPE, - component: CreateTestTypeComponent, - resolve: { testTypeTaxonomy: testTypeTaxonomyResolver, contingencyTest: contingencyTestResolver }, - }, - { - path: TestRecordCreateRoutes.TEST_DETAILS, - component: TestRouterOutletComponent, - resolve: { TestTypeTaxonomy: testTypeTaxonomyResolver, defectTaxonomy: defectsTaxonomyResolver, testStations: testStationsResolver }, - data: { title: 'Test details', roles: Roles.TestResultCreateContingency, breadcrumbPreserveQueryParams: true }, - canActivate: [RoleGuard], - children: [ - { - path: '', - component: CreateTestRecordComponent, - }, - { - path: TestRecordCreateRoutes.DEFECT, - component: DefectComponent, - data: { title: 'Defect', roles: Roles.TestResultCreateContingency, isEditing: true }, - canActivate: [RoleGuard], - }, - { - path: TestRecordCreateRoutes.SELECT_DEFECT, - component: TestRouterOutletComponent, - data: { title: 'Select defect', roles: Roles.TestResultCreateContingency }, - children: [ - { - path: '', - component: DefectSelectComponent, - canActivate: [RoleGuard], - }, - { - path: TestRecordCreateRoutes.SELECT_DEFECT_REF, - component: DefectComponent, - data: { title: 'Defect', roles: Roles.TestResultCreateContingency, isEditing: true }, - canActivate: [RoleGuard], - }, - ], - }, - { - path: TestRecordCreateRoutes.REQUIRED_STANDARD, - component: RequiredStandardComponent, - data: { title: 'Required Standard', roles: Roles.TestResultCreateContingency, isEditing: true }, - canActivate: [RoleGuard], - }, - { - path: TestRecordCreateRoutes.SELECT_REQUIRED_STANDARD, - component: TestRouterOutletComponent, - resolve: { RequiredStandards: requiredStandardsResolver }, - data: { title: 'Select Required Standard', roles: Roles.TestResultCreateContingency }, - children: [ - { - path: '', - component: RequiredStandardSelectComponent, - canActivate: [RoleGuard], - }, - { - path: TestRecordCreateRoutes.REQUIRED_STANDARD_REF, - component: RequiredStandardComponent, - data: { title: 'Required Standard', roles: Roles.TestResultCreateContingency, isEditing: true }, - canActivate: [RoleGuard], - }, - ], - }, - ], - }, - ], - }, + { + path: '', + component: TestRouterOutletComponent, + resolve: { contingencyTest: contingencyTestResolver }, + children: [ + { + path: '', + redirectTo: 'type', + }, + { + path: TestRecordCreateRoutes.TYPE, + component: CreateTestTypeComponent, + resolve: { testTypeTaxonomy: testTypeTaxonomyResolver, contingencyTest: contingencyTestResolver }, + }, + { + path: TestRecordCreateRoutes.TEST_DETAILS, + component: TestRouterOutletComponent, + resolve: { + TestTypeTaxonomy: testTypeTaxonomyResolver, + defectTaxonomy: defectsTaxonomyResolver, + testStations: testStationsResolver, + }, + data: { title: 'Test details', roles: Roles.TestResultCreateContingency, breadcrumbPreserveQueryParams: true }, + canActivate: [RoleGuard], + children: [ + { + path: '', + component: CreateTestRecordComponent, + }, + { + path: TestRecordCreateRoutes.DEFECT, + component: DefectComponent, + data: { title: 'Defect', roles: Roles.TestResultCreateContingency, isEditing: true }, + canActivate: [RoleGuard], + }, + { + path: TestRecordCreateRoutes.SELECT_DEFECT, + component: TestRouterOutletComponent, + data: { title: 'Select defect', roles: Roles.TestResultCreateContingency }, + children: [ + { + path: '', + component: DefectSelectComponent, + canActivate: [RoleGuard], + }, + { + path: TestRecordCreateRoutes.SELECT_DEFECT_REF, + component: DefectComponent, + data: { title: 'Defect', roles: Roles.TestResultCreateContingency, isEditing: true }, + canActivate: [RoleGuard], + }, + ], + }, + { + path: TestRecordCreateRoutes.REQUIRED_STANDARD, + component: RequiredStandardComponent, + data: { title: 'Required Standard', roles: Roles.TestResultCreateContingency, isEditing: true }, + canActivate: [RoleGuard], + }, + { + path: TestRecordCreateRoutes.SELECT_REQUIRED_STANDARD, + component: TestRouterOutletComponent, + resolve: { RequiredStandards: requiredStandardsResolver }, + data: { title: 'Select Required Standard', roles: Roles.TestResultCreateContingency }, + children: [ + { + path: '', + component: RequiredStandardSelectComponent, + canActivate: [RoleGuard], + }, + { + path: TestRecordCreateRoutes.REQUIRED_STANDARD_REF, + component: RequiredStandardComponent, + data: { title: 'Required Standard', roles: Roles.TestResultCreateContingency, isEditing: true }, + canActivate: [RoleGuard], + }, + ], + }, + ], + }, + ], + }, ]; @NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule], + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], }) export class CreateTestRecordsRoutingModule {} diff --git a/src/app/features/test-records/create/create-test-records.module.ts b/src/app/features/test-records/create/create-test-records.module.ts index ec12acd0c7..e196a31c94 100644 --- a/src/app/features/test-records/create/create-test-records.module.ts +++ b/src/app/features/test-records/create/create-test-records.module.ts @@ -10,7 +10,15 @@ import { CreateTestTypeComponent } from './views/create-test-type/create-test-ty import { TestRouterOutletComponent } from './views/test-router-outlet/test-router-outlet.component'; @NgModule({ - declarations: [CreateTestTypeComponent, CreateTestRecordComponent, TestRouterOutletComponent], - imports: [CommonModule, CreateTestRecordsRoutingModule, DynamicFormsModule, SharedModule, FormsModule, ReactiveFormsModule, TestRecordsModule], + declarations: [CreateTestTypeComponent, CreateTestRecordComponent, TestRouterOutletComponent], + imports: [ + CommonModule, + CreateTestRecordsRoutingModule, + DynamicFormsModule, + SharedModule, + FormsModule, + ReactiveFormsModule, + TestRecordsModule, + ], }) export class CreateTestRecordsModule {} diff --git a/src/app/features/test-records/create/views/create-test-record/create-test-record.component.spec.ts b/src/app/features/test-records/create/views/create-test-record/create-test-record.component.spec.ts index 5097ab41d1..027368c626 100644 --- a/src/app/features/test-records/create/views/create-test-record/create-test-record.component.spec.ts +++ b/src/app/features/test-records/create/views/create-test-record/create-test-record.component.spec.ts @@ -1,10 +1,12 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { - ComponentFixture, fakeAsync, flush, TestBed, tick, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, flush, tick } from '@angular/core/testing'; import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; -import { DefaultService as CreateTestResultsService, GetTestResultsService, UpdateTestResultsService } from '@api/test-results'; +import { + DefaultService as CreateTestResultsService, + GetTestResultsService, + UpdateTestResultsService, +} from '@api/test-results'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { RoleRequiredDirective } from '@directives/app-role-required.directive'; import { AbandonDialogComponent } from '@forms/custom-sections/abandon-dialog/abandon-dialog.component'; @@ -30,200 +32,202 @@ import { NumberPlateComponent } from '@shared/components/number-plate/number-pla import { DefaultNullOrEmpty } from '@shared/pipes/default-null-or-empty/default-null-or-empty.pipe'; import { TestTypeNamePipe } from '@shared/pipes/test-type-name/test-type-name.pipe'; import { SharedModule } from '@shared/shared.module'; -import { initialAppState, State } from '@store/.'; -import { - sectionTemplates, testResultInEdit, toEditOrNotToEdit, -} from '@store/test-records'; -import { Observable, of, ReplaySubject } from 'rxjs'; +import { State, initialAppState } from '@store/.'; +import { sectionTemplates, testResultInEdit, toEditOrNotToEdit } from '@store/test-records'; +import { Observable, ReplaySubject, of } from 'rxjs'; import { BaseTestRecordComponent } from '../../../components/base-test-record/base-test-record.component'; import { VehicleHeaderComponent } from '../../../components/vehicle-header/vehicle-header.component'; import { CreateTestRecordComponent } from './create-test-record.component'; describe('CreateTestRecordComponent', () => { - let component: CreateTestRecordComponent; - let fixture: ComponentFixture; - const actions$ = new ReplaySubject(); - let router: Router; - let testRecordsService: TestRecordsService; - let store: MockStore; - - const mockTechnicalRecordService = { - get viewableTechRecord$() { - return { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' }; - }, - }; - const MockUserService = { - getUserName$: jest.fn().mockReturnValue(new Observable()), - roles$: of([Roles.TestResultAmend, Roles.TestResultView]), - }; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ - CreateTestRecordComponent, - BaseTestRecordComponent, - DefaultNullOrEmpty, - TestTypeNamePipe, - ButtonComponent, - ButtonGroupComponent, - IconComponent, - NumberPlateComponent, - VehicleHeaderComponent, - RoleRequiredDirective, - ], - imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule, SharedModule], - providers: [ - GlobalErrorService, - RouterService, - TestRecordsService, - GetTestResultsService, - UpdateTestResultsService, - CreateTestResultsService, - { provide: UserService, useValue: MockUserService }, - provideMockStore({ initialState: initialAppState }), - provideMockActions(() => actions$), - { provide: TechnicalRecordService, useValue: mockTechnicalRecordService }, - DynamicFormService, - ], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(CreateTestRecordComponent); - component = fixture.componentInstance; - router = TestBed.inject(Router); - testRecordsService = TestBed.inject(TestRecordsService); - store = TestBed.inject(MockStore); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should navigate back to the tech record', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - component.backToTechRecord(); - expect(navigateSpy).toHaveBeenCalled(); - }); - - it('should call createTestResult with value of all forms merged into one', async () => { - fixture.detectChanges(); - const createTestResultSpy = jest.spyOn(testRecordsService, 'createTestResult').mockImplementation(() => {}); - const testRecord = { testResultId: '1', testTypes: [{ testTypeId: '2' }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testRecord); - store.overrideSelector(sectionTemplates, Object.values(contingencyTestTemplates.psv['testTypesGroup1'] ?? {})); - - component.isAnyFormInvalid = jest.fn().mockReturnValue(false); - - await component.handleSave(); - fixture.detectChanges(); - expect(createTestResultSpy).toHaveBeenCalledTimes(1); - expect(createTestResultSpy).toHaveBeenCalledWith(testRecord); - }); - - it('should not call createTestResult if some forms are invalid', async () => { - const createTestResultSpy = jest.spyOn(testRecordsService, 'createTestResult').mockImplementation(() => {}); - const testRecord = { testResultId: '1', testTypes: [{ testTypeId: '2' }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testRecord); - store.overrideSelector(sectionTemplates, Object.values(contingencyTestTemplates.psv['testTypesGroup1'] ?? '')); - - fixture.detectChanges(); - component.isAnyFormInvalid = jest.fn().mockReturnValue(true); - - await component.handleSave(); - - expect(createTestResultSpy).not.toHaveBeenCalled(); - }); - - it('should dispatch the action to update the test result in edit', () => { - const updateTestResultSpy = jest.spyOn(testRecordsService, 'updateEditingTestResult').mockImplementation(() => {}); - component.handleNewTestResult({} as TestResultModel); - expect(updateTestResultSpy).toHaveBeenCalled(); - }); - - describe('CreateTestRecordComponent.prototype.isAnyFormInvalid.name', () => { - beforeEach(() => { - store.overrideSelector(testResultInEdit, mockTestResult()); - store.overrideSelector(toEditOrNotToEdit, undefined); - }); - - afterEach(() => { - store.resetSelectors(); - }); - - it('should return true if some forms are invalid', () => { - component.abandonDialog = { dynamicFormGroup: { form: { controls: { errors: 'foo' }, invalid: true } } } as unknown as AbandonDialogComponent; - component.testMode = TestModeEnum.Abandon; - DynamicFormService.validate = jest.fn(); - expect(component.isAnyFormInvalid()).toBe(true); - }); - - it('should return false if no forms are invalid', fakeAsync(() => { - tick(); - fixture.detectChanges(); - expect(component.isAnyFormInvalid()).toBe(false); - flush(); - })); - }); - - describe('CreateTestRecordComponent.prototype.abandon.name', () => { - it('should set testMode to be abandon', () => { - component.abandon(); - expect(component.testMode).toEqual(TestModeEnum.Abandon); - }); - }); - - describe('CreateTestRecordComponent.prototype.handleAbandonAction.name', () => { - it('should call handle save', async () => { - const handleSaveSpy = jest.spyOn(component, 'handleSave'); - - await component.handleAbandonAction('yes'); - - expect(handleSaveSpy).toHaveBeenCalledTimes(1); - }); - - it('should set testMode to be edit', async () => { - component.testMode = TestModeEnum.Abandon; - - await component.handleAbandonAction('no'); - - expect(component.testMode).toEqual(TestModeEnum.Edit); - }); - }); - - it('should combine forms', async () => { - component['baseTestRecordComponent'] = { - sections: { forEach: jest.fn().mockReturnValue([{ foo: 'foo' }]) }, - } as unknown as BaseTestRecordComponent; - - // eslint-disable-next-line @typescript-eslint/no-misused-promises - const createTestResultSpy = jest.spyOn(testRecordsService, 'createTestResult').mockImplementation(() => Promise.resolve(true)); - const testRecord = { testResultId: '1', testTypes: [{ testTypeId: '2' }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testRecord); - store.overrideSelector(sectionTemplates, Object.values(contingencyTestTemplates.psv['testTypesGroup1'] ?? '')); - - fixture.detectChanges(); - - await component.handleSave(); - - fixture.detectChanges(); - expect(createTestResultSpy).toHaveBeenCalledTimes(1); - expect(createTestResultSpy).toHaveBeenCalledWith(testRecord); - }); - - it('should set testMode to be view', async () => { - component.techRecord = {} as V3TechRecordModel; - component.isAnyFormInvalid = jest.fn().mockReturnValue(false); - await component.handleReview(); - - expect(component.testMode).toEqual(TestModeEnum.View); - }); - - it('should set testMode back to edit', async () => { - component.isAnyFormInvalid = jest.fn().mockReturnValue(false); - await component.handleReview(); - component.handleCancel(); - - expect(component.testMode).toEqual(TestModeEnum.Edit); - }); + let component: CreateTestRecordComponent; + let fixture: ComponentFixture; + const actions$ = new ReplaySubject(); + let router: Router; + let testRecordsService: TestRecordsService; + let store: MockStore; + + const mockTechnicalRecordService = { + get viewableTechRecord$() { + return { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' }; + }, + }; + const MockUserService = { + getUserName$: jest.fn().mockReturnValue(new Observable()), + roles$: of([Roles.TestResultAmend, Roles.TestResultView]), + }; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + CreateTestRecordComponent, + BaseTestRecordComponent, + DefaultNullOrEmpty, + TestTypeNamePipe, + ButtonComponent, + ButtonGroupComponent, + IconComponent, + NumberPlateComponent, + VehicleHeaderComponent, + RoleRequiredDirective, + ], + imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule, SharedModule], + providers: [ + GlobalErrorService, + RouterService, + TestRecordsService, + GetTestResultsService, + UpdateTestResultsService, + CreateTestResultsService, + { provide: UserService, useValue: MockUserService }, + provideMockStore({ initialState: initialAppState }), + provideMockActions(() => actions$), + { provide: TechnicalRecordService, useValue: mockTechnicalRecordService }, + DynamicFormService, + ], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(CreateTestRecordComponent); + component = fixture.componentInstance; + router = TestBed.inject(Router); + testRecordsService = TestBed.inject(TestRecordsService); + store = TestBed.inject(MockStore); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should navigate back to the tech record', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + component.backToTechRecord(); + expect(navigateSpy).toHaveBeenCalled(); + }); + + it('should call createTestResult with value of all forms merged into one', async () => { + fixture.detectChanges(); + const createTestResultSpy = jest.spyOn(testRecordsService, 'createTestResult').mockImplementation(() => {}); + const testRecord = { testResultId: '1', testTypes: [{ testTypeId: '2' }] } as TestResultModel; + store.overrideSelector(testResultInEdit, testRecord); + store.overrideSelector(sectionTemplates, Object.values(contingencyTestTemplates.psv['testTypesGroup1'] ?? {})); + + component.isAnyFormInvalid = jest.fn().mockReturnValue(false); + + await component.handleSave(); + fixture.detectChanges(); + expect(createTestResultSpy).toHaveBeenCalledTimes(1); + expect(createTestResultSpy).toHaveBeenCalledWith(testRecord); + }); + + it('should not call createTestResult if some forms are invalid', async () => { + const createTestResultSpy = jest.spyOn(testRecordsService, 'createTestResult').mockImplementation(() => {}); + const testRecord = { testResultId: '1', testTypes: [{ testTypeId: '2' }] } as TestResultModel; + store.overrideSelector(testResultInEdit, testRecord); + store.overrideSelector(sectionTemplates, Object.values(contingencyTestTemplates.psv['testTypesGroup1'] ?? '')); + + fixture.detectChanges(); + component.isAnyFormInvalid = jest.fn().mockReturnValue(true); + + await component.handleSave(); + + expect(createTestResultSpy).not.toHaveBeenCalled(); + }); + + it('should dispatch the action to update the test result in edit', () => { + const updateTestResultSpy = jest.spyOn(testRecordsService, 'updateEditingTestResult').mockImplementation(() => {}); + component.handleNewTestResult({} as TestResultModel); + expect(updateTestResultSpy).toHaveBeenCalled(); + }); + + describe('CreateTestRecordComponent.prototype.isAnyFormInvalid.name', () => { + beforeEach(() => { + store.overrideSelector(testResultInEdit, mockTestResult()); + store.overrideSelector(toEditOrNotToEdit, undefined); + }); + + afterEach(() => { + store.resetSelectors(); + }); + + it('should return true if some forms are invalid', () => { + component.abandonDialog = { + dynamicFormGroup: { form: { controls: { errors: 'foo' }, invalid: true } }, + } as unknown as AbandonDialogComponent; + component.testMode = TestModeEnum.Abandon; + DynamicFormService.validate = jest.fn(); + expect(component.isAnyFormInvalid()).toBe(true); + }); + + it('should return false if no forms are invalid', fakeAsync(() => { + tick(); + fixture.detectChanges(); + expect(component.isAnyFormInvalid()).toBe(false); + flush(); + })); + }); + + describe('CreateTestRecordComponent.prototype.abandon.name', () => { + it('should set testMode to be abandon', () => { + component.abandon(); + expect(component.testMode).toEqual(TestModeEnum.Abandon); + }); + }); + + describe('CreateTestRecordComponent.prototype.handleAbandonAction.name', () => { + it('should call handle save', async () => { + const handleSaveSpy = jest.spyOn(component, 'handleSave'); + + await component.handleAbandonAction('yes'); + + expect(handleSaveSpy).toHaveBeenCalledTimes(1); + }); + + it('should set testMode to be edit', async () => { + component.testMode = TestModeEnum.Abandon; + + await component.handleAbandonAction('no'); + + expect(component.testMode).toEqual(TestModeEnum.Edit); + }); + }); + + it('should combine forms', async () => { + component['baseTestRecordComponent'] = { + sections: { forEach: jest.fn().mockReturnValue([{ foo: 'foo' }]) }, + } as unknown as BaseTestRecordComponent; + + // eslint-disable-next-line @typescript-eslint/no-misused-promises + const createTestResultSpy = jest + .spyOn(testRecordsService, 'createTestResult') + .mockImplementation(() => Promise.resolve(true)); + const testRecord = { testResultId: '1', testTypes: [{ testTypeId: '2' }] } as TestResultModel; + store.overrideSelector(testResultInEdit, testRecord); + store.overrideSelector(sectionTemplates, Object.values(contingencyTestTemplates.psv['testTypesGroup1'] ?? '')); + + fixture.detectChanges(); + + await component.handleSave(); + + fixture.detectChanges(); + expect(createTestResultSpy).toHaveBeenCalledTimes(1); + expect(createTestResultSpy).toHaveBeenCalledWith(testRecord); + }); + + it('should set testMode to be view', async () => { + component.techRecord = {} as V3TechRecordModel; + component.isAnyFormInvalid = jest.fn().mockReturnValue(false); + await component.handleReview(); + + expect(component.testMode).toEqual(TestModeEnum.View); + }); + + it('should set testMode back to edit', async () => { + component.isAnyFormInvalid = jest.fn().mockReturnValue(false); + await component.handleReview(); + component.handleCancel(); + + expect(component.testMode).toEqual(TestModeEnum.Edit); + }); }); diff --git a/src/app/features/test-records/create/views/create-test-record/create-test-record.component.ts b/src/app/features/test-records/create/views/create-test-record/create-test-record.component.ts index 3bf3344e50..9e60910340 100644 --- a/src/app/features/test-records/create/views/create-test-record/create-test-record.component.ts +++ b/src/app/features/test-records/create/views/create-test-record/create-test-record.component.ts @@ -1,6 +1,4 @@ -import { - AfterViewInit, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild, -} from '@angular/core'; +import { AfterViewInit, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalError } from '@core/components/global-error/global-error.interface'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; @@ -23,223 +21,271 @@ import { selectTechRecord } from '@store/technical-records'; import { createTestResultSuccess } from '@store/test-records'; import { getTypeOfTest } from '@store/test-types/selectors/test-types.selectors'; import cloneDeep from 'lodash.clonedeep'; -import { - BehaviorSubject, Observable, Subject, filter, firstValueFrom, map, of, take, takeUntil, tap, -} from 'rxjs'; +import { BehaviorSubject, Observable, Subject, filter, firstValueFrom, map, of, take, takeUntil, tap } from 'rxjs'; import { BaseTestRecordComponent } from '../../../components/base-test-record/base-test-record.component'; @Component({ - selector: 'app-create-test-record', - templateUrl: './create-test-record.component.html', + selector: 'app-create-test-record', + templateUrl: './create-test-record.component.html', }) export class CreateTestRecordComponent implements OnInit, OnDestroy, AfterViewInit { - @ViewChild(BaseTestRecordComponent) private baseTestRecordComponent?: BaseTestRecordComponent; - @ViewChild(AbandonDialogComponent) abandonDialog?: AbandonDialogComponent; - - private destroy$ = new Subject(); - - canCreate$ = new BehaviorSubject(false); - testMode = TestModeEnum.Edit; - testResult$: Observable = of(undefined); - testTypeId?: string; - techRecord: V3TechRecordModel | undefined = undefined; - - constructor( - private actions$: Actions, - private errorService: GlobalErrorService, - private route: ActivatedRoute, - private router: Router, - private routerService: RouterService, - private testRecordsService: TestRecordsService, - private cdr: ChangeDetectorRef, - private resultOfTestService: ResultOfTestService, - private store: Store, - private warningService: GlobalWarningService, - ) { - this.router.routeReuseStrategy.shouldReuseRoute = () => false; - } - - ngOnInit(): void { - this.testResult$ = this.testRecordsService.editingTestResult$.pipe(tap((editingTestResult) => !editingTestResult && this.backToTechRecord())); - - this.routerService - .getQueryParam$('testType') - .pipe( - take(1), - tap((testType) => !testType && this.backToTechRecord()), - filter((tt) => !!tt), - ) - .subscribe((testTypeId) => { - this.testRecordsService.contingencyTestTypeSelected(testTypeId as string); - this.testTypeId = testTypeId; - }); - - this.watchForCreateSuccess(); - - this.testRecordsService.canCreate$.pipe(take(1)).subscribe((val) => this.canCreate$.next(val)); - - this.store.select(selectTechRecord).pipe(take(1)).subscribe((techRecord) => { - this.techRecord = techRecord; - }); - } - - ngOnDestroy(): void { - this.errorService.clearErrors(); - - this.destroy$.next(); - this.destroy$.complete(); - } - - ngAfterViewInit(): void { - this.cdr.detectChanges(); - } - - backToTechRecord(): void { - void this.router.navigate(['../../..'], { relativeTo: this.route.parent }); - } - - /** - * Merge all section form values into one testResult and trigger action to update testResult. - * @returns void - */ - async handleSave(): Promise { - if (this.isAnyFormInvalid()) { - return; - } - - this.testRecordsService.cleanTestResult(); - - const testResult = await firstValueFrom(this.testResult$); - const testResultClone = cloneDeep(testResult) as TestResultModel; - - this.testRecordsService.createTestResult(testResultClone); - } - - async handleReview() { - if (this.isAnyFormInvalid()) return; - if (this.techRecord == null) return; - - this.errorService.clearErrors(); - this.testMode = TestModeEnum.View; - - const testResult = await firstValueFrom(this.testResult$); - if (testResult && this.techRecord?.techRecord_statusCode === StatusCodes.PROVISIONAL - && this.testTypeId - && this.validateUpdateStatus(testResult.testTypes[0].testResult, this.testTypeId)) { - const warnings: GlobalWarning[] = []; - warnings.push({ warning: 'This test will update the tech record to current, if the page is showing as provisional then refresh the page' }); - this.warningService.setWarnings(warnings); - } - } - - handleCancel() { - this.testMode = TestModeEnum.Edit; - this.warningService.clearWarnings(); - } - - watchForCreateSuccess() { - this.actions$.pipe(ofType(createTestResultSuccess), takeUntil(this.destroy$)).subscribe(() => { - this.backToTechRecord(); - }); - } - - handleNewTestResult(testResult: TestResultModel) { - this.testRecordsService.updateEditingTestResult(testResult); - } - - isAnyFormInvalid() { - const errors: GlobalError[] = []; - const forms = []; - - if (this.baseTestRecordComponent?.sections) { - this.baseTestRecordComponent.sections.forEach((section) => forms.push(section.form)); - } - - if (this.baseTestRecordComponent?.defects) { - forms.push(this.baseTestRecordComponent.defects.form); - } - - if (this.testMode === TestModeEnum.Abandon && this.abandonDialog?.dynamicFormGroup) { - forms.push(this.abandonDialog.dynamicFormGroup.form); - } - - forms.forEach((form) => { - DynamicFormService.validate(form, errors); - }); - - if (errors.length) { - this.errorService.setErrors(errors); - } - - return forms.some((form) => form.invalid); - } - - abandon() { - this.resultOfTestService.toggleAbandoned(resultOfTestEnum.abandoned); - - if (this.isAnyFormInvalid()) { - return; - } - - this.testMode = TestModeEnum.Abandon; - } - - async handleAbandonAction(event: string) { - switch (event) { - case 'yes': - await this.handleSave(); - break; - case 'no': - this.abandonDialog?.dynamicFormGroup?.form.reset(); - this.resultOfTestService.toggleAbandoned(resultOfTestEnum.pass); - this.testMode = TestModeEnum.Edit; - break; - default: - console.error('Invalid action'); - } - } - - get isDeskBased() { - return this.store.pipe( - select(getTypeOfTest(this.testTypeId)), - map((typeOfTest) => typeOfTest === TypeOfTest.DESK_BASED), - ); - } - - public get TestModeEnum(): typeof TestModeEnum { - return TestModeEnum; - } - - validateUpdateStatus = ( - testResult: string, - testTypeId: string, - ): boolean => ( - (testResult === 'pass' || testResult === 'prs') - && (this.isTestTypeFirstTest(testTypeId) - || this.isTestTypeNotifiableAlteration(testTypeId) - || this.isTestTypeCOIF(testTypeId) - || this.isTestTypeIVA(testTypeId)) - ); - - isTestTypeFirstTest(testTypeId: string): boolean { - const firstTestIds = ['41', '95', '65', '66', '67', '103', '104', '82', '83', '119', '120']; - return firstTestIds.includes(testTypeId); - } - - isTestTypeNotifiableAlteration(testTypeId: string): boolean { - const notifiableAlterationIds = ['38', '47', '48']; - return notifiableAlterationIds.includes(testTypeId); - } - - isTestTypeCOIF(testTypeId: string): boolean { - const coifIds = ['142', '143', '175', '176']; - return coifIds.includes(testTypeId); - } - - isTestTypeIVA(testTypeId: string): boolean { - const ivaIds = ['133', '134', '138', '139', '140', '165', '169', '167', '170', '135', '172', '173', '439', '449', - '136', '187', '126', '186', '193', '192', '195', '162', '191', '128', '188', '189', '125', '161', '158', '159', - '154', '190', '129', '196', '194', '197', '185', '420', '438', '163', '153', '184', '130', '183']; - return ivaIds.includes(testTypeId); - } + @ViewChild(BaseTestRecordComponent) private baseTestRecordComponent?: BaseTestRecordComponent; + @ViewChild(AbandonDialogComponent) abandonDialog?: AbandonDialogComponent; + + private destroy$ = new Subject(); + + canCreate$ = new BehaviorSubject(false); + testMode = TestModeEnum.Edit; + testResult$: Observable = of(undefined); + testTypeId?: string; + techRecord: V3TechRecordModel | undefined = undefined; + + constructor( + private actions$: Actions, + private errorService: GlobalErrorService, + private route: ActivatedRoute, + private router: Router, + private routerService: RouterService, + private testRecordsService: TestRecordsService, + private cdr: ChangeDetectorRef, + private resultOfTestService: ResultOfTestService, + private store: Store, + private warningService: GlobalWarningService + ) { + this.router.routeReuseStrategy.shouldReuseRoute = () => false; + } + + ngOnInit(): void { + this.testResult$ = this.testRecordsService.editingTestResult$.pipe( + tap((editingTestResult) => !editingTestResult && this.backToTechRecord()) + ); + + this.routerService + .getQueryParam$('testType') + .pipe( + take(1), + tap((testType) => !testType && this.backToTechRecord()), + filter((tt) => !!tt) + ) + .subscribe((testTypeId) => { + this.testRecordsService.contingencyTestTypeSelected(testTypeId as string); + this.testTypeId = testTypeId; + }); + + this.watchForCreateSuccess(); + + this.testRecordsService.canCreate$.pipe(take(1)).subscribe((val) => this.canCreate$.next(val)); + + this.store + .select(selectTechRecord) + .pipe(take(1)) + .subscribe((techRecord) => { + this.techRecord = techRecord; + }); + } + + ngOnDestroy(): void { + this.errorService.clearErrors(); + + this.destroy$.next(); + this.destroy$.complete(); + } + + ngAfterViewInit(): void { + this.cdr.detectChanges(); + } + + backToTechRecord(): void { + void this.router.navigate(['../../..'], { relativeTo: this.route.parent }); + } + + /** + * Merge all section form values into one testResult and trigger action to update testResult. + * @returns void + */ + async handleSave(): Promise { + if (this.isAnyFormInvalid()) { + return; + } + + this.testRecordsService.cleanTestResult(); + + const testResult = await firstValueFrom(this.testResult$); + const testResultClone = cloneDeep(testResult) as TestResultModel; + + this.testRecordsService.createTestResult(testResultClone); + } + + async handleReview() { + if (this.isAnyFormInvalid()) return; + if (this.techRecord == null) return; + + this.errorService.clearErrors(); + this.testMode = TestModeEnum.View; + + const testResult = await firstValueFrom(this.testResult$); + if ( + testResult && + this.techRecord?.techRecord_statusCode === StatusCodes.PROVISIONAL && + this.testTypeId && + this.validateUpdateStatus(testResult.testTypes[0].testResult, this.testTypeId) + ) { + const warnings: GlobalWarning[] = []; + warnings.push({ + warning: + 'This test will update the tech record to current, if the page is showing as provisional then refresh the page', + }); + this.warningService.setWarnings(warnings); + } + } + + handleCancel() { + this.testMode = TestModeEnum.Edit; + this.warningService.clearWarnings(); + } + + watchForCreateSuccess() { + this.actions$.pipe(ofType(createTestResultSuccess), takeUntil(this.destroy$)).subscribe(() => { + this.backToTechRecord(); + }); + } + + handleNewTestResult(testResult: TestResultModel) { + this.testRecordsService.updateEditingTestResult(testResult); + } + + isAnyFormInvalid() { + const errors: GlobalError[] = []; + const forms = []; + + if (this.baseTestRecordComponent?.sections) { + this.baseTestRecordComponent.sections.forEach((section) => forms.push(section.form)); + } + + if (this.baseTestRecordComponent?.defects) { + forms.push(this.baseTestRecordComponent.defects.form); + } + + if (this.testMode === TestModeEnum.Abandon && this.abandonDialog?.dynamicFormGroup) { + forms.push(this.abandonDialog.dynamicFormGroup.form); + } + + forms.forEach((form) => { + DynamicFormService.validate(form, errors); + }); + + if (errors.length) { + this.errorService.setErrors(errors); + } + + return forms.some((form) => form.invalid); + } + + abandon() { + this.resultOfTestService.toggleAbandoned(resultOfTestEnum.abandoned); + + if (this.isAnyFormInvalid()) { + return; + } + + this.testMode = TestModeEnum.Abandon; + } + + async handleAbandonAction(event: string) { + switch (event) { + case 'yes': + await this.handleSave(); + break; + case 'no': + this.abandonDialog?.dynamicFormGroup?.form.reset(); + this.resultOfTestService.toggleAbandoned(resultOfTestEnum.pass); + this.testMode = TestModeEnum.Edit; + break; + default: + console.error('Invalid action'); + } + } + + get isDeskBased() { + return this.store.pipe( + select(getTypeOfTest(this.testTypeId)), + map((typeOfTest) => typeOfTest === TypeOfTest.DESK_BASED) + ); + } + + public get TestModeEnum(): typeof TestModeEnum { + return TestModeEnum; + } + + validateUpdateStatus = (testResult: string, testTypeId: string): boolean => + (testResult === 'pass' || testResult === 'prs') && + (this.isTestTypeFirstTest(testTypeId) || + this.isTestTypeNotifiableAlteration(testTypeId) || + this.isTestTypeCOIF(testTypeId) || + this.isTestTypeIVA(testTypeId)); + + isTestTypeFirstTest(testTypeId: string): boolean { + const firstTestIds = ['41', '95', '65', '66', '67', '103', '104', '82', '83', '119', '120']; + return firstTestIds.includes(testTypeId); + } + + isTestTypeNotifiableAlteration(testTypeId: string): boolean { + const notifiableAlterationIds = ['38', '47', '48']; + return notifiableAlterationIds.includes(testTypeId); + } + + isTestTypeCOIF(testTypeId: string): boolean { + const coifIds = ['142', '143', '175', '176']; + return coifIds.includes(testTypeId); + } + + isTestTypeIVA(testTypeId: string): boolean { + const ivaIds = [ + '133', + '134', + '138', + '139', + '140', + '165', + '169', + '167', + '170', + '135', + '172', + '173', + '439', + '449', + '136', + '187', + '126', + '186', + '193', + '192', + '195', + '162', + '191', + '128', + '188', + '189', + '125', + '161', + '158', + '159', + '154', + '190', + '129', + '196', + '194', + '197', + '185', + '420', + '438', + '163', + '153', + '184', + '130', + '183', + ]; + return ivaIds.includes(testTypeId); + } } diff --git a/src/app/features/test-records/create/views/create-test-type/create-test-type.component.spec.ts b/src/app/features/test-records/create/views/create-test-type/create-test-type.component.spec.ts index b9ae1f44a2..6c41251730 100644 --- a/src/app/features/test-records/create/views/create-test-type/create-test-type.component.spec.ts +++ b/src/app/features/test-records/create/views/create-test-type/create-test-type.component.spec.ts @@ -13,85 +13,92 @@ import { TestTypeSelectComponent } from '../../../components/test-type-select/te import { CreateTestTypeComponent } from './create-test-type.component'; describe('CreateTestTypeComponent', () => { - let component: CreateTestTypeComponent; - let fixture: ComponentFixture; - let router: Router; - let route: ActivatedRoute; - let techRecordService: TechnicalRecordService; + let component: CreateTestTypeComponent; + let fixture: ComponentFixture; + let router: Router; + let route: ActivatedRoute; + let techRecordService: TechnicalRecordService; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [CreateTestTypeComponent, TestTypeSelectComponent], - imports: [HttpClientTestingModule, RouterTestingModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - { - provide: TechnicalRecordService, - }, - { provide: TestTypesService, useValue: { selectAllTestTypes$: of([]), testTypeIdChanged: () => {} } }, - ], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [CreateTestTypeComponent, TestTypeSelectComponent], + imports: [HttpClientTestingModule, RouterTestingModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + { + provide: TechnicalRecordService, + }, + { provide: TestTypesService, useValue: { selectAllTestTypes$: of([]), testTypeIdChanged: () => {} } }, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(CreateTestTypeComponent); - techRecordService = TestBed.inject(TechnicalRecordService); - component = fixture.componentInstance; - router = TestBed.inject(Router); - route = TestBed.inject(ActivatedRoute); + beforeEach(() => { + fixture = TestBed.createComponent(CreateTestTypeComponent); + techRecordService = TestBed.inject(TechnicalRecordService); + component = fixture.componentInstance; + router = TestBed.inject(Router); + route = TestBed.inject(ActivatedRoute); - jest.spyOn(window, 'alert').mockImplementation(); + jest.spyOn(window, 'alert').mockImplementation(); - fixture.detectChanges(); - }); + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it('should navigate to sibling path "amend-test-details"', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockReturnValue(Promise.resolve(true)); - component.handleSelectedTestType({ id: '1' } as TestType); - expect(navigateSpy).toHaveBeenCalledWith(['..', 'test-details'], { - queryParams: { testType: '1' }, - queryParamsHandling: 'merge', - relativeTo: route, - }); - }); + it('should navigate to sibling path "amend-test-details"', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockReturnValue(Promise.resolve(true)); + component.handleSelectedTestType({ id: '1' } as TestType); + expect(navigateSpy).toHaveBeenCalledWith(['..', 'test-details'], { + queryParams: { testType: '1' }, + queryParamsHandling: 'merge', + relativeTo: route, + }); + }); - describe('AfterContentInit', () => { - const testCases = [ - { - record: { - systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin', techRecord_recordCompleteness: 'foo', - } as V3TechRecordModel, - message: - 'Incomplete vehicle record.\n\n' - + 'This vehicle does not have enough data to be tested. ' - + 'Call Technical Support to correct this record and use SAR to test this vehicle.', - }, - { - record: { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_hiddenInVta: true, - techRecord_recordCompleteness: 'complete', - } as V3TechRecordModel, - message: 'Vehicle record is hidden in VTA.\n\nShow the vehicle record in VTA to start recording tests against it.', - }, - ]; + describe('AfterContentInit', () => { + const testCases = [ + { + record: { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_recordCompleteness: 'foo', + } as V3TechRecordModel, + message: + 'Incomplete vehicle record.\n\n' + + 'This vehicle does not have enough data to be tested. ' + + 'Call Technical Support to correct this record and use SAR to test this vehicle.', + }, + { + record: { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_hiddenInVta: true, + techRecord_recordCompleteness: 'complete', + } as V3TechRecordModel, + message: + 'Vehicle record is hidden in VTA.\n\nShow the vehicle record in VTA to start recording tests against it.', + }, + ]; - it.each(testCases)('should get the vehicle record and alert with the appropriate message', ({ record, message }) => { - jest.resetAllMocks(); - const mockTechRecordSpy = jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue(of(record)); - const alertSpy = jest.spyOn(window, 'alert').mockImplementation(); - const navigateSpy = jest.spyOn(router, 'navigate').mockReturnValue(Promise.resolve(true)); - component.ngAfterContentInit(); - expect(mockTechRecordSpy).toHaveBeenCalledTimes(1); - expect(alertSpy).toHaveBeenCalledTimes(1); - expect(alertSpy).toHaveBeenCalledWith(message); - expect(navigateSpy).toHaveBeenCalledWith(['../../..'], { relativeTo: route }); - }); - }); + it.each(testCases)( + 'should get the vehicle record and alert with the appropriate message', + ({ record, message }) => { + jest.resetAllMocks(); + const mockTechRecordSpy = jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue(of(record)); + const alertSpy = jest.spyOn(window, 'alert').mockImplementation(); + const navigateSpy = jest.spyOn(router, 'navigate').mockReturnValue(Promise.resolve(true)); + component.ngAfterContentInit(); + expect(mockTechRecordSpy).toHaveBeenCalledTimes(1); + expect(alertSpy).toHaveBeenCalledTimes(1); + expect(alertSpy).toHaveBeenCalledWith(message); + expect(navigateSpy).toHaveBeenCalledWith(['../../..'], { relativeTo: route }); + } + ); + }); }); diff --git a/src/app/features/test-records/create/views/create-test-type/create-test-type.component.ts b/src/app/features/test-records/create/views/create-test-type/create-test-type.component.ts index 7a64355d26..9928718dc3 100644 --- a/src/app/features/test-records/create/views/create-test-type/create-test-type.component.ts +++ b/src/app/features/test-records/create/views/create-test-type/create-test-type.component.ts @@ -10,49 +10,51 @@ import { contingencyTestTypeSelected } from '@store/test-records'; import { take } from 'rxjs'; @Component({ - selector: 'app-create-test-type', - templateUrl: './create-test-type.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-create-test-type', + templateUrl: './create-test-type.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class CreateTestTypeComponent implements AfterContentInit { - constructor( - private store: Store, - private router: Router, - private route: ActivatedRoute, - private technicalRecordService: TechnicalRecordService, - ) {} + constructor( + private store: Store, + private router: Router, + private route: ActivatedRoute, + private technicalRecordService: TechnicalRecordService + ) {} - ngAfterContentInit(): void { - this.technicalRecordService.techRecord$.pipe(take(1)).subscribe((techRecord) => { - if (techRecord?.techRecord_hiddenInVta) { - // eslint-disable-next-line no-alert - alert('Vehicle record is hidden in VTA.\n\nShow the vehicle record in VTA to start recording tests against it.'); + ngAfterContentInit(): void { + this.technicalRecordService.techRecord$.pipe(take(1)).subscribe((techRecord) => { + if (techRecord?.techRecord_hiddenInVta) { + // eslint-disable-next-line no-alert + alert( + 'Vehicle record is hidden in VTA.\n\nShow the vehicle record in VTA to start recording tests against it.' + ); - void this.router.navigate(['../../..'], { relativeTo: this.route }); - } else if ( - (techRecord as TechRecordType<'get'>)?.techRecord_recordCompleteness !== 'complete' - && (techRecord as TechRecordType<'get'>)?.techRecord_recordCompleteness !== 'testable' - ) { - // eslint-disable-next-line no-alert - alert( - 'Incomplete vehicle record.\n\n' - + 'This vehicle does not have enough data to be tested. ' - + 'Call Technical Support to correct this record and use SAR to test this vehicle.', - ); + void this.router.navigate(['../../..'], { relativeTo: this.route }); + } else if ( + (techRecord as TechRecordType<'get'>)?.techRecord_recordCompleteness !== 'complete' && + (techRecord as TechRecordType<'get'>)?.techRecord_recordCompleteness !== 'testable' + ) { + // eslint-disable-next-line no-alert + alert( + 'Incomplete vehicle record.\n\n' + + 'This vehicle does not have enough data to be tested. ' + + 'Call Technical Support to correct this record and use SAR to test this vehicle.' + ); - void this.router.navigate(['../../..'], { relativeTo: this.route }); - } - }); - } + void this.router.navigate(['../../..'], { relativeTo: this.route }); + } + }); + } - handleSelectedTestType(testType: TestType) { - this.store.dispatch(contingencyTestTypeSelected({ testType: testType.id })); - this.store.dispatch(clearAllSectionStates()); + handleSelectedTestType(testType: TestType) { + this.store.dispatch(contingencyTestTypeSelected({ testType: testType.id })); + this.store.dispatch(clearAllSectionStates()); - void this.router.navigate(['..', 'test-details'], { - queryParams: { testType: testType.id }, - queryParamsHandling: 'merge', - relativeTo: this.route, - }); - } + void this.router.navigate(['..', 'test-details'], { + queryParams: { testType: testType.id }, + queryParamsHandling: 'merge', + relativeTo: this.route, + }); + } } diff --git a/src/app/features/test-records/create/views/test-router-outlet/test-router-outlet.component.spec.ts b/src/app/features/test-records/create/views/test-router-outlet/test-router-outlet.component.spec.ts index 4da59bb9c3..d1d8bd0c1c 100644 --- a/src/app/features/test-records/create/views/test-router-outlet/test-router-outlet.component.spec.ts +++ b/src/app/features/test-records/create/views/test-router-outlet/test-router-outlet.component.spec.ts @@ -3,23 +3,23 @@ import { RouterTestingModule } from '@angular/router/testing'; import { TestRouterOutletComponent } from './test-router-outlet.component'; describe('TestRouterOutletComponent', () => { - let component: TestRouterOutletComponent; - let fixture: ComponentFixture; + let component: TestRouterOutletComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TestRouterOutletComponent], - imports: [RouterTestingModule], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TestRouterOutletComponent], + imports: [RouterTestingModule], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TestRouterOutletComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(TestRouterOutletComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/features/test-records/create/views/test-router-outlet/test-router-outlet.component.ts b/src/app/features/test-records/create/views/test-router-outlet/test-router-outlet.component.ts index 9427a72c5b..8ae25e17ef 100644 --- a/src/app/features/test-records/create/views/test-router-outlet/test-router-outlet.component.ts +++ b/src/app/features/test-records/create/views/test-router-outlet/test-router-outlet.component.ts @@ -1,8 +1,8 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; @Component({ - selector: 'app-test-router-outlet', - templateUrl: './test-router-outlet.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-test-router-outlet', + templateUrl: './test-router-outlet.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class TestRouterOutletComponent {} diff --git a/src/app/features/test-records/test-records.module.ts b/src/app/features/test-records/test-records.module.ts index 8cc4809ad4..248506de5e 100644 --- a/src/app/features/test-records/test-records.module.ts +++ b/src/app/features/test-records/test-records.module.ts @@ -8,8 +8,8 @@ import { TestTypeSelectComponent } from './components/test-type-select/test-type import { VehicleHeaderComponent } from './components/vehicle-header/vehicle-header.component'; @NgModule({ - declarations: [BaseTestRecordComponent, TestTypeSelectComponent, VehicleHeaderComponent], - imports: [CommonModule, SharedModule, DynamicFormsModule, RouterModule], - exports: [BaseTestRecordComponent, TestTypeSelectComponent, VehicleHeaderComponent], + declarations: [BaseTestRecordComponent, TestTypeSelectComponent, VehicleHeaderComponent], + imports: [CommonModule, SharedModule, DynamicFormsModule, RouterModule], + exports: [BaseTestRecordComponent, TestTypeSelectComponent, VehicleHeaderComponent], }) export class TestRecordsModule {} diff --git a/src/app/forms/components/approval-type/approval-type-focus-next.directive.spec.ts b/src/app/forms/components/approval-type/approval-type-focus-next.directive.spec.ts index 9b422898f5..fbefa03d7b 100644 --- a/src/app/forms/components/approval-type/approval-type-focus-next.directive.spec.ts +++ b/src/app/forms/components/approval-type/approval-type-focus-next.directive.spec.ts @@ -4,7 +4,7 @@ import { By } from '@angular/platform-browser'; import { ApprovalTypeFocusNextDirective } from './approval-type-focus-next.directive'; @Component({ - template: ` + template: ` `, @@ -12,42 +12,42 @@ import { ApprovalTypeFocusNextDirective } from './approval-type-focus-next.direc class TestComponent {} describe('ApprovalTypeFocusNext', () => { - let fixture: ComponentFixture; - let component: HTMLInputElement; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ApprovalTypeFocusNextDirective, TestComponent], - providers: [TemplateRef], - }).compileComponents(); - - fixture = TestBed.createComponent(TestComponent); - fixture.detectChanges(); - - component = fixture.debugElement.query(By.directive(ApprovalTypeFocusNextDirective)).nativeElement; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('onInput', () => { - it('should, when the value of the input equals the character limit, focus the next element', () => { - const input: HTMLInputElement = fixture.debugElement.query(By.css('#next')).nativeElement; - const focusSpy = jest.spyOn(input, 'focus'); - const getElementSpy = jest.spyOn(document, 'getElementById'); - component.value = 'abcdefghijklmnopqrst'; // 20 characters - component.dispatchEvent(new KeyboardEvent('input', { key: '.' })); - expect(focusSpy).toHaveBeenCalled(); - expect(getElementSpy).toHaveBeenCalled(); - }); - - it('should not attempt to focus any element when the input value is less than the character limit', () => { - const input: HTMLInputElement = fixture.debugElement.query(By.css('#next')).nativeElement; - const focusSpy = jest.spyOn(input, 'focus'); - component.value = 'abcdefghijklmnopqrs'; // 19 characters - component.dispatchEvent(new KeyboardEvent('input', { key: '.' })); - expect(focusSpy).not.toHaveBeenCalled(); - }); - }); + let fixture: ComponentFixture; + let component: HTMLInputElement; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ApprovalTypeFocusNextDirective, TestComponent], + providers: [TemplateRef], + }).compileComponents(); + + fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + + component = fixture.debugElement.query(By.directive(ApprovalTypeFocusNextDirective)).nativeElement; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('onInput', () => { + it('should, when the value of the input equals the character limit, focus the next element', () => { + const input: HTMLInputElement = fixture.debugElement.query(By.css('#next')).nativeElement; + const focusSpy = jest.spyOn(input, 'focus'); + const getElementSpy = jest.spyOn(document, 'getElementById'); + component.value = 'abcdefghijklmnopqrst'; // 20 characters + component.dispatchEvent(new KeyboardEvent('input', { key: '.' })); + expect(focusSpy).toHaveBeenCalled(); + expect(getElementSpy).toHaveBeenCalled(); + }); + + it('should not attempt to focus any element when the input value is less than the character limit', () => { + const input: HTMLInputElement = fixture.debugElement.query(By.css('#next')).nativeElement; + const focusSpy = jest.spyOn(input, 'focus'); + component.value = 'abcdefghijklmnopqrs'; // 19 characters + component.dispatchEvent(new KeyboardEvent('input', { key: '.' })); + expect(focusSpy).not.toHaveBeenCalled(); + }); + }); }); diff --git a/src/app/forms/components/approval-type/approval-type-focus-next.directive.ts b/src/app/forms/components/approval-type/approval-type-focus-next.directive.ts index de40b75141..1c2eac93f4 100644 --- a/src/app/forms/components/approval-type/approval-type-focus-next.directive.ts +++ b/src/app/forms/components/approval-type/approval-type-focus-next.directive.ts @@ -1,24 +1,22 @@ -import { - Directive, ElementRef, HostListener, Input, -} from '@angular/core'; +import { Directive, ElementRef, HostListener, Input } from '@angular/core'; @Directive({ - selector: '[appFocusNextApprovalType]', + selector: '[appFocusNextApprovalType]', }) export class ApprovalTypeFocusNextDirective { - @Input('appFocusNextApprovalType') nextInputId = ''; - @Input() characterLimit = 0; + @Input('appFocusNextApprovalType') nextInputId = ''; + @Input() characterLimit = 0; - constructor(private el: ElementRef) {} + constructor(private el: ElementRef) {} - @HostListener('input', ['$event']) - onInput() { - const { value } = this.el.nativeElement; - if (value.length === this.characterLimit) { - const nextInput = document.getElementById(this.nextInputId); - if (nextInput) { - nextInput.focus(); - } - } - } + @HostListener('input', ['$event']) + onInput() { + const { value } = this.el.nativeElement; + if (value.length === this.characterLimit) { + const nextInput = document.getElementById(this.nextInputId); + if (nextInput) { + nextInput.focus(); + } + } + } } diff --git a/src/app/forms/components/approval-type/approval-type.component.spec.ts b/src/app/forms/components/approval-type/approval-type.component.spec.ts index 46670d8de9..b3671be132 100644 --- a/src/app/forms/components/approval-type/approval-type.component.spec.ts +++ b/src/app/forms/components/approval-type/approval-type.component.spec.ts @@ -1,13 +1,9 @@ import { Component, ViewChild } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - FormsModule, ReactiveFormsModule, -} from '@angular/forms'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { ApprovalType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/approvalType.enum.js'; -import { - CustomFormControl, CustomFormGroup, FormNodeTypes, FormNodeWidth, -} from '@forms/services/dynamic-form.types'; +import { CustomFormControl, CustomFormGroup, FormNodeTypes, FormNodeWidth } from '@forms/services/dynamic-form.types'; import { provideMockStore } from '@ngrx/store/testing'; import { initialAppState } from '@store/index'; import { BaseControlComponent } from '../base-control/base-control.component'; @@ -16,420 +12,494 @@ import { FieldErrorMessageComponent } from '../field-error-message/field-error-m import { ApprovalTypeInputComponent } from './approval-type.component'; @Component({ - selector: 'app-host-component', - template: `
+ selector: 'app-host-component', + template: `
`, - styles: [], + styles: [], }) class HostComponent { - @ViewChild(ApprovalTypeInputComponent, { static: true }) approvalTypeComponent!: ApprovalTypeInputComponent; - - form = new CustomFormGroup({ - name: 'approvalType', - type: FormNodeTypes.GROUP, - }, { - approvalType: new CustomFormControl({ name: 'approvalType', type: FormNodeTypes.CONTROL }), - }); + @ViewChild(ApprovalTypeInputComponent, { static: true }) approvalTypeComponent!: ApprovalTypeInputComponent; + + form = new CustomFormGroup( + { + name: 'approvalType', + type: FormNodeTypes.GROUP, + }, + { + approvalType: new CustomFormControl({ name: 'approvalType', type: FormNodeTypes.CONTROL }), + } + ); } describe('ApprovalTypeComponent', () => { - let component: HostComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [BaseControlComponent, ApprovalTypeInputComponent, FieldErrorMessageComponent, FocusNextDirective, HostComponent], - imports: [FormsModule, ReactiveFormsModule], - providers: [GlobalErrorService, provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(HostComponent); - component = fixture.componentInstance; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('ngOnInit', () => { - it('should initialise all the compoennts subscriptions', () => { - const spy = jest.spyOn(component.approvalTypeComponent, 'subscribeAndPropagateChanges'); - component.approvalTypeComponent.ngOnInit(); - expect(spy).toHaveBeenCalled(); - }); - }); - - describe('ngAfterViewInit', () => { - it('should write the control value back to its control', () => { - const spy = jest.spyOn(component.approvalTypeComponent, 'valueWriteBack'); - component.approvalTypeComponent.ngAfterContentInit(); - expect(spy).toHaveBeenCalled(); - }); - }); - - describe('widths', () => { - it('should return form node widths', () => { - expect(component.approvalTypeComponent.widths).toBe(FormNodeWidth); - }); - }); - - describe('clearInput', () => { - it('should set all the approval type input number boxes to undefined, and call onChange', () => { - const spy = jest.spyOn(component.approvalTypeComponent, 'onChange'); - component.approvalTypeComponent.clearInput(); - expect(component.approvalTypeComponent.approvalTypeNumber1).toBeUndefined(); - expect(component.approvalTypeComponent.approvalTypeNumber2).toBeUndefined(); - expect(component.approvalTypeComponent.approvalTypeNumber3).toBeUndefined(); - expect(component.approvalTypeComponent.approvalTypeNumber4).toBeUndefined(); - expect(spy).toHaveBeenCalledWith(null); - }); - }); - - describe('validate', () => { - it('should, for the NTA format, call setErrors if the first approvalType number box is NOT filled in', () => { - component.approvalTypeComponent.approvalType = ApprovalType.NTA; - component.approvalTypeComponent.approvalTypeNumber1 = ''; // first number is required - component.approvalTypeComponent.validate(); - expect(component.approvalTypeComponent.errors?.error).toBe(true); - }); - - it('should, for the NTA formats, NOT call setErrors if the first approvalType number box is filled in', () => { - component.approvalTypeComponent.approvalType = ApprovalType.NTA; - component.approvalTypeComponent.approvalTypeNumber1 = 'number'; // first number is filled in, which is sufficient - component.approvalTypeComponent.validate(); - expect(component.approvalTypeComponent.errors?.error).toBeUndefined(); - }); - - it('should, for the GB_WVTA format, call setErrors if any of the first four number boxes are NOT filled in', () => { - component.approvalTypeComponent.approvalType = ApprovalType.GB_WVTA; - - // All numbers missing - component.approvalTypeComponent.approvalTypeNumber1 = ''; - component.approvalTypeComponent.validate(); - expect(component.approvalTypeComponent.errors?.error).toBe(true); - - // First number filled in, rest missing - component.approvalTypeComponent.approvalTypeNumber1 = 'number1'; - component.approvalTypeComponent.approvalTypeNumber2 = ''; - component.approvalTypeComponent.validate(); - expect(component.approvalTypeComponent.errors?.error).toBe(true); - - // First two numbers filled in, rest missing - component.approvalTypeComponent.approvalTypeNumber1 = 'number1'; - component.approvalTypeComponent.approvalTypeNumber2 = 'number2'; - component.approvalTypeComponent.approvalTypeNumber3 = ''; - component.approvalTypeComponent.validate(); - expect(component.approvalTypeComponent.errors?.error).toBe(true); - - // First three numbers filled in, rest missing - component.approvalTypeComponent.approvalTypeNumber1 = 'number1'; - component.approvalTypeComponent.approvalTypeNumber2 = 'number2'; - component.approvalTypeComponent.approvalTypeNumber3 = 'number3'; - component.approvalTypeComponent.approvalTypeNumber4 = ''; - component.approvalTypeComponent.validate(); - expect(component.approvalTypeComponent.errors?.error).toBe(true); - }); - - it('should, for the GB_WVTA format, NOT call setErrors if all of the first four number boxes are filled in', () => { - component.approvalTypeComponent.approvalType = ApprovalType.GB_WVTA; - component.approvalTypeComponent.approvalTypeNumber1 = 'number1'; - component.approvalTypeComponent.approvalTypeNumber2 = 'number2'; - component.approvalTypeComponent.approvalTypeNumber3 = 'number3'; - component.approvalTypeComponent.approvalTypeNumber4 = 'number4'; - component.approvalTypeComponent.validate(); - expect(component.approvalTypeComponent.errors?.error).toBeUndefined(); - }); - - it('should, for the NSSTA format, call setErrors if any of the first two number boxes are NOT filled in', () => { - component.approvalTypeComponent.approvalType = ApprovalType.NSSTA; - - // All numbers missing - component.approvalTypeComponent.approvalTypeNumber1 = ''; - component.approvalTypeComponent.validate(); - expect(component.approvalTypeComponent.errors?.error).toBe(true); - - // First number filled in, rest missing - component.approvalTypeComponent.approvalTypeNumber1 = 'number1'; - component.approvalTypeComponent.approvalTypeNumber2 = ''; - component.approvalTypeComponent.validate(); - expect(component.approvalTypeComponent.errors?.error).toBe(true); - }); - - it('should, for the NSSTA format, NOT call setErrors if all of the first two number boxes are filled in', () => { - component.approvalTypeComponent.approvalType = ApprovalType.NSSTA; - component.approvalTypeComponent.approvalTypeNumber1 = 'number1'; - component.approvalTypeComponent.approvalTypeNumber2 = 'number2'; - component.approvalTypeComponent.validate(); - expect(component.approvalTypeComponent.errors?.error).toBeUndefined(); - }); - }); - - describe('processApprovalTypeNumber', () => { - it('should, for NTA, return either the first approvalNumber or null if this is falsy', () => { - component.approvalTypeComponent.approvalType = ApprovalType.NTA; - const result1 = component.approvalTypeComponent.processApprovalTypeNumber('number1', undefined, undefined, undefined); - expect(result1).toBe('number1'); - - const result2 = component.approvalTypeComponent.processApprovalTypeNumber(undefined, undefined, undefined, undefined); - expect(result2).toBeNull(); - }); - - it('should, for ECTA, return either a full ECTA string if all 4 boxes are filled in, otherwise null', () => { - component.approvalTypeComponent.approvalType = ApprovalType.ECTA; - - const result1 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', 'CCCC', 'DDDDDD'); - expect(result1).toBe('eAA*BBBB/CCCC*DDDDDD'); - - const result2 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', 'CCCC', undefined); - expect(result2).toBeNull(); - - const result3 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', undefined, undefined); - expect(result3).toBeNull(); - - const result4 = component.approvalTypeComponent.processApprovalTypeNumber('AA', undefined, undefined, undefined); - expect(result4).toBeNull(); - - const result5 = component.approvalTypeComponent.processApprovalTypeNumber(undefined, undefined, undefined, undefined); - expect(result5).toBeNull(); - }); + let component: HostComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BaseControlComponent, + ApprovalTypeInputComponent, + FieldErrorMessageComponent, + FocusNextDirective, + HostComponent, + ], + imports: [FormsModule, ReactiveFormsModule], + providers: [GlobalErrorService, provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(HostComponent); + component = fixture.componentInstance; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('ngOnInit', () => { + it('should initialise all the compoennts subscriptions', () => { + const spy = jest.spyOn(component.approvalTypeComponent, 'subscribeAndPropagateChanges'); + component.approvalTypeComponent.ngOnInit(); + expect(spy).toHaveBeenCalled(); + }); + }); + + describe('ngAfterViewInit', () => { + it('should write the control value back to its control', () => { + const spy = jest.spyOn(component.approvalTypeComponent, 'valueWriteBack'); + component.approvalTypeComponent.ngAfterContentInit(); + expect(spy).toHaveBeenCalled(); + }); + }); + + describe('widths', () => { + it('should return form node widths', () => { + expect(component.approvalTypeComponent.widths).toBe(FormNodeWidth); + }); + }); + + describe('clearInput', () => { + it('should set all the approval type input number boxes to undefined, and call onChange', () => { + const spy = jest.spyOn(component.approvalTypeComponent, 'onChange'); + component.approvalTypeComponent.clearInput(); + expect(component.approvalTypeComponent.approvalTypeNumber1).toBeUndefined(); + expect(component.approvalTypeComponent.approvalTypeNumber2).toBeUndefined(); + expect(component.approvalTypeComponent.approvalTypeNumber3).toBeUndefined(); + expect(component.approvalTypeComponent.approvalTypeNumber4).toBeUndefined(); + expect(spy).toHaveBeenCalledWith(null); + }); + }); + + describe('validate', () => { + it('should, for the NTA format, call setErrors if the first approvalType number box is NOT filled in', () => { + component.approvalTypeComponent.approvalType = ApprovalType.NTA; + component.approvalTypeComponent.approvalTypeNumber1 = ''; // first number is required + component.approvalTypeComponent.validate(); + expect(component.approvalTypeComponent.errors?.error).toBe(true); + }); + + it('should, for the NTA formats, NOT call setErrors if the first approvalType number box is filled in', () => { + component.approvalTypeComponent.approvalType = ApprovalType.NTA; + component.approvalTypeComponent.approvalTypeNumber1 = 'number'; // first number is filled in, which is sufficient + component.approvalTypeComponent.validate(); + expect(component.approvalTypeComponent.errors?.error).toBeUndefined(); + }); + + it('should, for the GB_WVTA format, call setErrors if any of the first four number boxes are NOT filled in', () => { + component.approvalTypeComponent.approvalType = ApprovalType.GB_WVTA; + + // All numbers missing + component.approvalTypeComponent.approvalTypeNumber1 = ''; + component.approvalTypeComponent.validate(); + expect(component.approvalTypeComponent.errors?.error).toBe(true); + + // First number filled in, rest missing + component.approvalTypeComponent.approvalTypeNumber1 = 'number1'; + component.approvalTypeComponent.approvalTypeNumber2 = ''; + component.approvalTypeComponent.validate(); + expect(component.approvalTypeComponent.errors?.error).toBe(true); + + // First two numbers filled in, rest missing + component.approvalTypeComponent.approvalTypeNumber1 = 'number1'; + component.approvalTypeComponent.approvalTypeNumber2 = 'number2'; + component.approvalTypeComponent.approvalTypeNumber3 = ''; + component.approvalTypeComponent.validate(); + expect(component.approvalTypeComponent.errors?.error).toBe(true); + + // First three numbers filled in, rest missing + component.approvalTypeComponent.approvalTypeNumber1 = 'number1'; + component.approvalTypeComponent.approvalTypeNumber2 = 'number2'; + component.approvalTypeComponent.approvalTypeNumber3 = 'number3'; + component.approvalTypeComponent.approvalTypeNumber4 = ''; + component.approvalTypeComponent.validate(); + expect(component.approvalTypeComponent.errors?.error).toBe(true); + }); + + it('should, for the GB_WVTA format, NOT call setErrors if all of the first four number boxes are filled in', () => { + component.approvalTypeComponent.approvalType = ApprovalType.GB_WVTA; + component.approvalTypeComponent.approvalTypeNumber1 = 'number1'; + component.approvalTypeComponent.approvalTypeNumber2 = 'number2'; + component.approvalTypeComponent.approvalTypeNumber3 = 'number3'; + component.approvalTypeComponent.approvalTypeNumber4 = 'number4'; + component.approvalTypeComponent.validate(); + expect(component.approvalTypeComponent.errors?.error).toBeUndefined(); + }); + + it('should, for the NSSTA format, call setErrors if any of the first two number boxes are NOT filled in', () => { + component.approvalTypeComponent.approvalType = ApprovalType.NSSTA; + + // All numbers missing + component.approvalTypeComponent.approvalTypeNumber1 = ''; + component.approvalTypeComponent.validate(); + expect(component.approvalTypeComponent.errors?.error).toBe(true); + + // First number filled in, rest missing + component.approvalTypeComponent.approvalTypeNumber1 = 'number1'; + component.approvalTypeComponent.approvalTypeNumber2 = ''; + component.approvalTypeComponent.validate(); + expect(component.approvalTypeComponent.errors?.error).toBe(true); + }); + + it('should, for the NSSTA format, NOT call setErrors if all of the first two number boxes are filled in', () => { + component.approvalTypeComponent.approvalType = ApprovalType.NSSTA; + component.approvalTypeComponent.approvalTypeNumber1 = 'number1'; + component.approvalTypeComponent.approvalTypeNumber2 = 'number2'; + component.approvalTypeComponent.validate(); + expect(component.approvalTypeComponent.errors?.error).toBeUndefined(); + }); + }); + + describe('processApprovalTypeNumber', () => { + it('should, for NTA, return either the first approvalNumber or null if this is falsy', () => { + component.approvalTypeComponent.approvalType = ApprovalType.NTA; + const result1 = component.approvalTypeComponent.processApprovalTypeNumber( + 'number1', + undefined, + undefined, + undefined + ); + expect(result1).toBe('number1'); + + const result2 = component.approvalTypeComponent.processApprovalTypeNumber( + undefined, + undefined, + undefined, + undefined + ); + expect(result2).toBeNull(); + }); + + it('should, for ECTA, return either a full ECTA string if all 4 boxes are filled in, otherwise null', () => { + component.approvalTypeComponent.approvalType = ApprovalType.ECTA; + + const result1 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', 'CCCC', 'DDDDDD'); + expect(result1).toBe('eAA*BBBB/CCCC*DDDDDD'); + + const result2 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', 'CCCC', undefined); + expect(result2).toBeNull(); + + const result3 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', undefined, undefined); + expect(result3).toBeNull(); + + const result4 = component.approvalTypeComponent.processApprovalTypeNumber('AA', undefined, undefined, undefined); + expect(result4).toBeNull(); + + const result5 = component.approvalTypeComponent.processApprovalTypeNumber( + undefined, + undefined, + undefined, + undefined + ); + expect(result5).toBeNull(); + }); + + it('should, for IVA, return either the first approvalNumber or null if this is falsy', () => { + component.approvalTypeComponent.approvalType = ApprovalType.IVA; + const result1 = component.approvalTypeComponent.processApprovalTypeNumber( + 'number1', + undefined, + undefined, + undefined + ); + expect(result1).toBe('number1'); + + const result2 = component.approvalTypeComponent.processApprovalTypeNumber( + undefined, + undefined, + undefined, + undefined + ); + expect(result2).toBeNull(); + }); + + it('should, for NSSTA, return either a full NSSTA string if all 2 boxes are filled in, otherwise null', () => { + component.approvalTypeComponent.approvalType = ApprovalType.NSSTA; + + const result3 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBBBB', undefined, undefined); + expect(result3).toBe('eAA*NKS*BBBBBB'); + + const result4 = component.approvalTypeComponent.processApprovalTypeNumber('AA', undefined, undefined, undefined); + expect(result4).toBeNull(); + + const result5 = component.approvalTypeComponent.processApprovalTypeNumber( + undefined, + undefined, + undefined, + undefined + ); + expect(result5).toBeNull(); + }); + + it('should, for ECSSTA, return either a full ECSSTA string if all 4 boxes are filled in, otherwise null', () => { + component.approvalTypeComponent.approvalType = ApprovalType.ECSSTA; + + const result1 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BB', 'CCCC', 'DDDDDD'); + expect(result1).toBe('eAA*KSBB/CCCC*DDDDDD'); + + const result2 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BB', 'CCCC', undefined); + expect(result2).toBeNull(); + + const result3 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BB', undefined, undefined); + expect(result3).toBeNull(); + + const result4 = component.approvalTypeComponent.processApprovalTypeNumber('AA', undefined, undefined, undefined); + expect(result4).toBeNull(); + + const result5 = component.approvalTypeComponent.processApprovalTypeNumber( + undefined, + undefined, + undefined, + undefined + ); + expect(result5).toBeNull(); + }); + + it('should, for GB_WVTA, return either a full GB_WVTA string if all 4 boxes are filled in, otherwise null', () => { + component.approvalTypeComponent.approvalType = ApprovalType.GB_WVTA; + + const result1 = component.approvalTypeComponent.processApprovalTypeNumber('AAA', 'BBBB', 'CCCC', 'DDDDDDD'); + expect(result1).toBe('AAA*BBBB/CCCC*DDDDDDD'); + + const result2 = component.approvalTypeComponent.processApprovalTypeNumber('AAA', 'BBBB', 'CCCC', undefined); + expect(result2).toBeNull(); + + const result3 = component.approvalTypeComponent.processApprovalTypeNumber('AAA', 'BBBB', undefined, undefined); + expect(result3).toBeNull(); + + const result4 = component.approvalTypeComponent.processApprovalTypeNumber('AAA', undefined, undefined, undefined); + expect(result4).toBeNull(); + + const result5 = component.approvalTypeComponent.processApprovalTypeNumber( + undefined, + undefined, + undefined, + undefined + ); + expect(result5).toBeNull(); + }); + + it('should, for UKNI_WVTA, return either a full UKNI_WVTA string if all 4 boxes are filled in, otherwise null', () => { + component.approvalTypeComponent.approvalType = ApprovalType.UKNI_WVTA; + + const result1 = component.approvalTypeComponent.processApprovalTypeNumber('A', 'BBBB', 'CCCC', 'DDDDDD'); + expect(result1).toBe('A11*BBBB/CCCC*DDDDDD'); + + const result2 = component.approvalTypeComponent.processApprovalTypeNumber('A', 'BBBB', 'CCCC', undefined); + expect(result2).toBeNull(); + + const result3 = component.approvalTypeComponent.processApprovalTypeNumber('A', 'BBBB', undefined, undefined); + expect(result3).toBeNull(); + + const result4 = component.approvalTypeComponent.processApprovalTypeNumber('A', undefined, undefined, undefined); + expect(result4).toBeNull(); + + const result5 = component.approvalTypeComponent.processApprovalTypeNumber( + undefined, + undefined, + undefined, + undefined + ); + expect(result5).toBeNull(); + }); + + it('should, for EU_WVTA_PRE_23, return either a full EU_WVTA_PRE_23 string if all 4 boxes are filled in, otherwise null', () => { + component.approvalTypeComponent.approvalType = ApprovalType.EU_WVTA_PRE_23; + + const result1 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', 'CCCC', 'DDDDDD'); + expect(result1).toBe('eAA*BBBB/CCCC*DDDDDD'); - it('should, for IVA, return either the first approvalNumber or null if this is falsy', () => { - component.approvalTypeComponent.approvalType = ApprovalType.IVA; - const result1 = component.approvalTypeComponent.processApprovalTypeNumber('number1', undefined, undefined, undefined); - expect(result1).toBe('number1'); + const result2 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', 'CCCC', undefined); + expect(result2).toBeNull(); - const result2 = component.approvalTypeComponent.processApprovalTypeNumber(undefined, undefined, undefined, undefined); - expect(result2).toBeNull(); - }); + const result3 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', undefined, undefined); + expect(result3).toBeNull(); - it('should, for NSSTA, return either a full NSSTA string if all 2 boxes are filled in, otherwise null', () => { - component.approvalTypeComponent.approvalType = ApprovalType.NSSTA; + const result4 = component.approvalTypeComponent.processApprovalTypeNumber('AA', undefined, undefined, undefined); + expect(result4).toBeNull(); - const result3 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBBBB', undefined, undefined); - expect(result3).toBe('eAA*NKS*BBBBBB'); + const result5 = component.approvalTypeComponent.processApprovalTypeNumber( + undefined, + undefined, + undefined, + undefined + ); + expect(result5).toBeNull(); + }); - const result4 = component.approvalTypeComponent.processApprovalTypeNumber('AA', undefined, undefined, undefined); - expect(result4).toBeNull(); + it('should, for EU_WVTA_23_ON, return either a full EU_WVTA_23_ON string if all 4 boxes are filled in, otherwise null', () => { + component.approvalTypeComponent.approvalType = ApprovalType.EU_WVTA_23_ON; - const result5 = component.approvalTypeComponent.processApprovalTypeNumber(undefined, undefined, undefined, undefined); - expect(result5).toBeNull(); - }); + const result1 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', 'CCCC', 'DDDDDD'); + expect(result1).toBe('eAA*BBBB/CCCC*DDDDDD'); - it('should, for ECSSTA, return either a full ECSSTA string if all 4 boxes are filled in, otherwise null', () => { - component.approvalTypeComponent.approvalType = ApprovalType.ECSSTA; + const result2 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', 'CCCC', undefined); + expect(result2).toBeNull(); - const result1 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BB', 'CCCC', 'DDDDDD'); - expect(result1).toBe('eAA*KSBB/CCCC*DDDDDD'); + const result3 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', undefined, undefined); + expect(result3).toBeNull(); - const result2 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BB', 'CCCC', undefined); - expect(result2).toBeNull(); + const result4 = component.approvalTypeComponent.processApprovalTypeNumber('AA', undefined, undefined, undefined); + expect(result4).toBeNull(); - const result3 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BB', undefined, undefined); - expect(result3).toBeNull(); + const result5 = component.approvalTypeComponent.processApprovalTypeNumber( + undefined, + undefined, + undefined, + undefined + ); + expect(result5).toBeNull(); + }); - const result4 = component.approvalTypeComponent.processApprovalTypeNumber('AA', undefined, undefined, undefined); - expect(result4).toBeNull(); + it('should, for QNIG, return either a full QNIG string if all 4 boxes are filled in, otherwise null', () => { + component.approvalTypeComponent.approvalType = ApprovalType.QNIG; - const result5 = component.approvalTypeComponent.processApprovalTypeNumber(undefined, undefined, undefined, undefined); - expect(result5).toBeNull(); - }); + const result1 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', 'CCCC', 'DDDDDD'); + expect(result1).toBe('eAA*BBBB/CCCC*DDDDDD'); - it('should, for GB_WVTA, return either a full GB_WVTA string if all 4 boxes are filled in, otherwise null', () => { - component.approvalTypeComponent.approvalType = ApprovalType.GB_WVTA; + const result2 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', 'CCCC', undefined); + expect(result2).toBeNull(); - const result1 = component.approvalTypeComponent.processApprovalTypeNumber('AAA', 'BBBB', 'CCCC', 'DDDDDDD'); - expect(result1).toBe('AAA*BBBB/CCCC*DDDDDDD'); + const result3 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', undefined, undefined); + expect(result3).toBeNull(); - const result2 = component.approvalTypeComponent.processApprovalTypeNumber('AAA', 'BBBB', 'CCCC', undefined); - expect(result2).toBeNull(); - - const result3 = component.approvalTypeComponent.processApprovalTypeNumber('AAA', 'BBBB', undefined, undefined); - expect(result3).toBeNull(); - - const result4 = component.approvalTypeComponent.processApprovalTypeNumber('AAA', undefined, undefined, undefined); - expect(result4).toBeNull(); - - const result5 = component.approvalTypeComponent.processApprovalTypeNumber(undefined, undefined, undefined, undefined); - expect(result5).toBeNull(); - }); - - it('should, for UKNI_WVTA, return either a full UKNI_WVTA string if all 4 boxes are filled in, otherwise null', () => { - component.approvalTypeComponent.approvalType = ApprovalType.UKNI_WVTA; - - const result1 = component.approvalTypeComponent.processApprovalTypeNumber('A', 'BBBB', 'CCCC', 'DDDDDD'); - expect(result1).toBe('A11*BBBB/CCCC*DDDDDD'); - - const result2 = component.approvalTypeComponent.processApprovalTypeNumber('A', 'BBBB', 'CCCC', undefined); - expect(result2).toBeNull(); - - const result3 = component.approvalTypeComponent.processApprovalTypeNumber('A', 'BBBB', undefined, undefined); - expect(result3).toBeNull(); - - const result4 = component.approvalTypeComponent.processApprovalTypeNumber('A', undefined, undefined, undefined); - expect(result4).toBeNull(); - - const result5 = component.approvalTypeComponent.processApprovalTypeNumber(undefined, undefined, undefined, undefined); - expect(result5).toBeNull(); - }); - - it('should, for EU_WVTA_PRE_23, return either a full EU_WVTA_PRE_23 string if all 4 boxes are filled in, otherwise null', () => { - component.approvalTypeComponent.approvalType = ApprovalType.EU_WVTA_PRE_23; - - const result1 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', 'CCCC', 'DDDDDD'); - expect(result1).toBe('eAA*BBBB/CCCC*DDDDDD'); - - const result2 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', 'CCCC', undefined); - expect(result2).toBeNull(); - - const result3 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', undefined, undefined); - expect(result3).toBeNull(); - - const result4 = component.approvalTypeComponent.processApprovalTypeNumber('AA', undefined, undefined, undefined); - expect(result4).toBeNull(); - - const result5 = component.approvalTypeComponent.processApprovalTypeNumber(undefined, undefined, undefined, undefined); - expect(result5).toBeNull(); - }); - - it('should, for EU_WVTA_23_ON, return either a full EU_WVTA_23_ON string if all 4 boxes are filled in, otherwise null', () => { - component.approvalTypeComponent.approvalType = ApprovalType.EU_WVTA_23_ON; - - const result1 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', 'CCCC', 'DDDDDD'); - expect(result1).toBe('eAA*BBBB/CCCC*DDDDDD'); - - const result2 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', 'CCCC', undefined); - expect(result2).toBeNull(); - - const result3 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', undefined, undefined); - expect(result3).toBeNull(); - - const result4 = component.approvalTypeComponent.processApprovalTypeNumber('AA', undefined, undefined, undefined); - expect(result4).toBeNull(); - - const result5 = component.approvalTypeComponent.processApprovalTypeNumber(undefined, undefined, undefined, undefined); - expect(result5).toBeNull(); - }); - - it('should, for QNIG, return either a full QNIG string if all 4 boxes are filled in, otherwise null', () => { - component.approvalTypeComponent.approvalType = ApprovalType.QNIG; - - const result1 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', 'CCCC', 'DDDDDD'); - expect(result1).toBe('eAA*BBBB/CCCC*DDDDDD'); - - const result2 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', 'CCCC', undefined); - expect(result2).toBeNull(); - - const result3 = component.approvalTypeComponent.processApprovalTypeNumber('AA', 'BBBB', undefined, undefined); - expect(result3).toBeNull(); - - const result4 = component.approvalTypeComponent.processApprovalTypeNumber('AA', undefined, undefined, undefined); - expect(result4).toBeNull(); - - const result5 = component.approvalTypeComponent.processApprovalTypeNumber(undefined, undefined, undefined, undefined); - expect(result5).toBeNull(); - }); - - it('should, for PROV_GB_WVTA, return either a full PROV_GB_WVTA string if all 4 boxes are filled in, otherwise null', () => { - component.approvalTypeComponent.approvalType = ApprovalType.PROV_GB_WVTA; - - const result1 = component.approvalTypeComponent.processApprovalTypeNumber('AAA', 'BBBB', 'CCCC', 'DDDDDD'); - expect(result1).toBe('AAA*BBBB/CCCC*DDDDDD'); - - const result2 = component.approvalTypeComponent.processApprovalTypeNumber('AAA', 'BBBB', 'CCCC', undefined); - expect(result2).toBeNull(); - - const result3 = component.approvalTypeComponent.processApprovalTypeNumber('AAA', 'BBBB', undefined, undefined); - expect(result3).toBeNull(); - - const result4 = component.approvalTypeComponent.processApprovalTypeNumber('AAA', undefined, undefined, undefined); - expect(result4).toBeNull(); - - const result5 = component.approvalTypeComponent.processApprovalTypeNumber(undefined, undefined, undefined, undefined); - expect(result5).toBeNull(); - }); - - it('should, for SMALL_SERIES_NKSXX, return either a full SMALL_SERIES_NKSXX string if all 4 boxes are filled in, otherwise null', () => { - component.approvalTypeComponent.approvalType = ApprovalType.SMALL_SERIES_NKSXX; - - const result2 = component.approvalTypeComponent.processApprovalTypeNumber('XX', 'AA', 'BBBB', 'CCCCCC'); - expect(result2).toBe('XX11*NKSAA/BBBB*CCCCCC'); - - const result4 = component.approvalTypeComponent.processApprovalTypeNumber('XX', 'AA', undefined, undefined); - expect(result4).toBeNull(); - - const result5 = component.approvalTypeComponent.processApprovalTypeNumber('XX', undefined, undefined, undefined); - expect(result5).toBeNull(); - }); - - it('should, for SMALL_SERIES_NKS, return either a full SMALL_SERIES_NKS string if all 4 boxes are filled in, otherwise null', () => { - component.approvalTypeComponent.approvalType = ApprovalType.SMALL_SERIES_NKS; - - const result2 = component.approvalTypeComponent.processApprovalTypeNumber('XX', 'AA', 'BBBB', 'CCCCCC'); - expect(result2).toBe('XX11*NKS*AA'); - - const result4 = component.approvalTypeComponent.processApprovalTypeNumber('XX', 'AA', undefined, undefined); - expect(result4).toBe('XX11*NKS*AA'); - - const result5 = component.approvalTypeComponent.processApprovalTypeNumber('XX', undefined, undefined, undefined); - expect(result5).toBeNull(); - }); - - it('should, for IVA_VCA, return either a full IVA_VCA string if all 4 boxes are filled in, otherwise null', () => { - component.approvalTypeComponent.approvalType = ApprovalType.IVA_VCA; - - const result2 = component.approvalTypeComponent.processApprovalTypeNumber('XX', 'AA', 'BBBB', 'CCCCCC'); - expect(result2).toBe('n11*NIVXX/AA*BBBB'); - - const result5 = component.approvalTypeComponent.processApprovalTypeNumber('XX', undefined, undefined, undefined); - expect(result5).toBeNull(); - }); - }); - - describe('getId', () => { - it('should format the id of the control given its meta name', () => { - component.approvalTypeComponent.approvalType = ApprovalType.NSSTA; - - const result = component.approvalTypeComponent.getId('name'); - expect(result).toBe('name-approvalTypeNumber1-NSSTA'); - }); - }); - - describe('set approval type numbers', () => { - // the following are added for test coverage as these methods just next subjects - it('should return void for onTechRecord_approvalTypeNumber1_Change', () => { - const result = component.approvalTypeComponent.onTechRecord_approvalTypeNumber1_Change('number'); - expect(result).toBeUndefined(); - }); - - it('should return void for onTechRecord_approvalTypeNumber2_Change', () => { - const result = component.approvalTypeComponent.onTechRecord_approvalTypeNumber2_Change('number'); - expect(result).toBeUndefined(); - }); - - it('should return void for onTechRecord_approvalTypeNumber3_Change', () => { - const result = component.approvalTypeComponent.onTechRecord_approvalTypeNumber3_Change('number'); - expect(result).toBeUndefined(); - }); - - it('should return void for onTechRecord_approvalTypeNumber4_Change', () => { - const result = component.approvalTypeComponent.onTechRecord_approvalTypeNumber4_Change('number'); - expect(result).toBeUndefined(); - }); - }); - - describe('valueWriteBack', () => { - it('should return if a falsy value is passed', () => { - const result = component.approvalTypeComponent.valueWriteBack(null); - expect(result).toBeUndefined(); - }); - - it('should return if the component is missing an approvalType', () => { - component.approvalTypeComponent.approvalType = undefined; - const result = component.approvalTypeComponent.valueWriteBack(null); - expect(result).toBeUndefined(); - }); - }); + const result4 = component.approvalTypeComponent.processApprovalTypeNumber('AA', undefined, undefined, undefined); + expect(result4).toBeNull(); + + const result5 = component.approvalTypeComponent.processApprovalTypeNumber( + undefined, + undefined, + undefined, + undefined + ); + expect(result5).toBeNull(); + }); + + it('should, for PROV_GB_WVTA, return either a full PROV_GB_WVTA string if all 4 boxes are filled in, otherwise null', () => { + component.approvalTypeComponent.approvalType = ApprovalType.PROV_GB_WVTA; + + const result1 = component.approvalTypeComponent.processApprovalTypeNumber('AAA', 'BBBB', 'CCCC', 'DDDDDD'); + expect(result1).toBe('AAA*BBBB/CCCC*DDDDDD'); + + const result2 = component.approvalTypeComponent.processApprovalTypeNumber('AAA', 'BBBB', 'CCCC', undefined); + expect(result2).toBeNull(); + + const result3 = component.approvalTypeComponent.processApprovalTypeNumber('AAA', 'BBBB', undefined, undefined); + expect(result3).toBeNull(); + + const result4 = component.approvalTypeComponent.processApprovalTypeNumber('AAA', undefined, undefined, undefined); + expect(result4).toBeNull(); + + const result5 = component.approvalTypeComponent.processApprovalTypeNumber( + undefined, + undefined, + undefined, + undefined + ); + expect(result5).toBeNull(); + }); + + it('should, for SMALL_SERIES_NKSXX, return either a full SMALL_SERIES_NKSXX string if all 4 boxes are filled in, otherwise null', () => { + component.approvalTypeComponent.approvalType = ApprovalType.SMALL_SERIES_NKSXX; + + const result2 = component.approvalTypeComponent.processApprovalTypeNumber('XX', 'AA', 'BBBB', 'CCCCCC'); + expect(result2).toBe('XX11*NKSAA/BBBB*CCCCCC'); + + const result4 = component.approvalTypeComponent.processApprovalTypeNumber('XX', 'AA', undefined, undefined); + expect(result4).toBeNull(); + + const result5 = component.approvalTypeComponent.processApprovalTypeNumber('XX', undefined, undefined, undefined); + expect(result5).toBeNull(); + }); + + it('should, for SMALL_SERIES_NKS, return either a full SMALL_SERIES_NKS string if all 4 boxes are filled in, otherwise null', () => { + component.approvalTypeComponent.approvalType = ApprovalType.SMALL_SERIES_NKS; + + const result2 = component.approvalTypeComponent.processApprovalTypeNumber('XX', 'AA', 'BBBB', 'CCCCCC'); + expect(result2).toBe('XX11*NKS*AA'); + + const result4 = component.approvalTypeComponent.processApprovalTypeNumber('XX', 'AA', undefined, undefined); + expect(result4).toBe('XX11*NKS*AA'); + + const result5 = component.approvalTypeComponent.processApprovalTypeNumber('XX', undefined, undefined, undefined); + expect(result5).toBeNull(); + }); + + it('should, for IVA_VCA, return either a full IVA_VCA string if all 4 boxes are filled in, otherwise null', () => { + component.approvalTypeComponent.approvalType = ApprovalType.IVA_VCA; + + const result2 = component.approvalTypeComponent.processApprovalTypeNumber('XX', 'AA', 'BBBB', 'CCCCCC'); + expect(result2).toBe('n11*NIVXX/AA*BBBB'); + + const result5 = component.approvalTypeComponent.processApprovalTypeNumber('XX', undefined, undefined, undefined); + expect(result5).toBeNull(); + }); + }); + + describe('getId', () => { + it('should format the id of the control given its meta name', () => { + component.approvalTypeComponent.approvalType = ApprovalType.NSSTA; + + const result = component.approvalTypeComponent.getId('name'); + expect(result).toBe('name-approvalTypeNumber1-NSSTA'); + }); + }); + + describe('set approval type numbers', () => { + // the following are added for test coverage as these methods just next subjects + it('should return void for onTechRecord_approvalTypeNumber1_Change', () => { + const result = component.approvalTypeComponent.onTechRecord_approvalTypeNumber1_Change('number'); + expect(result).toBeUndefined(); + }); + + it('should return void for onTechRecord_approvalTypeNumber2_Change', () => { + const result = component.approvalTypeComponent.onTechRecord_approvalTypeNumber2_Change('number'); + expect(result).toBeUndefined(); + }); + + it('should return void for onTechRecord_approvalTypeNumber3_Change', () => { + const result = component.approvalTypeComponent.onTechRecord_approvalTypeNumber3_Change('number'); + expect(result).toBeUndefined(); + }); + + it('should return void for onTechRecord_approvalTypeNumber4_Change', () => { + const result = component.approvalTypeComponent.onTechRecord_approvalTypeNumber4_Change('number'); + expect(result).toBeUndefined(); + }); + }); + + describe('valueWriteBack', () => { + it('should return if a falsy value is passed', () => { + const result = component.approvalTypeComponent.valueWriteBack(null); + expect(result).toBeUndefined(); + }); + + it('should return if the component is missing an approvalType', () => { + component.approvalTypeComponent.approvalType = undefined; + const result = component.approvalTypeComponent.valueWriteBack(null); + expect(result).toBeUndefined(); + }); + }); }); diff --git a/src/app/forms/components/approval-type/approval-type.component.ts b/src/app/forms/components/approval-type/approval-type.component.ts index 43a8e258c9..4d4ae1a8be 100644 --- a/src/app/forms/components/approval-type/approval-type.component.ts +++ b/src/app/forms/components/approval-type/approval-type.component.ts @@ -1,454 +1,486 @@ import { - AfterContentInit, ChangeDetectorRef, Component, Injector, Input, OnChanges, OnDestroy, OnInit, + AfterContentInit, + ChangeDetectorRef, + Component, + Injector, + Input, + OnChanges, + OnDestroy, + OnInit, } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { ApprovalType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/approvalType.enum.js'; import { FormNodeWidth } from '@forms/services/dynamic-form.types'; -import { - BehaviorSubject, Observable, Subscription, combineLatest, -} from 'rxjs'; +import { BehaviorSubject, Observable, Subscription, combineLatest } from 'rxjs'; import { BaseControlComponent } from '../base-control/base-control.component'; const patterns: Record = { - NTA: /^(.+)$/i, // 25 - 'IVA - DVSA/NI': /^(.+)$/i, // 25 - IVA: /^(.+)$/i, // 25 - ECTA: /^e(.{2})\*(.{4})\/(.{4})\*(.{6})$/i, // 20 - NSSTA: /^e(.{2})\*NKS\*(.{6})$/i, // 14 - ECSSTA: /^e(.{2})\*KS(.{2})\/(.{4})\*(.{6})$/i, // 18 - 'GB WVTA': /^(.{3})\*(.{4})\/(.{4})\*(.{7})$/i, // 21 - 'UKNI WVTA': /^(.{1})11\*(.{4})\/(.{4})\*(.{6})$/i, // 20 - 'EU WVTA Pre 23': /^e(.{2})\*(.{4})\/(.{4})\*(.{6})$/i, // 20 - 'EU WVTA 23 on': /^e(.{2})\*(.{4})\/(.{4})\*(.{6})$/i, // 20 - QNIG: /^e(.{2})\*(.{4})\/(.{4})\*(.{6})$/i, // 20 - 'Prov.GB WVTA': /^(.{3})\*(.{4})\/(.{4})\*(.{6})$/i, // 20 - 'Small series NKSXX': /^(.?)11\*NKS(.{0,2})\/(.{0,4})\*(.{0,6})$/i, // 25 - 'Small series NKS': /^(.?)11\*NKS\*(.{0,6})$/i, // 23 - 'IVA - VCA': /^n11\*NIV(.{2})\/(.{4})\*(.{6})$/i, // 19 + NTA: /^(.+)$/i, // 25 + 'IVA - DVSA/NI': /^(.+)$/i, // 25 + IVA: /^(.+)$/i, // 25 + ECTA: /^e(.{2})\*(.{4})\/(.{4})\*(.{6})$/i, // 20 + NSSTA: /^e(.{2})\*NKS\*(.{6})$/i, // 14 + ECSSTA: /^e(.{2})\*KS(.{2})\/(.{4})\*(.{6})$/i, // 18 + 'GB WVTA': /^(.{3})\*(.{4})\/(.{4})\*(.{7})$/i, // 21 + 'UKNI WVTA': /^(.{1})11\*(.{4})\/(.{4})\*(.{6})$/i, // 20 + 'EU WVTA Pre 23': /^e(.{2})\*(.{4})\/(.{4})\*(.{6})$/i, // 20 + 'EU WVTA 23 on': /^e(.{2})\*(.{4})\/(.{4})\*(.{6})$/i, // 20 + QNIG: /^e(.{2})\*(.{4})\/(.{4})\*(.{6})$/i, // 20 + 'Prov.GB WVTA': /^(.{3})\*(.{4})\/(.{4})\*(.{6})$/i, // 20 + 'Small series NKSXX': /^(.?)11\*NKS(.{0,2})\/(.{0,4})\*(.{0,6})$/i, // 25 + 'Small series NKS': /^(.?)11\*NKS\*(.{0,6})$/i, // 23 + 'IVA - VCA': /^n11\*NIV(.{2})\/(.{4})\*(.{6})$/i, // 19 }; const patternsPartialMatch: Record = { - NTA: /^(.+)$/i, - 'IVA - DVSA/NI': /^(.+)$/i, - IVA: /^(.+)$/i, - ECTA: /^e(.{0,2})\*(.{0,4})\/(.{0,4})\*(.{0,6})$/i, - NSSTA: /^e(.{0,2})\*NKS\*(.{0,6})$/i, - ECSSTA: /^e(.{0,2})\*KS(.{0,2})\/(.{0,4})\*(.{0,6})$/i, - 'GB WVTA': /^(.{0,3})\*(.{0,4})\/(.{0,4})\*(.{0,7})$/i, - 'UKNI WVTA': /^(.?)11\*(.{0,4})\/(.{0,4})\*(.{0,6})$/i, - 'EU WVTA Pre 23': /^e(.{0,2})\*(.{0,4})\/(.{0,4})\*(.{0,6})$/i, - 'EU WVTA 23 on': /^e(.{0,2})\*(.{0,4})\/(.{0,4})\*(.{0,6})$/i, - QNIG: /^e(.{0,2})\*(.{0,4})\/(.{0,4})\*(.{0,6})$/i, - 'Prov.GB WVTA': /^(.{0,3})\*(.{0,4})\/(.{0,4})\*(.{0,6})$/i, - 'Small series NKSXX': /^(.?)11\*NKS(.{0,2})\/(.{0,4})\*(.{0,6})$/i, // 25 - 'Small series NKS': /^(.?)11\*NKS\*(.{0,6})$/i, // 23 - 'IVA - VCA': /^n11\*NIV(.{0,2})\/(.{0,4})\*(.{0,6})$/i, + NTA: /^(.+)$/i, + 'IVA - DVSA/NI': /^(.+)$/i, + IVA: /^(.+)$/i, + ECTA: /^e(.{0,2})\*(.{0,4})\/(.{0,4})\*(.{0,6})$/i, + NSSTA: /^e(.{0,2})\*NKS\*(.{0,6})$/i, + ECSSTA: /^e(.{0,2})\*KS(.{0,2})\/(.{0,4})\*(.{0,6})$/i, + 'GB WVTA': /^(.{0,3})\*(.{0,4})\/(.{0,4})\*(.{0,7})$/i, + 'UKNI WVTA': /^(.?)11\*(.{0,4})\/(.{0,4})\*(.{0,6})$/i, + 'EU WVTA Pre 23': /^e(.{0,2})\*(.{0,4})\/(.{0,4})\*(.{0,6})$/i, + 'EU WVTA 23 on': /^e(.{0,2})\*(.{0,4})\/(.{0,4})\*(.{0,6})$/i, + QNIG: /^e(.{0,2})\*(.{0,4})\/(.{0,4})\*(.{0,6})$/i, + 'Prov.GB WVTA': /^(.{0,3})\*(.{0,4})\/(.{0,4})\*(.{0,6})$/i, + 'Small series NKSXX': /^(.?)11\*NKS(.{0,2})\/(.{0,4})\*(.{0,6})$/i, // 25 + 'Small series NKS': /^(.?)11\*NKS\*(.{0,6})$/i, // 23 + 'IVA - VCA': /^n11\*NIV(.{0,2})\/(.{0,4})\*(.{0,6})$/i, }; const patternsGenericPartialMatch: Record = { - NTA: /^(.+)$/i, - 'IVA - DVSA/NI': /^(.+)$/i, - IVA: /^(.+)$/i, - ECTA: /^(.{0,2})(.{0,4})(.{0,4})(.{0,6})$/i, - NSSTA: /^(.{0,2})(.{0,6})$/i, - ECSSTA: /^(.{0,2})(.{0,2})(.{0,4})(.{0,6})$/i, - 'GB WVTA': /^(.{0,3})(.{0,4})(.{0,4})(.{0,7})$/i, - 'UKNI WVTA': /^(.?)(.{0,4})(.{0,4})(.{0,6})$/i, - 'EU WVTA Pre 23': /^(.{0,2})(.{0,4})(.{0,4})(.{0,6})$/i, - 'EU WVTA 23 on': /^(.{0,2})(.{0,4})(.{0,4})(.{0,6})$/i, - QNIG: /^(.{0,2})(.{0,4})(.{0,4})(.{0,6})$/i, - 'Prov.GB WVTA': /^(.{0,3})(.{0,4})(.{0,4})(.{0,6})$/i, - 'Small series NKSXX': /^(.?)11\*NKS(.{0,2})\/(.{0,4})\*(.{0,6})$/i, // 25 - 'Small series NKS': /^(.?)11\*NKS\*(.{0,6})$/i, // 23 - 'IVA - VCA': /^(.{0,2})(.{0,4})(.{0,6})$/i, + NTA: /^(.+)$/i, + 'IVA - DVSA/NI': /^(.+)$/i, + IVA: /^(.+)$/i, + ECTA: /^(.{0,2})(.{0,4})(.{0,4})(.{0,6})$/i, + NSSTA: /^(.{0,2})(.{0,6})$/i, + ECSSTA: /^(.{0,2})(.{0,2})(.{0,4})(.{0,6})$/i, + 'GB WVTA': /^(.{0,3})(.{0,4})(.{0,4})(.{0,7})$/i, + 'UKNI WVTA': /^(.?)(.{0,4})(.{0,4})(.{0,6})$/i, + 'EU WVTA Pre 23': /^(.{0,2})(.{0,4})(.{0,4})(.{0,6})$/i, + 'EU WVTA 23 on': /^(.{0,2})(.{0,4})(.{0,4})(.{0,6})$/i, + QNIG: /^(.{0,2})(.{0,4})(.{0,4})(.{0,6})$/i, + 'Prov.GB WVTA': /^(.{0,3})(.{0,4})(.{0,4})(.{0,6})$/i, + 'Small series NKSXX': /^(.?)11\*NKS(.{0,2})\/(.{0,4})\*(.{0,6})$/i, // 25 + 'Small series NKS': /^(.?)11\*NKS\*(.{0,6})$/i, // 23 + 'IVA - VCA': /^(.{0,2})(.{0,4})(.{0,6})$/i, }; const characterLimit: Record = { - NTA: 25, - 'IVA - DVSA/NI': 25, - IVA: 25, - ECTA: 20, - NSSTA: 14, - ECSSTA: 18, - 'GB WVTA': 21, - 'UKNI WVTA': 20, - 'EU WVTA Pre 23': 20, - 'EU WVTA 23 on': 20, - QNIG: 20, - 'Prov.GB WVTA': 20, - 'Small series NKSXX': 25, - 'Small series NKS': 23, - 'IVA - VCA': 19, + NTA: 25, + 'IVA - DVSA/NI': 25, + IVA: 25, + ECTA: 20, + NSSTA: 14, + ECSSTA: 18, + 'GB WVTA': 21, + 'UKNI WVTA': 20, + 'EU WVTA Pre 23': 20, + 'EU WVTA 23 on': 20, + QNIG: 20, + 'Prov.GB WVTA': 20, + 'Small series NKSXX': 25, + 'Small series NKS': 23, + 'IVA - VCA': 19, }; const characterLimitGeneric: Record = { - NTA: 25, - 'IVA - DVSA/NI': 25, - IVA: 25, - ECTA: 16, - NSSTA: 8, - ECSSTA: 14, - 'GB WVTA': 18, - 'UKNI WVTA': 15, - 'EU WVTA Pre 23': 16, - 'EU WVTA 23 on': 16, - QNIG: 16, - 'Prov.GB WVTA': 17, - 'Small series NKSXX': 25, - 'Small series NKS': 23, - 'IVA - VCA': 12, + NTA: 25, + 'IVA - DVSA/NI': 25, + IVA: 25, + ECTA: 16, + NSSTA: 8, + ECSSTA: 14, + 'GB WVTA': 18, + 'UKNI WVTA': 15, + 'EU WVTA Pre 23': 16, + 'EU WVTA 23 on': 16, + QNIG: 16, + 'Prov.GB WVTA': 17, + 'Small series NKSXX': 25, + 'Small series NKS': 23, + 'IVA - VCA': 12, }; @Component({ - selector: './app-approval-type-input', - templateUrl: './approval-type.component.html', - styleUrls: ['./approval-type.component.scss'], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: ApprovalTypeInputComponent, - multi: true, - }, - ], + selector: './app-approval-type-input', + templateUrl: './approval-type.component.html', + styleUrls: ['./approval-type.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: ApprovalTypeInputComponent, + multi: true, + }, + ], }) -export class ApprovalTypeInputComponent extends BaseControlComponent implements OnChanges, OnInit, OnDestroy, AfterContentInit { - @Input() isEditing = false; - @Input() approvalType?: string; - @Input() approvalTypeChange: boolean | undefined; - - private approvalTypeNumber_1: BehaviorSubject = new BehaviorSubject(undefined); - private approvalTypeNumber_2: BehaviorSubject = new BehaviorSubject(undefined); - private approvalTypeNumber_3: BehaviorSubject = new BehaviorSubject(undefined); - private approvalTypeNumber_4: BehaviorSubject = new BehaviorSubject(undefined); - - private approvalTypeNumber1$: Observable; - private approvalTypeNumber2$: Observable; - private approvalTypeNumber3$: Observable; - private approvalTypeNumber4$: Observable; - - private subscriptions: Array = []; - public errors?: { - error: boolean; - errors?: { - error: boolean; - reason: string; - index: number; - }[]; - }; - protected formSubmitted? = false; - public approvalTypeNumber1?: string; - public approvalTypeNumber2?: string; - public approvalTypeNumber3?: string; - public approvalTypeNumber4?: string; - - constructor(injector: Injector, changeDetectorRef: ChangeDetectorRef, public globalErrorService: GlobalErrorService) { - super(injector, changeDetectorRef); - this.approvalTypeNumber1$ = this.approvalTypeNumber_1.asObservable(); - this.approvalTypeNumber2$ = this.approvalTypeNumber_2.asObservable(); - this.approvalTypeNumber3$ = this.approvalTypeNumber_3.asObservable(); - this.approvalTypeNumber4$ = this.approvalTypeNumber_4.asObservable(); - this.globalErrorService.errors$.subscribe((globalErrors) => { - if (globalErrors.length) { - this.formSubmitted = true; - } - }); - } - - ngOnChanges(): void { - this.valueWriteBack(this.value); - - if (this.approvalTypeChange) { - this.clearInput(); - } - } - - ngOnInit(): void { - this.subscriptions.push(this.subscribeAndPropagateChanges()); - } - - override ngAfterContentInit(): void { - super.ngAfterContentInit(); - this.valueWriteBack(this.value); - } - - ngOnDestroy(): void { - this.subscriptions.forEach((s) => s && s.unsubscribe()); - } - - onTechRecord_approvalTypeNumber1_Change(event: string | undefined) { - this.approvalTypeNumber_1.next(event); - } - - onTechRecord_approvalTypeNumber2_Change(event: string | undefined) { - this.approvalTypeNumber_2.next(event); - } - - onTechRecord_approvalTypeNumber3_Change(event: string | undefined) { - this.approvalTypeNumber_3.next(event); - } - - onTechRecord_approvalTypeNumber4_Change(event: string | undefined) { - this.approvalTypeNumber_4.next(event); - } - - valueWriteBack(value: string | null): void { - if (!value || !this.approvalType) { - return; - } - - const NTA_IVA_Types = ['NTA', 'IVA', 'IVA - DVSA/NI']; - const OtherTypes = [ - 'ECTA', - 'NSSTA', - 'ECSSTA', - 'GB WVTA', - 'UKNI WVTA', - 'EU WVTA Pre 23', - 'EU WVTA 23 on', - 'QNIG', - 'Prov.GB WVTA', - 'IVA - VCA', - 'Small series NKSXX', - 'Small series NKS', - ]; - - if (NTA_IVA_Types.includes(this.approvalType)) { - this.extractValuesNtaIva(value, patterns[this.approvalType]); - } else if (OtherTypes.includes(this.approvalType)) { - this.extractValues(value); - } - } - - private extractValues(value: string): void { - if (!value || !this.approvalType) return; - - const getMatchedValues = (_value: string, pattern: RegExp) => { - const result = _value.match(pattern); - return result ? result.slice(1) : []; - }; - - const pattern = patterns[this.approvalType]; - const patternPartial = patternsPartialMatch[this.approvalType] || /^$/; - - let matches = getMatchedValues(value, pattern); - if (matches) { - this.setTypeApprovalNumbers(matches.filter((x) => x)); - } - - if (!matches.length) { - const limit = characterLimit[this.approvalType]; - const limitedValue = value.length > limit ? value.substring(0, limit) : value; - matches = getMatchedValues(limitedValue, patternPartial); - this.setTypeApprovalNumbers(matches.filter((x) => x)); - } - - if (!matches.length) { - const limit = characterLimitGeneric[this.approvalType]; - const limitedValue = value.length > limit ? value.substring(0, limit) : value; - const genericPattern = patternsGenericPartialMatch[this.approvalType] || /^$/; - matches = getMatchedValues(limitedValue, genericPattern); - this.setTypeApprovalNumbers(matches.filter((x) => x)); - } - - if (!matches.length) { - console.error('Unknown approvalType:', this.approvalType); - } - } - - private extractValuesNtaIva(value: string, pattern: RegExp): void { - const matches = value.match(pattern)?.map((x) => (x.length > 25 ? x.substring(0, 25) : x)); - this.setTypeApprovalNumbers(matches || []); - } - - private setTypeApprovalNumbers(matches: string[]) { - if (matches) { - const [approvalTypeNumber1, approvalTypeNumber2, approvalTypeNumber3, approvalTypeNumber4] = matches; - this.approvalTypeNumber1 = approvalTypeNumber1; - this.approvalTypeNumber_1.next(approvalTypeNumber1); - this.approvalTypeNumber2 = approvalTypeNumber2; - this.approvalTypeNumber_2.next(approvalTypeNumber2); - this.approvalTypeNumber3 = approvalTypeNumber3; - this.approvalTypeNumber_3.next(approvalTypeNumber3); - this.approvalTypeNumber4 = approvalTypeNumber4; - this.approvalTypeNumber_4.next(approvalTypeNumber4); - } - } - - /** - * Subscribes to all date segments and propagates value as `string`. - * @returns Subscription - */ - subscribeAndPropagateChanges() { - return combineLatest([this.approvalTypeNumber1$, this.approvalTypeNumber2$, this.approvalTypeNumber3$, this.approvalTypeNumber4$]).subscribe( - ([approvalTypeNumber1, approvalTypeNumber2, approvalTypeNumber3, approvalTypeNumber4]) => { - if (!approvalTypeNumber1 && !approvalTypeNumber2 && !approvalTypeNumber3 && !approvalTypeNumber4) { - this.onChange(null); - } else { - this.onChange(this.processApprovalTypeNumber(approvalTypeNumber1, approvalTypeNumber2, approvalTypeNumber3, approvalTypeNumber4)); - } - }, - ); - } - - validate() { - const setErrors = () => { - this.errors = { - error: true, - errors: [ - { - error: true, - reason: 'Approval type number is required with Approval type', - index: 0, - }, - ], - }; - }; - - const oneRequired = () => !this.approvalTypeNumber1 && this.approvalType; - const twoRequired = () => oneRequired() || !this.approvalTypeNumber2; - const threeRequired = () => twoRequired() || !this.approvalTypeNumber3; - const fourRequired = () => threeRequired() || !this.approvalTypeNumber4; - - switch (this.approvalType) { - case ApprovalType.NTA: - case ApprovalType.IVA: - case ApprovalType.IVA_DVSA_NI: - if (oneRequired()) { - setErrors(); - } - break; - - case ApprovalType.GB_WVTA: - case ApprovalType.EU_WVTA_PRE_23: - case ApprovalType.EU_WVTA_23_ON: - case ApprovalType.PROV_GB_WVTA: - case ApprovalType.QNIG: - case ApprovalType.ECTA: - case ApprovalType.ECSSTA: - case ApprovalType.UKNI_WVTA: - if (fourRequired()) { - setErrors(); - } - break; - - case ApprovalType.IVA_VCA: - case ApprovalType.SMALL_SERIES_NKSXX: - if (fourRequired()) { - setErrors(); - } - break; - - case ApprovalType.NSSTA: - case ApprovalType.SMALL_SERIES_NKS: - if (twoRequired()) { - setErrors(); - } - break; - - default: - break; - } - } - - clearInput() { - this.approvalTypeNumber1 = undefined; - this.approvalTypeNumber2 = undefined; - this.approvalTypeNumber3 = undefined; - this.approvalTypeNumber4 = undefined; - - this.approvalTypeNumber_1.next(this.approvalTypeNumber1); - this.approvalTypeNumber_2.next(this.approvalTypeNumber2); - this.approvalTypeNumber_3.next(this.approvalTypeNumber3); - this.approvalTypeNumber_4.next(this.approvalTypeNumber4); - - this.onChange(null); - } - - get widths(): typeof FormNodeWidth { - return FormNodeWidth; - } - - processApprovalTypeNumber( - approvalTypeNumber1: string | undefined, - approvalTypeNumber2: string | undefined, - approvalTypeNumber3: string | undefined, - approvalTypeNumber4: string | undefined, - ) { - switch (this.approvalType) { - case ApprovalType.NTA: - return approvalTypeNumber1 || null; - - case ApprovalType.ECTA: - return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 && approvalTypeNumber4 - ? `e${approvalTypeNumber1}*${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` - : null; - - case ApprovalType.IVA: - return approvalTypeNumber1 || null; - - case ApprovalType.NSSTA: - return approvalTypeNumber1 && approvalTypeNumber2 ? `e${approvalTypeNumber1}*NKS*${approvalTypeNumber2}` : null; - - case ApprovalType.ECSSTA: - return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 && approvalTypeNumber4 - ? `e${approvalTypeNumber1}*KS${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` - : null; - - case ApprovalType.GB_WVTA: - return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 && approvalTypeNumber4 - ? `${approvalTypeNumber1}*${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` - : null; - - case ApprovalType.UKNI_WVTA: - return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 && approvalTypeNumber4 - ? `${approvalTypeNumber1}11*${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` - : null; - - case ApprovalType.EU_WVTA_PRE_23: - return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 && approvalTypeNumber4 - ? `e${approvalTypeNumber1}*${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` - : null; - - case ApprovalType.EU_WVTA_23_ON: - return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 && approvalTypeNumber4 - ? `e${approvalTypeNumber1}*${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` - : null; - - case ApprovalType.QNIG: - return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 && approvalTypeNumber4 - ? `e${approvalTypeNumber1}*${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` - : null; - - case ApprovalType.PROV_GB_WVTA: - return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 && approvalTypeNumber4 - ? `${approvalTypeNumber1}*${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` - : null; - - case ApprovalType.SMALL_SERIES_NKSXX: - return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 - ? `${approvalTypeNumber1}11*NKS${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` - : null; - - case ApprovalType.SMALL_SERIES_NKS: - return approvalTypeNumber1 && approvalTypeNumber2 ? `${approvalTypeNumber1}11*NKS*${approvalTypeNumber2}` : null; - - case ApprovalType.IVA_VCA: - return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 - ? `n11*NIV${approvalTypeNumber1}/${approvalTypeNumber2}*${approvalTypeNumber3}` - : null; - - case ApprovalType.IVA_DVSA_NI: - return approvalTypeNumber1 || null; - default: - return 'Unknown approval type'; - } - } - - getId(name: string) { - const id = `${name}-approvalTypeNumber1-${this.approvalType}`; - if (this.control) { - this.control.meta.customId = id; - } - return id; - } +export class ApprovalTypeInputComponent + extends BaseControlComponent + implements OnChanges, OnInit, OnDestroy, AfterContentInit +{ + @Input() isEditing = false; + @Input() approvalType?: string; + @Input() approvalTypeChange: boolean | undefined; + + private approvalTypeNumber_1: BehaviorSubject = new BehaviorSubject( + undefined + ); + private approvalTypeNumber_2: BehaviorSubject = new BehaviorSubject( + undefined + ); + private approvalTypeNumber_3: BehaviorSubject = new BehaviorSubject( + undefined + ); + private approvalTypeNumber_4: BehaviorSubject = new BehaviorSubject( + undefined + ); + + private approvalTypeNumber1$: Observable; + private approvalTypeNumber2$: Observable; + private approvalTypeNumber3$: Observable; + private approvalTypeNumber4$: Observable; + + private subscriptions: Array = []; + public errors?: { + error: boolean; + errors?: { + error: boolean; + reason: string; + index: number; + }[]; + }; + protected formSubmitted? = false; + public approvalTypeNumber1?: string; + public approvalTypeNumber2?: string; + public approvalTypeNumber3?: string; + public approvalTypeNumber4?: string; + + constructor( + injector: Injector, + changeDetectorRef: ChangeDetectorRef, + public globalErrorService: GlobalErrorService + ) { + super(injector, changeDetectorRef); + this.approvalTypeNumber1$ = this.approvalTypeNumber_1.asObservable(); + this.approvalTypeNumber2$ = this.approvalTypeNumber_2.asObservable(); + this.approvalTypeNumber3$ = this.approvalTypeNumber_3.asObservable(); + this.approvalTypeNumber4$ = this.approvalTypeNumber_4.asObservable(); + this.globalErrorService.errors$.subscribe((globalErrors) => { + if (globalErrors.length) { + this.formSubmitted = true; + } + }); + } + + ngOnChanges(): void { + this.valueWriteBack(this.value); + + if (this.approvalTypeChange) { + this.clearInput(); + } + } + + ngOnInit(): void { + this.subscriptions.push(this.subscribeAndPropagateChanges()); + } + + override ngAfterContentInit(): void { + super.ngAfterContentInit(); + this.valueWriteBack(this.value); + } + + ngOnDestroy(): void { + this.subscriptions.forEach((s) => s && s.unsubscribe()); + } + + onTechRecord_approvalTypeNumber1_Change(event: string | undefined) { + this.approvalTypeNumber_1.next(event); + } + + onTechRecord_approvalTypeNumber2_Change(event: string | undefined) { + this.approvalTypeNumber_2.next(event); + } + + onTechRecord_approvalTypeNumber3_Change(event: string | undefined) { + this.approvalTypeNumber_3.next(event); + } + + onTechRecord_approvalTypeNumber4_Change(event: string | undefined) { + this.approvalTypeNumber_4.next(event); + } + + valueWriteBack(value: string | null): void { + if (!value || !this.approvalType) { + return; + } + + const NTA_IVA_Types = ['NTA', 'IVA', 'IVA - DVSA/NI']; + const OtherTypes = [ + 'ECTA', + 'NSSTA', + 'ECSSTA', + 'GB WVTA', + 'UKNI WVTA', + 'EU WVTA Pre 23', + 'EU WVTA 23 on', + 'QNIG', + 'Prov.GB WVTA', + 'IVA - VCA', + 'Small series NKSXX', + 'Small series NKS', + ]; + + if (NTA_IVA_Types.includes(this.approvalType)) { + this.extractValuesNtaIva(value, patterns[this.approvalType]); + } else if (OtherTypes.includes(this.approvalType)) { + this.extractValues(value); + } + } + + private extractValues(value: string): void { + if (!value || !this.approvalType) return; + + const getMatchedValues = (_value: string, pattern: RegExp) => { + const result = _value.match(pattern); + return result ? result.slice(1) : []; + }; + + const pattern = patterns[this.approvalType]; + const patternPartial = patternsPartialMatch[this.approvalType] || /^$/; + + let matches = getMatchedValues(value, pattern); + if (matches) { + this.setTypeApprovalNumbers(matches.filter((x) => x)); + } + + if (!matches.length) { + const limit = characterLimit[this.approvalType]; + const limitedValue = value.length > limit ? value.substring(0, limit) : value; + matches = getMatchedValues(limitedValue, patternPartial); + this.setTypeApprovalNumbers(matches.filter((x) => x)); + } + + if (!matches.length) { + const limit = characterLimitGeneric[this.approvalType]; + const limitedValue = value.length > limit ? value.substring(0, limit) : value; + const genericPattern = patternsGenericPartialMatch[this.approvalType] || /^$/; + matches = getMatchedValues(limitedValue, genericPattern); + this.setTypeApprovalNumbers(matches.filter((x) => x)); + } + + if (!matches.length) { + console.error('Unknown approvalType:', this.approvalType); + } + } + + private extractValuesNtaIva(value: string, pattern: RegExp): void { + const matches = value.match(pattern)?.map((x) => (x.length > 25 ? x.substring(0, 25) : x)); + this.setTypeApprovalNumbers(matches || []); + } + + private setTypeApprovalNumbers(matches: string[]) { + if (matches) { + const [approvalTypeNumber1, approvalTypeNumber2, approvalTypeNumber3, approvalTypeNumber4] = matches; + this.approvalTypeNumber1 = approvalTypeNumber1; + this.approvalTypeNumber_1.next(approvalTypeNumber1); + this.approvalTypeNumber2 = approvalTypeNumber2; + this.approvalTypeNumber_2.next(approvalTypeNumber2); + this.approvalTypeNumber3 = approvalTypeNumber3; + this.approvalTypeNumber_3.next(approvalTypeNumber3); + this.approvalTypeNumber4 = approvalTypeNumber4; + this.approvalTypeNumber_4.next(approvalTypeNumber4); + } + } + + /** + * Subscribes to all date segments and propagates value as `string`. + * @returns Subscription + */ + subscribeAndPropagateChanges() { + return combineLatest([ + this.approvalTypeNumber1$, + this.approvalTypeNumber2$, + this.approvalTypeNumber3$, + this.approvalTypeNumber4$, + ]).subscribe(([approvalTypeNumber1, approvalTypeNumber2, approvalTypeNumber3, approvalTypeNumber4]) => { + if (!approvalTypeNumber1 && !approvalTypeNumber2 && !approvalTypeNumber3 && !approvalTypeNumber4) { + this.onChange(null); + } else { + this.onChange( + this.processApprovalTypeNumber( + approvalTypeNumber1, + approvalTypeNumber2, + approvalTypeNumber3, + approvalTypeNumber4 + ) + ); + } + }); + } + + validate() { + const setErrors = () => { + this.errors = { + error: true, + errors: [ + { + error: true, + reason: 'Approval type number is required with Approval type', + index: 0, + }, + ], + }; + }; + + const oneRequired = () => !this.approvalTypeNumber1 && this.approvalType; + const twoRequired = () => oneRequired() || !this.approvalTypeNumber2; + const threeRequired = () => twoRequired() || !this.approvalTypeNumber3; + const fourRequired = () => threeRequired() || !this.approvalTypeNumber4; + + switch (this.approvalType) { + case ApprovalType.NTA: + case ApprovalType.IVA: + case ApprovalType.IVA_DVSA_NI: + if (oneRequired()) { + setErrors(); + } + break; + + case ApprovalType.GB_WVTA: + case ApprovalType.EU_WVTA_PRE_23: + case ApprovalType.EU_WVTA_23_ON: + case ApprovalType.PROV_GB_WVTA: + case ApprovalType.QNIG: + case ApprovalType.ECTA: + case ApprovalType.ECSSTA: + case ApprovalType.UKNI_WVTA: + if (fourRequired()) { + setErrors(); + } + break; + + case ApprovalType.IVA_VCA: + case ApprovalType.SMALL_SERIES_NKSXX: + if (fourRequired()) { + setErrors(); + } + break; + + case ApprovalType.NSSTA: + case ApprovalType.SMALL_SERIES_NKS: + if (twoRequired()) { + setErrors(); + } + break; + + default: + break; + } + } + + clearInput() { + this.approvalTypeNumber1 = undefined; + this.approvalTypeNumber2 = undefined; + this.approvalTypeNumber3 = undefined; + this.approvalTypeNumber4 = undefined; + + this.approvalTypeNumber_1.next(this.approvalTypeNumber1); + this.approvalTypeNumber_2.next(this.approvalTypeNumber2); + this.approvalTypeNumber_3.next(this.approvalTypeNumber3); + this.approvalTypeNumber_4.next(this.approvalTypeNumber4); + + this.onChange(null); + } + + get widths(): typeof FormNodeWidth { + return FormNodeWidth; + } + + processApprovalTypeNumber( + approvalTypeNumber1: string | undefined, + approvalTypeNumber2: string | undefined, + approvalTypeNumber3: string | undefined, + approvalTypeNumber4: string | undefined + ) { + switch (this.approvalType) { + case ApprovalType.NTA: + return approvalTypeNumber1 || null; + + case ApprovalType.ECTA: + return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 && approvalTypeNumber4 + ? `e${approvalTypeNumber1}*${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` + : null; + + case ApprovalType.IVA: + return approvalTypeNumber1 || null; + + case ApprovalType.NSSTA: + return approvalTypeNumber1 && approvalTypeNumber2 ? `e${approvalTypeNumber1}*NKS*${approvalTypeNumber2}` : null; + + case ApprovalType.ECSSTA: + return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 && approvalTypeNumber4 + ? `e${approvalTypeNumber1}*KS${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` + : null; + + case ApprovalType.GB_WVTA: + return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 && approvalTypeNumber4 + ? `${approvalTypeNumber1}*${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` + : null; + + case ApprovalType.UKNI_WVTA: + return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 && approvalTypeNumber4 + ? `${approvalTypeNumber1}11*${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` + : null; + + case ApprovalType.EU_WVTA_PRE_23: + return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 && approvalTypeNumber4 + ? `e${approvalTypeNumber1}*${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` + : null; + + case ApprovalType.EU_WVTA_23_ON: + return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 && approvalTypeNumber4 + ? `e${approvalTypeNumber1}*${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` + : null; + + case ApprovalType.QNIG: + return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 && approvalTypeNumber4 + ? `e${approvalTypeNumber1}*${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` + : null; + + case ApprovalType.PROV_GB_WVTA: + return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 && approvalTypeNumber4 + ? `${approvalTypeNumber1}*${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` + : null; + + case ApprovalType.SMALL_SERIES_NKSXX: + return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 + ? `${approvalTypeNumber1}11*NKS${approvalTypeNumber2}/${approvalTypeNumber3}*${approvalTypeNumber4}` + : null; + + case ApprovalType.SMALL_SERIES_NKS: + return approvalTypeNumber1 && approvalTypeNumber2 + ? `${approvalTypeNumber1}11*NKS*${approvalTypeNumber2}` + : null; + + case ApprovalType.IVA_VCA: + return approvalTypeNumber1 && approvalTypeNumber2 && approvalTypeNumber3 + ? `n11*NIV${approvalTypeNumber1}/${approvalTypeNumber2}*${approvalTypeNumber3}` + : null; + + case ApprovalType.IVA_DVSA_NI: + return approvalTypeNumber1 || null; + default: + return 'Unknown approval type'; + } + } + + getId(name: string) { + const id = `${name}-approvalTypeNumber1-${this.approvalType}`; + if (this.control) { + this.control.meta.customId = id; + } + return id; + } } diff --git a/src/app/forms/components/autocomplete/autocomplete.component.spec.ts b/src/app/forms/components/autocomplete/autocomplete.component.spec.ts index ffaee4b948..4cd953f538 100644 --- a/src/app/forms/components/autocomplete/autocomplete.component.spec.ts +++ b/src/app/forms/components/autocomplete/autocomplete.component.spec.ts @@ -8,96 +8,97 @@ import { FieldErrorMessageComponent } from '../field-error-message/field-error-m import { AutocompleteComponent } from './autocomplete.component'; jest.mock('accessible-autocomplete/dist/accessible-autocomplete.min', () => { - return { - __esModule: true, - default: jest.fn(), - enhanceSelectElement: () => {}, - }; + return { + __esModule: true, + default: jest.fn(), + enhanceSelectElement: () => {}, + }; }); @Component({ - selector: 'app-host-component', - template: '
', + selector: 'app-host-component', + template: + '
', }) class HostComponent { - name = 'autocomplete'; - options$ = of([ - { label: 'option1', value: 'option1' }, - { label: 'option2', value: 'option2' }, - ]); - form = new FormGroup({ foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL }, '') }); + name = 'autocomplete'; + options$ = of([ + { label: 'option1', value: 'option1' }, + { label: 'option2', value: 'option2' }, + ]); + form = new FormGroup({ foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL }, '') }); } describe('AutocompleteComponent', () => { - let component: HostComponent; - let fixture: ComponentFixture; - let autocompleteComponent: AutocompleteComponent; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AutocompleteComponent, HostComponent, FieldErrorMessageComponent], - imports: [FormsModule, ReactiveFormsModule], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(HostComponent); - component = fixture.componentInstance; - autocompleteComponent = fixture.debugElement.query(By.directive(AutocompleteComponent)).componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it.each([ - ['option1', of([{ label: 'option1', value: 'option1' }]), 'option1'], - [undefined, of([{ label: 'option1', value: 'option1' }]), 'option3'], - ])('should return %s for %o when looking for $s', (expected, options$, label) => { - autocompleteComponent.options$ = options$; - expect(autocompleteComponent.findOptionValue(label)).toBe(expected); - }); - - it('should call handleChange when input value changes', () => { - const handleChangeSpy = jest.spyOn(autocompleteComponent, 'handleChange'); - const autocompleteInput: HTMLInputElement = fixture.debugElement.query(By.css(`#${component.name}`)).nativeElement; - - autocompleteInput.dispatchEvent(new Event('change')); - - expect(handleChangeSpy).toHaveBeenCalled(); - }); - - it('should find option value by label and propagate to form control', () => { - const findOptionValueSpy = jest.spyOn(autocompleteComponent, 'findOptionValue'); - const control = component.form.get('foo'); - - autocompleteComponent.handleChange({ target: { value: 'option2' } } as unknown as Event); - - expect(findOptionValueSpy).toHaveBeenCalled(); - expect(control?.value).toBe('option2'); - expect(control?.touched).toBeTruthy(); - }); - - it('should propagate "" to form control when input is left empty', () => { - 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(); - }); - - it('should propagate "[INVALID_OPTION]" to form control when value is not an option', () => { - const findOptionValueSpy = jest.spyOn(autocompleteComponent, 'findOptionValue'); - const control = component.form.get('foo'); - - autocompleteComponent.handleChange({ target: { value: 'option3' } } as unknown as Event); - - expect(findOptionValueSpy).toHaveBeenCalled(); - expect(control?.value).toBe('[INVALID_OPTION]'); - expect(control?.touched).toBeTruthy(); - }); + let component: HostComponent; + let fixture: ComponentFixture; + let autocompleteComponent: AutocompleteComponent; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AutocompleteComponent, HostComponent, FieldErrorMessageComponent], + imports: [FormsModule, ReactiveFormsModule], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(HostComponent); + component = fixture.componentInstance; + autocompleteComponent = fixture.debugElement.query(By.directive(AutocompleteComponent)).componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it.each([ + ['option1', of([{ label: 'option1', value: 'option1' }]), 'option1'], + [undefined, of([{ label: 'option1', value: 'option1' }]), 'option3'], + ])('should return %s for %o when looking for $s', (expected, options$, label) => { + autocompleteComponent.options$ = options$; + expect(autocompleteComponent.findOptionValue(label)).toBe(expected); + }); + + it('should call handleChange when input value changes', () => { + const handleChangeSpy = jest.spyOn(autocompleteComponent, 'handleChange'); + const autocompleteInput: HTMLInputElement = fixture.debugElement.query(By.css(`#${component.name}`)).nativeElement; + + autocompleteInput.dispatchEvent(new Event('change')); + + expect(handleChangeSpy).toHaveBeenCalled(); + }); + + it('should find option value by label and propagate to form control', () => { + const findOptionValueSpy = jest.spyOn(autocompleteComponent, 'findOptionValue'); + const control = component.form.get('foo'); + + autocompleteComponent.handleChange({ target: { value: 'option2' } } as unknown as Event); + + expect(findOptionValueSpy).toHaveBeenCalled(); + expect(control?.value).toBe('option2'); + expect(control?.touched).toBeTruthy(); + }); + + it('should propagate "" to form control when input is left empty', () => { + 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(); + }); + + it('should propagate "[INVALID_OPTION]" to form control when value is not an option', () => { + const findOptionValueSpy = jest.spyOn(autocompleteComponent, 'findOptionValue'); + const control = component.form.get('foo'); + + autocompleteComponent.handleChange({ target: { value: 'option3' } } as unknown as Event); + + expect(findOptionValueSpy).toHaveBeenCalled(); + expect(control?.value).toBe('[INVALID_OPTION]'); + expect(control?.touched).toBeTruthy(); + }); }); diff --git a/src/app/forms/components/autocomplete/autocomplete.component.ts b/src/app/forms/components/autocomplete/autocomplete.component.ts index bc1b0c9c82..7a08717079 100644 --- a/src/app/forms/components/autocomplete/autocomplete.component.ts +++ b/src/app/forms/components/autocomplete/autocomplete.component.ts @@ -1,7 +1,5 @@ import { DOCUMENT } from '@angular/common'; -import { - AfterContentInit, AfterViewInit, ChangeDetectorRef, Component, Inject, Injector, Input, -} from '@angular/core'; +import { AfterContentInit, AfterViewInit, ChangeDetectorRef, Component, Inject, Injector, Input } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { CustomValidators } from '@forms/validators/custom-validators'; import { enhanceSelectElement } from 'accessible-autocomplete/dist/accessible-autocomplete.min'; @@ -9,98 +7,105 @@ import { Observable, lastValueFrom, takeWhile } from 'rxjs'; import { BaseControlComponent } from '../base-control/base-control.component'; @Component({ - selector: 'app-autocomplete', - templateUrl: './autocomplete.component.html', - styleUrls: ['./autocomplete.component.scss'], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: AutocompleteComponent, - multi: true, - }, - ], + selector: 'app-autocomplete', + templateUrl: './autocomplete.component.html', + styleUrls: ['./autocomplete.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: AutocompleteComponent, + multi: true, + }, + ], }) export class AutocompleteComponent extends BaseControlComponent implements AfterViewInit, AfterContentInit { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - @Input() options$!: Observable; - @Input() defaultValue = ''; - - // eslint-disable-next-line max-len - DROP_DOWN_ARROW = ''; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - options: any[] = []; - - constructor(injector: Injector, @Inject(DOCUMENT) private document: Document, changeDetectorRef: ChangeDetectorRef) { - super(injector, changeDetectorRef); - } - - ngAfterViewInit(): void { - // eslint-disable-next-line @typescript-eslint/no-this-alias - const self = this; - - lastValueFrom(this.options$.pipe(takeWhile((options) => !options || options.length === 0, true))).then((options) => { - this.options = options; - this.cdr.detectChanges(); - - enhanceSelectElement({ - selectElement: this.document.querySelector(`#${this.name}`), - autoselect: false, - defaultValue: '', - showAllValues: true, - confirmOnBlur: false, - dropdownArrow: () => this.DROP_DOWN_ARROW, - onConfirm(selected) { - self.handleChangeForOption(selected); - }, - }); - - window.document.querySelector(`#${this.name}`)?.addEventListener('change', (event) => this.handleChange(event)); - }).catch(() => {}); - } - - override ngAfterContentInit(): void { - super.ngAfterContentInit(); - this.addValidators(); - } - - get style(): string { - return `autocomplete__wrapper${this.noBottomMargin ? '' : ' extra-margin'}`; - } - - get innerStyle(): string { - return this.width ? ` govuk-input--width-${this.width}` : ' internal-wrapper'; - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - handleChange(event: any) { - const { - target: { value }, - } = event; - - this.handleChangeForOption(value); - } - - handleChangeForOption(value: string) { - const optionValue = this.findOptionValue(value); - - this.control?.patchValue(optionValue ?? '[INVALID_OPTION]'); - this.control?.markAsTouched(); - this.control?.updateValueAndValidity(); - this.cdr.detectChanges(); - } - - /** - * Takes the value from the autocomplete element and looks for a matching option in the options array. - * Returns the found value or undefined if no match. - * If value is empty, returns `''`. - * @param value - value to get option for - * @returns `string | undefined` - */ - findOptionValue(label: string) { - return label ? this.options.find((option) => option.label === label)?.value : ''; - } - - addValidators() { - this.control?.addValidators([CustomValidators.invalidOption]); - } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + @Input() options$!: Observable; + @Input() defaultValue = ''; + + // eslint-disable-next-line max-len + DROP_DOWN_ARROW = + ''; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + options: any[] = []; + + constructor( + injector: Injector, + @Inject(DOCUMENT) private document: Document, + changeDetectorRef: ChangeDetectorRef + ) { + super(injector, changeDetectorRef); + } + + ngAfterViewInit(): void { + // eslint-disable-next-line @typescript-eslint/no-this-alias + const self = this; + + lastValueFrom(this.options$.pipe(takeWhile((options) => !options || options.length === 0, true))) + .then((options) => { + this.options = options; + this.cdr.detectChanges(); + + enhanceSelectElement({ + selectElement: this.document.querySelector(`#${this.name}`), + autoselect: false, + defaultValue: '', + showAllValues: true, + confirmOnBlur: false, + dropdownArrow: () => this.DROP_DOWN_ARROW, + onConfirm(selected) { + self.handleChangeForOption(selected); + }, + }); + + window.document.querySelector(`#${this.name}`)?.addEventListener('change', (event) => this.handleChange(event)); + }) + .catch(() => {}); + } + + override ngAfterContentInit(): void { + super.ngAfterContentInit(); + this.addValidators(); + } + + get style(): string { + return `autocomplete__wrapper${this.noBottomMargin ? '' : ' extra-margin'}`; + } + + get innerStyle(): string { + return this.width ? ` govuk-input--width-${this.width}` : ' internal-wrapper'; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + handleChange(event: any) { + const { + target: { value }, + } = event; + + this.handleChangeForOption(value); + } + + handleChangeForOption(value: string) { + const optionValue = this.findOptionValue(value); + + this.control?.patchValue(optionValue ?? '[INVALID_OPTION]'); + this.control?.markAsTouched(); + this.control?.updateValueAndValidity(); + this.cdr.detectChanges(); + } + + /** + * Takes the value from the autocomplete element and looks for a matching option in the options array. + * Returns the found value or undefined if no match. + * If value is empty, returns `''`. + * @param value - value to get option for + * @returns `string | undefined` + */ + findOptionValue(label: string) { + return label ? this.options.find((option) => option.label === label)?.value : ''; + } + + addValidators() { + this.control?.addValidators([CustomValidators.invalidOption]); + } } diff --git a/src/app/forms/components/autocomplete/autocomplete.stories.ts b/src/app/forms/components/autocomplete/autocomplete.stories.ts index ecba69c689..8a9e8bbf4d 100644 --- a/src/app/forms/components/autocomplete/autocomplete.stories.ts +++ b/src/app/forms/components/autocomplete/autocomplete.stories.ts @@ -1,45 +1,45 @@ import { CommonModule } from '@angular/common'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { Meta, moduleMetadata, Story } from '@storybook/angular'; +import { Meta, Story, moduleMetadata } from '@storybook/angular'; import { AutocompleteComponent } from './autocomplete.component'; export default { - title: 'Forms/Autocomplete', - component: AutocompleteComponent, - decorators: [ - moduleMetadata({ - declarations: [AutocompleteComponent], - imports: [CommonModule, FormsModule, ReactiveFormsModule] - }) - ] + title: 'Forms/Autocomplete', + component: AutocompleteComponent, + decorators: [ + moduleMetadata({ + declarations: [AutocompleteComponent], + imports: [CommonModule, FormsModule, ReactiveFormsModule], + }), + ], } as Meta; -const Template: Story = args => { - const { id, label, options, name, hint, defaultValue = 'red' } = args; - return { - component: AutocompleteComponent, - template: `
`, - props: { - id, - label, - hint, - name, - options, - defaultValue - } - }; +const Template: Story = (args) => { + const { id, label, options, name, hint, defaultValue = 'red' } = args; + return { + component: AutocompleteComponent, + template: `
`, + props: { + id, + label, + hint, + name, + options, + defaultValue, + }, + }; }; const defaultArgs = { - label: 'Autocomplete', - hint: 'Type any letter to start searching', - name: 'name', - id: 'name' + '-wrapper', - options: ['red', 'yellow', 'blue', 'green'], - defaultValue: 'red' + label: 'Autocomplete', + hint: 'Type any letter to start searching', + name: 'name', + id: 'name' + '-wrapper', + options: ['red', 'yellow', 'blue', 'green'], + defaultValue: 'red', }; export const Enabled = Template.bind({}); Enabled.args = { - ...defaultArgs + ...defaultArgs, }; diff --git a/src/app/forms/components/base-control/base-control.component.spec.ts b/src/app/forms/components/base-control/base-control.component.spec.ts index d2723b6564..ff05f29a77 100644 --- a/src/app/forms/components/base-control/base-control.component.spec.ts +++ b/src/app/forms/components/base-control/base-control.component.spec.ts @@ -4,137 +4,140 @@ import { CustomFormControl, FormNodeTypes } from '../../services/dynamic-form.ty import { BaseControlComponent } from './base-control.component'; describe('BaseControlComponent', () => { - let component: BaseControlComponent; - let fixture: ComponentFixture; - - const controlMetaData = { name: 'testControl', type: FormNodeTypes.CONTROL, children: [] }; - - describe('has control binding', () => { - beforeEach(async () => { - const NG_CONTROL_PROVIDER = { - provide: NgControl, - useClass: class extends NgControl { - control = new CustomFormControl(controlMetaData, '', [Validators.required]); - viewToModelUpdate() {} - }, - }; - - await TestBed.configureTestingModule({ - declarations: [BaseControlComponent], - imports: [FormsModule], - }) - .overrideComponent(BaseControlComponent, { add: { providers: [NG_CONTROL_PROVIDER] } }) - .compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(BaseControlComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should register a change', () => { - component.registerOnChange('FUNCTION' as unknown as () => void); - expect(component.onChange).toBe('FUNCTION'); - }); - - it('should register it has been touched', () => { - component.registerOnTouched('FUNCTION' as unknown as () => void); - expect(component.onTouched).toBe('FUNCTION'); - }); - - it('should call onChange successfully', () => { - const onChangepy = jest.spyOn(component, 'onChange'); - - component.onChange(null); - - expect(onChangepy).toHaveBeenCalledWith(null); - }); - - it('should call onTouched successfully', () => { - const onTouchedpy = jest.spyOn(component, 'onTouched'); - - component.onTouched(); - - expect(onTouchedpy).toHaveBeenCalled(); - }); - - it('should return disabled', () => { - expect(component.disabled).toBeFalsy(); - }); - - it('should return metadata', () => { - expect(component.meta).toEqual(controlMetaData); - }); - - it('should correctly set focused flag', () => { - component.handleEvent(new Event('focus')); - expect(component.focused).toBeTruthy(); - - component.handleEvent(new Event('blur')); - expect(component.focused).toBeFalsy(); - - const handleEventSpy = jest.spyOn(component, 'handleEvent'); - const state = component.handleEvent(new Event('submit')); - expect(handleEventSpy).toHaveBeenCalled(); - expect(state).toBeNull(); - }); - - describe('interacting with the value', () => { - it('writeValue should set the value', () => { - component.writeValue('anything'); - expect(component.value).toBe('anything'); - }); - - it('set should set the value', () => { - component.value = 'anything'; - expect(component.value).toBe('anything'); - }); - }); - - describe('validation', () => { - it('should get mapped message for first validation error', () => { - component.label = 'Test control'; - component.control?.markAsTouched(); - fixture.detectChanges(); - expect(component.error).toBe('Test control is required'); - }); - - it('should get "" when control is valid', () => { - component.label = 'Test control'; - component.control?.patchValue('test'); - component.control?.markAsTouched(); - fixture.detectChanges(); - expect(component.error).toBe(''); - }); - }); - }); - - describe('does not have control binding', () => { - beforeEach(async () => { - await TestBed.configureTestingModule({ declarations: [BaseControlComponent], imports: [FormsModule] }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(BaseControlComponent); - component = fixture.componentInstance; - }); - - it('shoud throw no control binding error', () => { - expect(component).toBeTruthy(); - expect(() => fixture.detectChanges()).toThrow(Error); - }); - - it('should return undefined for metadata', () => { - expect(component.meta).toBeUndefined(); - }); - - it('disabled should default to false', () => { - expect(component.disabled).toBeFalsy(); - }); - }); + let component: BaseControlComponent; + let fixture: ComponentFixture; + + const controlMetaData = { name: 'testControl', type: FormNodeTypes.CONTROL, children: [] }; + + describe('has control binding', () => { + beforeEach(async () => { + const NG_CONTROL_PROVIDER = { + provide: NgControl, + useClass: class extends NgControl { + control = new CustomFormControl(controlMetaData, '', [Validators.required]); + viewToModelUpdate() {} + }, + }; + + await TestBed.configureTestingModule({ + declarations: [BaseControlComponent], + imports: [FormsModule], + }) + .overrideComponent(BaseControlComponent, { add: { providers: [NG_CONTROL_PROVIDER] } }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(BaseControlComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should register a change', () => { + component.registerOnChange('FUNCTION' as unknown as () => void); + expect(component.onChange).toBe('FUNCTION'); + }); + + it('should register it has been touched', () => { + component.registerOnTouched('FUNCTION' as unknown as () => void); + expect(component.onTouched).toBe('FUNCTION'); + }); + + it('should call onChange successfully', () => { + const onChangepy = jest.spyOn(component, 'onChange'); + + component.onChange(null); + + expect(onChangepy).toHaveBeenCalledWith(null); + }); + + it('should call onTouched successfully', () => { + const onTouchedpy = jest.spyOn(component, 'onTouched'); + + component.onTouched(); + + expect(onTouchedpy).toHaveBeenCalled(); + }); + + it('should return disabled', () => { + expect(component.disabled).toBeFalsy(); + }); + + it('should return metadata', () => { + expect(component.meta).toEqual(controlMetaData); + }); + + it('should correctly set focused flag', () => { + component.handleEvent(new Event('focus')); + expect(component.focused).toBeTruthy(); + + component.handleEvent(new Event('blur')); + expect(component.focused).toBeFalsy(); + + const handleEventSpy = jest.spyOn(component, 'handleEvent'); + const state = component.handleEvent(new Event('submit')); + expect(handleEventSpy).toHaveBeenCalled(); + expect(state).toBeNull(); + }); + + describe('interacting with the value', () => { + it('writeValue should set the value', () => { + component.writeValue('anything'); + expect(component.value).toBe('anything'); + }); + + it('set should set the value', () => { + component.value = 'anything'; + expect(component.value).toBe('anything'); + }); + }); + + describe('validation', () => { + it('should get mapped message for first validation error', () => { + component.label = 'Test control'; + component.control?.markAsTouched(); + fixture.detectChanges(); + expect(component.error).toBe('Test control is required'); + }); + + it('should get "" when control is valid', () => { + component.label = 'Test control'; + component.control?.patchValue('test'); + component.control?.markAsTouched(); + fixture.detectChanges(); + expect(component.error).toBe(''); + }); + }); + }); + + describe('does not have control binding', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BaseControlComponent], + imports: [FormsModule], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(BaseControlComponent); + component = fixture.componentInstance; + }); + + it('shoud throw no control binding error', () => { + expect(component).toBeTruthy(); + expect(() => fixture.detectChanges()).toThrow(Error); + }); + + it('should return undefined for metadata', () => { + expect(component.meta).toBeUndefined(); + }); + + it('disabled should default to false', () => { + expect(component.disabled).toBeFalsy(); + }); + }); }); diff --git a/src/app/forms/components/base-control/base-control.component.ts b/src/app/forms/components/base-control/base-control.component.ts index f9fcdfa896..01641e5065 100644 --- a/src/app/forms/components/base-control/base-control.component.ts +++ b/src/app/forms/components/base-control/base-control.component.ts @@ -1,5 +1,11 @@ import { - AfterContentInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, Injector, Input, + AfterContentInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ContentChild, + Injector, + Input, } from '@angular/core'; import { ControlValueAccessor, NgControl } from '@angular/forms'; import { PrefixDirective } from '@forms/directives/prefix.directive'; @@ -10,103 +16,106 @@ import { CustomControl, FormNodeViewTypes, FormNodeWidth } from '../../services/ import { ErrorMessageMap } from '../../utils/error-message-map'; @Component({ - selector: 'app-base-control', - template: '', - styles: [], - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-base-control', + template: '', + styles: [], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class BaseControlComponent implements ControlValueAccessor, AfterContentInit { - @ContentChild(PrefixDirective) prefix?: PrefixDirective; - @ContentChild(SuffixDirective) suffix?: SuffixDirective; - - @Input() name = ''; - @Input() customId?: string; - @Input() hint?: string; - @Input() label?: string; - @Input() width?: FormNodeWidth; - @Input() viewType: FormNodeViewTypes = FormNodeViewTypes.STRING; - @Input() noBottomMargin = false; - @Input() warning?: string | null = null; - - public onChange: (event: unknown) => void = () => {}; - public onTouched = () => {}; - public focused = false; - public errorMessage?: string; - public control?: CustomControl; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - private control_value: any; - - constructor(protected injector: Injector, protected cdr: ChangeDetectorRef) { - this.name = ''; - } - - ngAfterContentInit(): void { - const ngControl: NgControl | null = this.injector.get(NgControl, null); - if (ngControl) { - this.control = ngControl.control as CustomControl; - if (this.control && this.control.meta) { - this.control.meta.changeDetection = this.cdr; - } - } else { - throw new Error(`No control binding for ${this.name}`); - } - } - - get error(): string { - if (this.control?.touched && this.control.invalid) { - const { errors } = this.control; - if (errors) { - const errorList = Object.keys(errors); - const firstError = ErrorMessageMap[errorList[0] as ValidatorNames]; - return this.control.meta.customErrorMessage ?? firstError(errors[errorList[0]], this.label); - } - } - return ''; - } - - get value() { - return this.control_value; - } - - set value(value) { - this.control_value = value; - } - - get disabled() { - return this.control?.disabled ?? false; - } - - get meta() { - return this.control?.meta; - } - - public handleEvent(event: Event) { - switch (event.type) { - case 'focus': - this.focused = true; - return true; - case 'blur': - this.focused = false; - return false; - default: - return null; - } - } - - writeValue(obj: unknown): void { - this.value = obj; - } - - registerOnChange(fn: (event: unknown) => void): void { - this.onChange = fn; - } - - registerOnTouched(fn: () => void): void { - this.onTouched = fn; - } - - trackBy(i: number) { - return i; - } + @ContentChild(PrefixDirective) prefix?: PrefixDirective; + @ContentChild(SuffixDirective) suffix?: SuffixDirective; + + @Input() name = ''; + @Input() customId?: string; + @Input() hint?: string; + @Input() label?: string; + @Input() width?: FormNodeWidth; + @Input() viewType: FormNodeViewTypes = FormNodeViewTypes.STRING; + @Input() noBottomMargin = false; + @Input() warning?: string | null = null; + + public onChange: (event: unknown) => void = () => {}; + public onTouched = () => {}; + public focused = false; + public errorMessage?: string; + public control?: CustomControl; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private control_value: any; + + constructor( + protected injector: Injector, + protected cdr: ChangeDetectorRef + ) { + this.name = ''; + } + + ngAfterContentInit(): void { + const ngControl: NgControl | null = this.injector.get(NgControl, null); + if (ngControl) { + this.control = ngControl.control as CustomControl; + if (this.control && this.control.meta) { + this.control.meta.changeDetection = this.cdr; + } + } else { + throw new Error(`No control binding for ${this.name}`); + } + } + + get error(): string { + if (this.control?.touched && this.control.invalid) { + const { errors } = this.control; + if (errors) { + const errorList = Object.keys(errors); + const firstError = ErrorMessageMap[errorList[0] as ValidatorNames]; + return this.control.meta.customErrorMessage ?? firstError(errors[errorList[0]], this.label); + } + } + return ''; + } + + get value() { + return this.control_value; + } + + set value(value) { + this.control_value = value; + } + + get disabled() { + return this.control?.disabled ?? false; + } + + get meta() { + return this.control?.meta; + } + + public handleEvent(event: Event) { + switch (event.type) { + case 'focus': + this.focused = true; + return true; + case 'blur': + this.focused = false; + return false; + default: + return null; + } + } + + writeValue(obj: unknown): void { + this.value = obj; + } + + registerOnChange(fn: (event: unknown) => void): void { + this.onChange = fn; + } + + registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } + + trackBy(i: number) { + return i; + } } diff --git a/src/app/forms/components/checkbox-group/checkbox-group.component.spec.ts b/src/app/forms/components/checkbox-group/checkbox-group.component.spec.ts index b76049e456..19b676e853 100644 --- a/src/app/forms/components/checkbox-group/checkbox-group.component.spec.ts +++ b/src/app/forms/components/checkbox-group/checkbox-group.component.spec.ts @@ -9,80 +9,80 @@ import { FieldErrorMessageComponent } from '../field-error-message/field-error-m import { CheckboxGroupComponent } from './checkbox-group.component'; @Component({ - selector: 'app-host-component', - template: `
+ selector: 'app-host-component', + template: `
`, - styles: [], + styles: [], }) class HostComponent { - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), - }); - delimited?: { regex: string; separator: string }; - options: MultiOptions = [ - { label: 'Value 1', value: '1' }, - { label: 'Value 2', value: '2' }, - { label: 'Value 3', value: '3' }, - ]; + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), + }); + delimited?: { regex: string; separator: string }; + options: MultiOptions = [ + { label: 'Value 1', value: '1' }, + { label: 'Value 2', value: '2' }, + { label: 'Value 3', value: '3' }, + ]; } describe('CheckboxGroupComponent', () => { - let component: HostComponent; - let fixture: ComponentFixture; + let component: HostComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [HostComponent, CheckboxGroupComponent, BaseControlComponent, FieldErrorMessageComponent], - imports: [FormsModule, ReactiveFormsModule], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [HostComponent, CheckboxGroupComponent, BaseControlComponent, FieldErrorMessageComponent], + imports: [FormsModule, ReactiveFormsModule], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(HostComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(HostComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - describe('value as array', () => { - it('should be propagated from element to the form control', () => { - const foo = component.form.get('foo'); - const boxes = fixture.debugElement.queryAll(By.css('input[type="checkbox"]')); - expect(boxes).toHaveLength(3); + describe('value as array', () => { + it('should be propagated from element to the form control', () => { + const foo = component.form.get('foo'); + const boxes = fixture.debugElement.queryAll(By.css('input[type="checkbox"]')); + expect(boxes).toHaveLength(3); - (boxes[1].nativeElement as HTMLInputElement).click(); - (boxes[0].nativeElement as HTMLInputElement).click(); - expect(foo?.value).toEqual(['2', '1']); - (boxes[1].nativeElement as HTMLInputElement).click(); - (boxes[0].nativeElement as HTMLInputElement).click(); - expect(foo?.value).toBeNull(); - }); - }); + (boxes[1].nativeElement as HTMLInputElement).click(); + (boxes[0].nativeElement as HTMLInputElement).click(); + expect(foo?.value).toEqual(['2', '1']); + (boxes[1].nativeElement as HTMLInputElement).click(); + (boxes[0].nativeElement as HTMLInputElement).click(); + expect(foo?.value).toBeNull(); + }); + }); - describe('value as separated string', () => { - it('should be propagated from element to the form control', () => { - component.delimited = { regex: '\\. (? { + it('should be propagated from element to the form control', () => { + component.delimited = { regex: '\\. (? { - it('should be propagated from the form control to the element', () => { - component.form.patchValue({ foo: ['1', '2'] }); - fixture.detectChanges(); - const checkedBoxes = fixture.debugElement.queryAll(By.css('input[type="checkbox"][checked=true]')); - expect(checkedBoxes).toHaveLength(2); - }); - }); + describe('value propagated to element', () => { + it('should be propagated from the form control to the element', () => { + component.form.patchValue({ foo: ['1', '2'] }); + fixture.detectChanges(); + const checkedBoxes = fixture.debugElement.queryAll(By.css('input[type="checkbox"][checked=true]')); + expect(checkedBoxes).toHaveLength(2); + }); + }); }); diff --git a/src/app/forms/components/checkbox-group/checkbox-group.component.ts b/src/app/forms/components/checkbox-group/checkbox-group.component.ts index 21d57351fc..00c9982fa9 100644 --- a/src/app/forms/components/checkbox-group/checkbox-group.component.ts +++ b/src/app/forms/components/checkbox-group/checkbox-group.component.ts @@ -5,55 +5,56 @@ import { BaseControlComponent } from '../base-control/base-control.component'; type OptionsType = string | number | boolean; @Component({ - selector: 'app-checkbox-group', - templateUrl: './checkbox-group.component.html', - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: CheckboxGroupComponent, - multi: true, - }, - ], + selector: 'app-checkbox-group', + templateUrl: './checkbox-group.component.html', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: CheckboxGroupComponent, + multi: true, + }, + ], }) export class CheckboxGroupComponent extends BaseControlComponent { - @Input() options: FormNodeOption[] = []; - @Input() delimited?: { regex?: string; separator: string }; + @Input() options: FormNodeOption[] = []; + @Input() delimited?: { regex?: string; separator: string }; - isChecked(option: string | number | boolean): boolean { - return this.value && this.value.includes(option); - } + isChecked(option: string | number | boolean): boolean { + return this.value && this.value.includes(option); + } - handleChange(event: boolean, option: FormNodeOption): void { - return event ? this.add(option) : this.remove(option); - } + handleChange(event: boolean, option: FormNodeOption): void { + return event ? this.add(option) : this.remove(option); + } - private add(option: FormNodeOption) { - if (!this.value) { - this.value = this.delimited ? option.value : [option.value]; - } else { - this.value = this.value.concat(this.delimited ? `${this.delimited.separator}${option.value}` : option.value); - } + private add(option: FormNodeOption) { + if (!this.value) { + this.value = this.delimited ? option.value : [option.value]; + } else { + this.value = this.value.concat(this.delimited ? `${this.delimited.separator}${option.value}` : option.value); + } - this.onChange(this.value); - } + this.onChange(this.value); + } - private remove(option: FormNodeOption) { - // eslint-disable-next-line security/detect-non-literal-regexp - const separator = this.delimited && this.delimited?.regex ? new RegExp(this.delimited?.regex) : this.delimited?.separator; + private remove(option: FormNodeOption) { + // eslint-disable-next-line security/detect-non-literal-regexp + const separator = + this.delimited && this.delimited?.regex ? new RegExp(this.delimited?.regex) : this.delimited?.separator; - let newValue = separator ? this.value?.split(separator) : [...this.value]; + let newValue = separator ? this.value?.split(separator) : [...this.value]; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - newValue = newValue?.filter((v: any) => v !== option.value); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + newValue = newValue?.filter((v: any) => v !== option.value); - newValue = separator ? newValue?.join(this.delimited?.separator) : newValue; + newValue = separator ? newValue?.join(this.delimited?.separator) : newValue; - this.value = newValue !== '' && newValue?.length !== 0 ? newValue : null; + this.value = newValue !== '' && newValue?.length !== 0 ? newValue : null; - this.onChange(this.value); - } + this.onChange(this.value); + } - trackByFn(i: number) { - return i; - } + trackByFn(i: number) { + return i; + } } diff --git a/src/app/forms/components/checkbox-group/checkbox-group.stories.ts b/src/app/forms/components/checkbox-group/checkbox-group.stories.ts index 538382ce1a..b63d08bb6e 100644 --- a/src/app/forms/components/checkbox-group/checkbox-group.stories.ts +++ b/src/app/forms/components/checkbox-group/checkbox-group.stories.ts @@ -5,62 +5,62 @@ import { BaseControlComponent } from '../base-control/base-control.component'; import { CheckboxGroupComponent } from './checkbox-group.component'; export default { - title: 'Forms/Checkbox group', - component: CheckboxGroupComponent, - args: { - options: [ - { label: 'Red', value: 'red' }, - { label: 'Green', value: 'green' }, - { label: 'Blue', value: 'blue' } - ] - }, - argTypes: { - label: { - name: 'label', - type: 'string', - description: 'Fieldset label' - } - }, - decorators: [ - moduleMetadata({ - declarations: [CheckboxGroupComponent, BaseControlComponent], - imports: [CommonModule, FormsModule, ReactiveFormsModule] - }) - ] + title: 'Forms/Checkbox group', + component: CheckboxGroupComponent, + args: { + options: [ + { label: 'Red', value: 'red' }, + { label: 'Green', value: 'green' }, + { label: 'Blue', value: 'blue' }, + ], + }, + argTypes: { + label: { + name: 'label', + type: 'string', + description: 'Fieldset label', + }, + }, + decorators: [ + moduleMetadata({ + declarations: [CheckboxGroupComponent, BaseControlComponent], + imports: [CommonModule, FormsModule, ReactiveFormsModule], + }), + ], } as Meta; -const Template: Story = args => { - const { label, options, name, hint, value = [], disabled = false, validators = [] } = args; - const form = new FormGroup({ [name]: new FormControl({ value, disabled }, validators) }); - return { - component: CheckboxGroupComponent, - template: `
{{ form.value | json }}
`, - props: { - form, - label, - name, - options, - hint - } - }; +const Template: Story = (args) => { + const { label, options, name, hint, value = [], disabled = false, validators = [] } = args; + const form = new FormGroup({ [name]: new FormControl({ value, disabled }, validators) }); + return { + component: CheckboxGroupComponent, + template: `
{{ form.value | json }}
`, + props: { + form, + label, + name, + options, + hint, + }, + }; }; export const Enabled = Template.bind({}); Enabled.args = { - label: 'Colors', - name: 'colors' + label: 'Colors', + name: 'colors', }; export const Disabled = Template.bind({}); Disabled.args = { - ...Enabled.args, - disabled: true + ...Enabled.args, + disabled: true, }; export const Invalid = Template.bind({}); Invalid.args = { - ...Enabled.args, - value: ['red'], - hint: 'uncheck "Red" and click outside to see error message.', - validators: [Validators.required] + ...Enabled.args, + value: ['red'], + hint: 'uncheck "Red" and click outside to see error message.', + validators: [Validators.required], }; diff --git a/src/app/forms/components/checkbox/checkbox.component.spec.ts b/src/app/forms/components/checkbox/checkbox.component.spec.ts index 67e56ecd15..4ff559b985 100644 --- a/src/app/forms/components/checkbox/checkbox.component.spec.ts +++ b/src/app/forms/components/checkbox/checkbox.component.spec.ts @@ -5,35 +5,35 @@ import { CustomFormControl, FormNodeTypes } from '@forms/services/dynamic-form.t import { CheckboxComponent } from './checkbox.component'; @Component({ - selector: 'app-host-component', - template: `
+ selector: 'app-host-component', + template: `
`, - styles: [], + styles: [], }) class HostComponent { - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, ''), - }); + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, ''), + }); } describe('CheckboxComponent', () => { - let component: HostComponent; - let fixture: ComponentFixture; + let component: HostComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [CheckboxComponent], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [CheckboxComponent], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(HostComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(HostComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/components/checkbox/checkbox.component.ts b/src/app/forms/components/checkbox/checkbox.component.ts index b14574eb37..2155065234 100644 --- a/src/app/forms/components/checkbox/checkbox.component.ts +++ b/src/app/forms/components/checkbox/checkbox.component.ts @@ -3,8 +3,8 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { BaseControlComponent } from '../base-control/base-control.component'; @Component({ - selector: 'app-checkbox', - templateUrl: './checkbox.component.html', - providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: CheckboxComponent, multi: true }], + selector: 'app-checkbox', + templateUrl: './checkbox.component.html', + providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: CheckboxComponent, multi: true }], }) export class CheckboxComponent extends BaseControlComponent {} diff --git a/src/app/forms/components/contingency-adr-generate-cert/contingency-adr-generate-cert.component.spec.ts b/src/app/forms/components/contingency-adr-generate-cert/contingency-adr-generate-cert.component.spec.ts index d21c7286da..99e8db312e 100644 --- a/src/app/forms/components/contingency-adr-generate-cert/contingency-adr-generate-cert.component.spec.ts +++ b/src/app/forms/components/contingency-adr-generate-cert/contingency-adr-generate-cert.component.spec.ts @@ -14,103 +14,104 @@ import { ReplaySubject, of } from 'rxjs'; import { ContingencyAdrGenerateCertComponent } from './contingency-adr-generate-cert.component'; const mockRecord = { - systemNumber: 'sysNum', - createdTimestamp: 'now', - techRecord_statusCode: 'current', - techRecord_adrPassCertificateDetails: [ - { - createdByName: 'tester', - certificateType: 'pass', - generatedTimestamp: '2025-01-12T10:36:33.987Z', - certificateId: '12345', - }, - { - createdByName: 'tester', - certificateType: 'pass', - generatedTimestamp: '2025-01-14T10:36:33.987Z', - certificateId: '12345', - }, - ], - techRecord_vehicleType: 'hgv', - partialVin: '4321', - vin: '87654321', - techRecord_createdAt: 'now', - techRecord_createdById: 'tester', - techRecord_createdByName: 'tester', - techRecord_reasonForCreation: 'test', - techRecord_recordCompleteness: 'skeleton', - techRecord_vehicleClass_description: 'heavy goods vehicle', - techRecord_bodyType_description: 'box', - primaryVrm: '12345', - + systemNumber: 'sysNum', + createdTimestamp: 'now', + techRecord_statusCode: 'current', + techRecord_adrPassCertificateDetails: [ + { + createdByName: 'tester', + certificateType: 'pass', + generatedTimestamp: '2025-01-12T10:36:33.987Z', + certificateId: '12345', + }, + { + createdByName: 'tester', + certificateType: 'pass', + generatedTimestamp: '2025-01-14T10:36:33.987Z', + certificateId: '12345', + }, + ], + techRecord_vehicleType: 'hgv', + partialVin: '4321', + vin: '87654321', + techRecord_createdAt: 'now', + techRecord_createdById: 'tester', + techRecord_createdByName: 'tester', + techRecord_reasonForCreation: 'test', + techRecord_recordCompleteness: 'skeleton', + techRecord_vehicleClass_description: 'heavy goods vehicle', + techRecord_bodyType_description: 'box', + primaryVrm: '12345', } as unknown as V3TechRecordModel; describe('AdrGenerateCertTestComponent', () => { - let component: ContingencyAdrGenerateCertComponent; - let fixture: ComponentFixture; - let store: Store; - let techRecordService: TechnicalRecordService; - let actions$: ReplaySubject; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ContingencyAdrGenerateCertComponent], - providers: [ - provideMockStore({ initialState: initialAppState }), - { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, - provideMockActions(() => actions$), - TechnicalRecordService, - ], - imports: [HttpClientTestingModule], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }).compileComponents(); - }); - beforeEach(() => { - fixture = TestBed.createComponent(ContingencyAdrGenerateCertComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - store = TestBed.inject(Store); - techRecordService = TestBed.inject(TechnicalRecordService); - fixture = TestBed.createComponent(ContingencyAdrGenerateCertComponent); - component = fixture.componentInstance; - }); + let component: ContingencyAdrGenerateCertComponent; + let fixture: ComponentFixture; + let store: Store; + let techRecordService: TechnicalRecordService; + let actions$: ReplaySubject; + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ContingencyAdrGenerateCertComponent], + providers: [ + provideMockStore({ initialState: initialAppState }), + { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, + provideMockActions(() => actions$), + TechnicalRecordService, + ], + imports: [HttpClientTestingModule], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + }).compileComponents(); + }); + beforeEach(() => { + fixture = TestBed.createComponent(ContingencyAdrGenerateCertComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + store = TestBed.inject(Store); + techRecordService = TestBed.inject(TechnicalRecordService); + fixture = TestBed.createComponent(ContingencyAdrGenerateCertComponent); + component = fixture.componentInstance; + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - describe('lastCertificateDate', () => { - it('should return the most recent certificate date generation date', () => { - jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue(of(mockRecord)); - expect(component.lastCertificateDate).toBe('An ADR certificate was last generated on 14/01/2025'); - }); - it('should return a default string if there are no ADR certificates on a record', () => { - const newMock = { ...mockRecord, techRecord_adrPassCertificateDetails: [] }; - jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue(of(newMock)); - expect(component.lastCertificateDate).toBe('There are no previous ADR certificates for this vehicle'); - }); - }); + describe('lastCertificateDate', () => { + it('should return the most recent certificate date generation date', () => { + jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue(of(mockRecord)); + expect(component.lastCertificateDate).toBe('An ADR certificate was last generated on 14/01/2025'); + }); + it('should return a default string if there are no ADR certificates on a record', () => { + const newMock = { ...mockRecord, techRecord_adrPassCertificateDetails: [] }; + jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue(of(newMock)); + expect(component.lastCertificateDate).toBe('There are no previous ADR certificates for this vehicle'); + }); + }); - describe('documentParams', () => { - it('should return a map in correct format', () => { - expect(component.documentParams('testFileName')).toEqual(new Map([['fileName', 'testFileName']])); - }); - }); + describe('documentParams', () => { + it('should return a map in correct format', () => { + expect(component.documentParams('testFileName')).toEqual(new Map([['fileName', 'testFileName']])); + }); + }); - describe('handleSubmit', () => { - beforeEach(() => { - jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue(of(mockRecord)); - }); - it('should dispatch the correct action with correct params', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.ngOnInit(); - component.handleSubmit(); + describe('handleSubmit', () => { + beforeEach(() => { + jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue(of(mockRecord)); + }); + it('should dispatch the correct action with correct params', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.ngOnInit(); + component.handleSubmit(); - expect(dispatchSpy).toHaveBeenCalled(); - expect(dispatchSpy).toHaveBeenCalledWith(generateADRCertificate({ - systemNumber: 'sysNum', - createdTimestamp: 'now', - certificateType: 'PASS', - })); - }); - }); + expect(dispatchSpy).toHaveBeenCalled(); + expect(dispatchSpy).toHaveBeenCalledWith( + generateADRCertificate({ + systemNumber: 'sysNum', + createdTimestamp: 'now', + certificateType: 'PASS', + }) + ); + }); + }); }); diff --git a/src/app/forms/components/contingency-adr-generate-cert/contingency-adr-generate-cert.component.ts b/src/app/forms/components/contingency-adr-generate-cert/contingency-adr-generate-cert.component.ts index a2ce418825..dd8bbf11ed 100644 --- a/src/app/forms/components/contingency-adr-generate-cert/contingency-adr-generate-cert.component.ts +++ b/src/app/forms/components/contingency-adr-generate-cert/contingency-adr-generate-cert.component.ts @@ -1,9 +1,9 @@ -import { - Component, - inject, -} from '@angular/core'; +import { Component, inject } from '@angular/core'; import { ADRCertificateDetails } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/trl/complete'; -import { TechRecordGETHGV, TechRecordGETTRL } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb-vehicle-type'; +import { + TechRecordGETHGV, + TechRecordGETTRL, +} from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb-vehicle-type'; import { CustomFormControlComponent } from '@forms/custom-sections/custom-form-control/custom-form-control.component'; import { Actions, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; @@ -12,73 +12,74 @@ import { TechnicalRecordService } from '@services/technical-record/technical-rec import { State } from '@store/index'; import { retryInterceptorFailure } from '@store/retry-interceptor/actions/retry-interceptor.actions'; import { generateADRCertificate, generateADRCertificateSuccess } from '@store/technical-records'; -import { - Subject, - take, - takeUntil, -} from 'rxjs'; +import { Subject, take, takeUntil } from 'rxjs'; @Component({ - selector: 'app-contingency-adr-generate-cert', - templateUrl: './contingency-adr-generate-cert.component.html', - styleUrls: ['./contingency-adr-generate-cert.component.scss'], + selector: 'app-contingency-adr-generate-cert', + templateUrl: './contingency-adr-generate-cert.component.html', + styleUrls: ['./contingency-adr-generate-cert.component.scss'], }) export class ContingencyAdrGenerateCertComponent extends CustomFormControlComponent { - systemNumber?: string; - createdTimestamp?: string; - store = inject(Store); - techRecordService = inject(TechnicalRecordService); - actions$ = inject(Actions); - loading = inject(LoadingService); - fileName?: string; - errorString?: string | null; + systemNumber?: string; + createdTimestamp?: string; + store = inject(Store); + techRecordService = inject(TechnicalRecordService); + actions$ = inject(Actions); + loading = inject(LoadingService); + fileName?: string; + errorString?: string | null; - private destroy$ = new Subject(); + private destroy$ = new Subject(); - ngOnInit(): void { - this.techRecordService.techRecord$.pipe(takeUntil(this.destroy$)).subscribe((record) => { - this.systemNumber = (record as TechRecordGETHGV).systemNumber; - this.createdTimestamp = (record as TechRecordGETHGV).createdTimestamp; - }); + ngOnInit(): void { + this.techRecordService.techRecord$.pipe(takeUntil(this.destroy$)).subscribe((record) => { + this.systemNumber = (record as TechRecordGETHGV).systemNumber; + this.createdTimestamp = (record as TechRecordGETHGV).createdTimestamp; + }); - this.actions$.pipe(ofType(generateADRCertificateSuccess), takeUntil(this.destroy$)).subscribe(({ id }) => { - this.fileName = id; - this.cdr.detectChanges(); - }); + this.actions$.pipe(ofType(generateADRCertificateSuccess), takeUntil(this.destroy$)).subscribe(({ id }) => { + this.fileName = id; + this.cdr.detectChanges(); + }); - this.actions$.pipe(ofType(retryInterceptorFailure), takeUntil(this.destroy$)).subscribe(() => { - this.errorString = 'Try link again or Enter 000000 in Certificate Number and then press "Pass And Issue Documents Centrally" on TAS'; - this.cdr.detectChanges(); - }); - } + this.actions$.pipe(ofType(retryInterceptorFailure), takeUntil(this.destroy$)).subscribe(() => { + this.errorString = + 'Try link again or Enter 000000 in Certificate Number and then press "Pass And Issue Documents Centrally" on TAS'; + this.cdr.detectChanges(); + }); + } - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } - get lastCertificateDate() { - let sortedTests: ADRCertificateDetails[] | undefined; - this.techRecordService.techRecord$.pipe(take(1)).subscribe((record) => { - sortedTests = (record as TechRecordGETHGV | TechRecordGETTRL).techRecord_adrPassCertificateDetails?.sort((a, b) => - a.generatedTimestamp && b.generatedTimestamp ? new Date(b.generatedTimestamp).getTime() - new Date(a.generatedTimestamp).getTime() : 0); - }); - return (sortedTests && sortedTests?.length > 0) - ? `An ADR certificate was last generated on ${new Date(sortedTests[0].generatedTimestamp).toLocaleDateString('en-UK')}` - : 'There are no previous ADR certificates for this vehicle'; - } + get lastCertificateDate() { + let sortedTests: ADRCertificateDetails[] | undefined; + this.techRecordService.techRecord$.pipe(take(1)).subscribe((record) => { + sortedTests = (record as TechRecordGETHGV | TechRecordGETTRL).techRecord_adrPassCertificateDetails?.sort( + (a, b) => + a.generatedTimestamp && b.generatedTimestamp + ? new Date(b.generatedTimestamp).getTime() - new Date(a.generatedTimestamp).getTime() + : 0 + ); + }); + return sortedTests && sortedTests?.length > 0 + ? `An ADR certificate was last generated on ${new Date(sortedTests[0].generatedTimestamp).toLocaleDateString('en-UK')}` + : 'There are no previous ADR certificates for this vehicle'; + } - documentParams(certificate: string): Map { - return new Map([['fileName', certificate]]); - } + documentParams(certificate: string): Map { + return new Map([['fileName', certificate]]); + } - handleSubmit(): void { - this.store.dispatch(generateADRCertificate( - { - systemNumber: this.systemNumber ?? '', - createdTimestamp: this.createdTimestamp ?? '', - certificateType: 'PASS', - }, - )); - } + handleSubmit(): void { + this.store.dispatch( + generateADRCertificate({ + systemNumber: this.systemNumber ?? '', + createdTimestamp: this.createdTimestamp ?? '', + certificateType: 'PASS', + }) + ); + } } diff --git a/src/app/forms/components/date/date.component.spec.ts b/src/app/forms/components/date/date.component.spec.ts index b4d4dccbe1..fdc68ba2d5 100644 --- a/src/app/forms/components/date/date.component.spec.ts +++ b/src/app/forms/components/date/date.component.spec.ts @@ -1,8 +1,6 @@ /* eslint-disable jest/no-conditional-expect */ import { Component, ViewChild } from '@angular/core'; -import { - ComponentFixture, TestBed, fakeAsync, tick, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { CustomFormControl, FormNodeTypes } from '@forms/services/dynamic-form.types'; @@ -14,170 +12,188 @@ import { DateComponent } from './date.component'; import { FocusNextDirective } from './focus-next.directive'; @Component({ - selector: 'app-host-component', - template: `
+ selector: 'app-host-component', + template: `
`, - styles: [], + styles: [], }) class HostComponent { - @ViewChild(DateComponent, { static: true }) dateComponent?: DateComponent; - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), - }); + @ViewChild(DateComponent, { static: true }) dateComponent?: DateComponent; + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), + }); } describe('DateComponent', () => { - let component: HostComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [BaseControlComponent, DateComponent, FieldErrorMessageComponent, FocusNextDirective, HostComponent], - imports: [FormsModule, ReactiveFormsModule], - providers: [GlobalErrorService, provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(HostComponent); - component = fixture.componentInstance; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should add validators', () => { - const addValidatorsSpy = jest.spyOn(component.dateComponent as DateComponent, 'addValidators'); - fixture.detectChanges(); - - expect(addValidatorsSpy).toHaveBeenCalledTimes(1); - }); - - describe('control values', () => { - it.each([ - ['2342346-6213-234T00:00:00.000', 2342346, 6213, 234, 1, 6], - ['2022-01-12T00:00:00.000', 2022, 0o1, 12, 1, 6], - ['2022--01T00:00:00.000', 2022, NaN, 0o1, 0o1, 0o1], - ['2022-01-T00:00:00.000', 2022, 0o1, NaN, 0o1, 0o1], - ['2022-02-01T13:45:00.000', 2022, 2, 0o1, 13, 45, true], - ['-01-01T01:01:00.000', NaN, 0o1, 0o1, 0o1, 0o1, true], - [undefined, undefined, undefined, undefined, undefined, undefined, true], - ])( - 'should be %s for %d, %d, %d, %d, %d', - ( - expected: string | undefined, - year: number | undefined, - month: number | undefined, - day: number | undefined, - hour: number | undefined, - minute: number | undefined, - displayTime = false, - ) => { - if (component.dateComponent) { - component.dateComponent.originalDate = '2022-01-01T01:06:00.000'; - component.dateComponent.displayTime = displayTime; - } - - fixture.detectChanges(); - - component.dateComponent?.onDayChange(day); - component.dateComponent?.onMonthChange(month); - component.dateComponent?.onYearChange(year); - component.dateComponent?.onHourChange(hour); - component.dateComponent?.onMinuteChange(minute); - if (expected === undefined) { - expect(component.form.get('foo')?.value).toBeNull(); - } else { - expect((component.form.get('foo')?.value as Date).toString()).toEqual(expected.toString()); - } - }, - ); - - it.each([ - ['2342346-6213-234', 2342346, 6213, 234, 1, 6], - ['2022-01-12', 2022, 0o1, 12, 1, 6], - ['2022--01', 2022, NaN, 0o1, 0o1, 0o1], - ['2022-01-', 2022, 0o1, NaN, 0o1, 0o1], - ['2022-02-01', 2022, 2, 0o1, 13, 45, true], - ['-01-01', NaN, 0o1, 0o1, 0o1, 0o1, true], - [undefined, undefined, undefined, undefined, undefined, undefined, true], - ])( - 'should be %s for %d, %d, %d, %d, %d', - ( - expected: string | undefined, - year: number | undefined, - month: number | undefined, - day: number | undefined, - hour: number | undefined, - minute: number | undefined, - displayTime = false, - ) => { - if (component.dateComponent) { - component.dateComponent.originalDate = '2022-01-01T01:06:00.000'; - component.dateComponent.displayTime = displayTime; - component.dateComponent.isoDate = false; - } - - fixture.detectChanges(); - - component.dateComponent?.onDayChange(day); - component.dateComponent?.onMonthChange(month); - component.dateComponent?.onYearChange(year); - component.dateComponent?.onHourChange(hour); - component.dateComponent?.onMinuteChange(minute); - if (expected === undefined) { - expect(component.form.get('foo')?.value).toBeNull(); - } else { - expect((component.form.get('foo')?.value as Date).toString()).toEqual(expected.toString()); - } - }, - ); - - it('should propagate control value to subjects', fakeAsync(() => { - const date = new Date('1995-12-17T03:24:00'); - component.dateComponent?.control?.patchValue(date.toISOString()); - - component.dateComponent?.valueWriteBack(date.toISOString()); - - tick(); - component.dateComponent?.control?.meta.changeDetection?.detectChanges(); - - expect(component.dateComponent?.day).toEqual(date.getDate()); - expect(component.dateComponent?.month).toEqual(date.getMonth() + 1); - expect(component.dateComponent?.year).toEqual(date.getFullYear()); - expect(component.dateComponent?.hour).toEqual(date.getUTCHours()); - expect(component.dateComponent?.minute).toEqual(date.getUTCMinutes()); - })); - }); - - describe('error handling', () => { - it('should return empty if the day, month and year are not defined', () => { - if (component.dateComponent) { - component.dateComponent.errors = { error: true, date: new Date(), errors: [{ error: false, reason: 'foo', index: 1 }] }; - } - expect(component.dateComponent?.elementHasErrors(1)).toBe(false); - }); - - it('should return true if there are some errors with the same index', () => { - if (component.dateComponent) { - component.dateComponent.day = 2; - component.dateComponent.year = 2021; - component.dateComponent.month = 2; - component.dateComponent.errors = { error: true, date: new Date(), errors: [{ error: false, reason: 'foo', index: 1 }] }; - } - expect(component.dateComponent?.elementHasErrors(1)).toBe(true); - }); - - it('should return false if there are no errors with the same index', () => { - if (component.dateComponent) { - component.dateComponent.day = 2; - component.dateComponent.year = 2021; - component.dateComponent.month = 2; - component.dateComponent.errors = { error: true, date: new Date(), errors: [{ error: false, reason: 'foo', index: 1 }] }; - } - expect(component.dateComponent?.elementHasErrors(2)).toBe(false); - }); - }); + let component: HostComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + BaseControlComponent, + DateComponent, + FieldErrorMessageComponent, + FocusNextDirective, + HostComponent, + ], + imports: [FormsModule, ReactiveFormsModule], + providers: [GlobalErrorService, provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(HostComponent); + component = fixture.componentInstance; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should add validators', () => { + const addValidatorsSpy = jest.spyOn(component.dateComponent as DateComponent, 'addValidators'); + fixture.detectChanges(); + + expect(addValidatorsSpy).toHaveBeenCalledTimes(1); + }); + + describe('control values', () => { + it.each([ + ['2342346-6213-234T00:00:00.000', 2342346, 6213, 234, 1, 6], + ['2022-01-12T00:00:00.000', 2022, 0o1, 12, 1, 6], + ['2022--01T00:00:00.000', 2022, Number.NaN, 0o1, 0o1, 0o1], + ['2022-01-T00:00:00.000', 2022, 0o1, Number.NaN, 0o1, 0o1], + ['2022-02-01T13:45:00.000', 2022, 2, 0o1, 13, 45, true], + ['-01-01T01:01:00.000', Number.NaN, 0o1, 0o1, 0o1, 0o1, true], + [undefined, undefined, undefined, undefined, undefined, undefined, true], + ])( + 'should be %s for %d, %d, %d, %d, %d', + ( + expected: string | undefined, + year: number | undefined, + month: number | undefined, + day: number | undefined, + hour: number | undefined, + minute: number | undefined, + displayTime = false + ) => { + if (component.dateComponent) { + component.dateComponent.originalDate = '2022-01-01T01:06:00.000'; + component.dateComponent.displayTime = displayTime; + } + + fixture.detectChanges(); + + component.dateComponent?.onDayChange(day); + component.dateComponent?.onMonthChange(month); + component.dateComponent?.onYearChange(year); + component.dateComponent?.onHourChange(hour); + component.dateComponent?.onMinuteChange(minute); + if (expected === undefined) { + expect(component.form.get('foo')?.value).toBeNull(); + } else { + expect((component.form.get('foo')?.value as Date).toString()).toEqual(expected.toString()); + } + } + ); + + it.each([ + ['2342346-6213-234', 2342346, 6213, 234, 1, 6], + ['2022-01-12', 2022, 0o1, 12, 1, 6], + ['2022--01', 2022, Number.NaN, 0o1, 0o1, 0o1], + ['2022-01-', 2022, 0o1, Number.NaN, 0o1, 0o1], + ['2022-02-01', 2022, 2, 0o1, 13, 45, true], + ['-01-01', Number.NaN, 0o1, 0o1, 0o1, 0o1, true], + [undefined, undefined, undefined, undefined, undefined, undefined, true], + ])( + 'should be %s for %d, %d, %d, %d, %d', + ( + expected: string | undefined, + year: number | undefined, + month: number | undefined, + day: number | undefined, + hour: number | undefined, + minute: number | undefined, + displayTime = false + ) => { + if (component.dateComponent) { + component.dateComponent.originalDate = '2022-01-01T01:06:00.000'; + component.dateComponent.displayTime = displayTime; + component.dateComponent.isoDate = false; + } + + fixture.detectChanges(); + + component.dateComponent?.onDayChange(day); + component.dateComponent?.onMonthChange(month); + component.dateComponent?.onYearChange(year); + component.dateComponent?.onHourChange(hour); + component.dateComponent?.onMinuteChange(minute); + if (expected === undefined) { + expect(component.form.get('foo')?.value).toBeNull(); + } else { + expect((component.form.get('foo')?.value as Date).toString()).toEqual(expected.toString()); + } + } + ); + + it('should propagate control value to subjects', fakeAsync(() => { + const date = new Date('1995-12-17T03:24:00'); + component.dateComponent?.control?.patchValue(date.toISOString()); + + component.dateComponent?.valueWriteBack(date.toISOString()); + + tick(); + component.dateComponent?.control?.meta.changeDetection?.detectChanges(); + + expect(component.dateComponent?.day).toEqual(date.getDate()); + expect(component.dateComponent?.month).toEqual(date.getMonth() + 1); + expect(component.dateComponent?.year).toEqual(date.getFullYear()); + expect(component.dateComponent?.hour).toEqual(date.getUTCHours()); + expect(component.dateComponent?.minute).toEqual(date.getUTCMinutes()); + })); + }); + + describe('error handling', () => { + it('should return empty if the day, month and year are not defined', () => { + if (component.dateComponent) { + component.dateComponent.errors = { + error: true, + date: new Date(), + errors: [{ error: false, reason: 'foo', index: 1 }], + }; + } + expect(component.dateComponent?.elementHasErrors(1)).toBe(false); + }); + + it('should return true if there are some errors with the same index', () => { + if (component.dateComponent) { + component.dateComponent.day = 2; + component.dateComponent.year = 2021; + component.dateComponent.month = 2; + component.dateComponent.errors = { + error: true, + date: new Date(), + errors: [{ error: false, reason: 'foo', index: 1 }], + }; + } + expect(component.dateComponent?.elementHasErrors(1)).toBe(true); + }); + + it('should return false if there are no errors with the same index', () => { + if (component.dateComponent) { + component.dateComponent.day = 2; + component.dateComponent.year = 2021; + component.dateComponent.month = 2; + component.dateComponent.errors = { + error: true, + date: new Date(), + errors: [{ error: false, reason: 'foo', index: 1 }], + }; + } + expect(component.dateComponent?.elementHasErrors(2)).toBe(false); + }); + }); }); diff --git a/src/app/forms/components/date/date.component.ts b/src/app/forms/components/date/date.component.ts index 408a6ef7f7..e686f2ce2c 100644 --- a/src/app/forms/components/date/date.component.ts +++ b/src/app/forms/components/date/date.component.ts @@ -1,210 +1,222 @@ /* eslint-disable no-underscore-dangle */ import { - AfterContentInit, ChangeDetectorRef, Component, EventEmitter, Injector, Input, OnDestroy, OnInit, Output, ViewChild, + AfterContentInit, + ChangeDetectorRef, + Component, + EventEmitter, + Injector, + Input, + OnDestroy, + OnInit, + Output, + ViewChild, } from '@angular/core'; import { AbstractControlDirective, NG_VALUE_ACCESSOR } from '@angular/forms'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { ValidatorNames } from '@forms/models/validators.enum'; -import { - BehaviorSubject, Observable, Subscription, combineLatest, -} from 'rxjs'; +import { BehaviorSubject, Observable, Subscription, combineLatest } from 'rxjs'; import validateDate from 'validate-govuk-date'; import { DateValidators } from '../../validators/date/date.validators'; import { BaseControlComponent } from '../base-control/base-control.component'; type Segments = { - day: Observable; - month: Observable; - year: Observable; - hour?: Observable; - minute?: Observable; + day: Observable; + month: Observable; + year: Observable; + hour?: Observable; + minute?: Observable; }; @Component({ - selector: 'app-date', - templateUrl: './date.component.html', - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: DateComponent, - multi: true, - }, - ], + selector: 'app-date', + templateUrl: './date.component.html', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: DateComponent, + multi: true, + }, + ], }) export class DateComponent extends BaseControlComponent implements OnInit, OnDestroy, AfterContentInit { - @Input() displayTime = false; - @Input() isoDate = true; - @Input() customError? = false; - @ViewChild('dayModel') dayModel?: AbstractControlDirective; - @Output() blur = new EventEmitter(); - - private day_: BehaviorSubject = new BehaviorSubject(undefined); - private month_: BehaviorSubject = new BehaviorSubject(undefined); - private year_: BehaviorSubject = new BehaviorSubject(undefined); - private hour_: BehaviorSubject = new BehaviorSubject(undefined); - private minute_: BehaviorSubject = new BehaviorSubject(undefined); - private day$: Observable; - private month$: Observable; - private year$: Observable; - private hour$: Observable; - private minute$: Observable; - private subscriptions: Array = []; - public originalDate = ''; - public errors?: { error: boolean; date?: Date; errors?: { error: boolean; reason: string; index: number }[] }; - private dateFieldOrDefault?: Record<'hours' | 'minutes' | 'seconds', string | number>; - protected formSubmitted? = false; - - public day?: number; - public month?: number; - public year?: number; - public hour?: number; - public minute?: number; - - dayId = ''; - monthId = ''; - yearId = ''; - - constructor(injector: Injector, changeDetectorRef: ChangeDetectorRef, public globalErrorService: GlobalErrorService) { - super(injector, changeDetectorRef); - this.day$ = this.day_.asObservable(); - this.month$ = this.month_.asObservable(); - this.year$ = this.year_.asObservable(); - this.hour$ = this.hour_.asObservable(); - this.minute$ = this.minute_.asObservable(); - this.globalErrorService.errors$.subscribe((globalErrors) => { - if (globalErrors.length) { - this.formSubmitted = true; - } - }); - } - - ngOnInit(): void { - this.subscriptions.push(this.subscribeAndPropagateChanges()); - this.dayId = `${this.customId ?? this.name}-day`; - this.monthId = `${this.customId ?? this.name}-month`; - this.yearId = `${this.customId ?? this.name}-year`; - } - - override ngAfterContentInit(): void { - super.ngAfterContentInit(); - this.originalDate = this.value; - this.dateFieldOrDefault = { - hours: this.originalDate ? new Date(this.originalDate).getHours() : '00', - minutes: this.originalDate ? new Date(this.originalDate).getMinutes() : '00', - seconds: this.originalDate ? new Date(this.originalDate).getSeconds() : '00', - }; - this.addValidators(); - this.valueWriteBack(this.value); - } - - ngOnDestroy(): void { - this.subscriptions.forEach((s) => s && s.unsubscribe()); - } - - onDayChange(event: number | undefined) { - this.day_.next(event); - } - - onMonthChange(event: number | undefined) { - this.month_.next(event); - } - - onYearChange(event: number | undefined) { - this.year_.next(event); - } - - onHourChange(event: number | undefined) { - this.hour_.next(event); - } - - onMinuteChange(event: number | undefined) { - this.minute_.next(event); - } - - valueWriteBack(value: string | null): void { - if (value && typeof value === 'string') { - const date = new Date(value); - this.day = date.getDate(); - this.day_.next(this.day); - this.month = date.getMonth() + 1; - this.month_.next(this.month); - this.year = date.getFullYear(); - this.year_.next(this.year); - this.hour = date.getHours(); - this.hour_.next(this.hour); - this.minute = date.getMinutes(); - this.minute_.next(this.minute); - } - } - - /** - * Subscribes to all date segments and propagates value as `Date`. - * @returns Subscription - */ - subscribeAndPropagateChanges() { - const dateFields: Segments = this.displayTime - ? { - day: this.day$, - month: this.month$, - year: this.year$, - hour: this.hour$, - minute: this.minute$, - } - : { day: this.day$, month: this.month$, year: this.year$ }; - return combineLatest(dateFields).subscribe({ - next: ({ - day, month, year, hour, minute, - }) => { - if (!day && !month && !year && !hour && !minute) { - this.onChange(null); - return; - } - hour = this.displayTime ? hour : this.dateFieldOrDefault?.hours; - minute = this.displayTime ? minute : this.dateFieldOrDefault?.minutes; - const second = this.dateFieldOrDefault?.seconds; - this.onChange(this.processDate(year, month, day, hour, minute, second)); - }, - }); - } - - processDate( - year: number | string | undefined, - month: number | string | undefined, - day: number | string | undefined, - hour: number | string | undefined, - minute: number | string | undefined, - second: number | string | undefined, - ) { - if (this.isoDate) { - return `${year || ''}-${this.padded(month)}-${this.padded(day)}T${this.padded(hour)}:${this.padded(minute)}:${this.padded(second)}.000`; - } - return `${year || ''}-${this.padded(month)}-${this.padded(day)}`; - } - - padded(n: number | string | undefined, l = 2) { - return n != null && !Number.isNaN(+n) ? String(n).padStart(l, '0') || '' : ''; - } - - /** - * Note: This function is not testable because `validDate` returns a reference that can't be compared to in spec file with `hasValidator` function. - */ - addValidators() { - this.control?.addValidators([DateValidators.validDate(this.displayTime, this.label)]); - this.control?.meta.validators?.push({ name: ValidatorNames.Custom, args: DateValidators.validDate(this.displayTime, this.label) }); - } - - validate() { - this.errors = validateDate(this.day || '', this.month || '', this.year || '', this.label); - } - - elementHasErrors(i: number) { - return this.day || this.month || this.year ? this.errors?.errors?.some((e) => e.index === i) : false; - } - - getId(name: string) { - const id = `${name}-day`; - if (this.control) { - this.control.meta.customId = id; - } - return id; - } + @Input() displayTime = false; + @Input() isoDate = true; + @Input() customError? = false; + @ViewChild('dayModel') dayModel?: AbstractControlDirective; + @Output() blur = new EventEmitter(); + + private day_: BehaviorSubject = new BehaviorSubject(undefined); + private month_: BehaviorSubject = new BehaviorSubject(undefined); + private year_: BehaviorSubject = new BehaviorSubject(undefined); + private hour_: BehaviorSubject = new BehaviorSubject(undefined); + private minute_: BehaviorSubject = new BehaviorSubject(undefined); + private day$: Observable; + private month$: Observable; + private year$: Observable; + private hour$: Observable; + private minute$: Observable; + private subscriptions: Array = []; + public originalDate = ''; + public errors?: { error: boolean; date?: Date; errors?: { error: boolean; reason: string; index: number }[] }; + private dateFieldOrDefault?: Record<'hours' | 'minutes' | 'seconds', string | number>; + protected formSubmitted? = false; + + public day?: number; + public month?: number; + public year?: number; + public hour?: number; + public minute?: number; + + dayId = ''; + monthId = ''; + yearId = ''; + + constructor( + injector: Injector, + changeDetectorRef: ChangeDetectorRef, + public globalErrorService: GlobalErrorService + ) { + super(injector, changeDetectorRef); + this.day$ = this.day_.asObservable(); + this.month$ = this.month_.asObservable(); + this.year$ = this.year_.asObservable(); + this.hour$ = this.hour_.asObservable(); + this.minute$ = this.minute_.asObservable(); + this.globalErrorService.errors$.subscribe((globalErrors) => { + if (globalErrors.length) { + this.formSubmitted = true; + } + }); + } + + ngOnInit(): void { + this.subscriptions.push(this.subscribeAndPropagateChanges()); + this.dayId = `${this.customId ?? this.name}-day`; + this.monthId = `${this.customId ?? this.name}-month`; + this.yearId = `${this.customId ?? this.name}-year`; + } + + override ngAfterContentInit(): void { + super.ngAfterContentInit(); + this.originalDate = this.value; + this.dateFieldOrDefault = { + hours: this.originalDate ? new Date(this.originalDate).getHours() : '00', + minutes: this.originalDate ? new Date(this.originalDate).getMinutes() : '00', + seconds: this.originalDate ? new Date(this.originalDate).getSeconds() : '00', + }; + this.addValidators(); + this.valueWriteBack(this.value); + } + + ngOnDestroy(): void { + this.subscriptions.forEach((s) => s && s.unsubscribe()); + } + + onDayChange(event: number | undefined) { + this.day_.next(event); + } + + onMonthChange(event: number | undefined) { + this.month_.next(event); + } + + onYearChange(event: number | undefined) { + this.year_.next(event); + } + + onHourChange(event: number | undefined) { + this.hour_.next(event); + } + + onMinuteChange(event: number | undefined) { + this.minute_.next(event); + } + + valueWriteBack(value: string | null): void { + if (value && typeof value === 'string') { + const date = new Date(value); + this.day = date.getDate(); + this.day_.next(this.day); + this.month = date.getMonth() + 1; + this.month_.next(this.month); + this.year = date.getFullYear(); + this.year_.next(this.year); + this.hour = date.getHours(); + this.hour_.next(this.hour); + this.minute = date.getMinutes(); + this.minute_.next(this.minute); + } + } + + /** + * Subscribes to all date segments and propagates value as `Date`. + * @returns Subscription + */ + subscribeAndPropagateChanges() { + const dateFields: Segments = this.displayTime + ? { + day: this.day$, + month: this.month$, + year: this.year$, + hour: this.hour$, + minute: this.minute$, + } + : { day: this.day$, month: this.month$, year: this.year$ }; + return combineLatest(dateFields).subscribe({ + next: ({ day, month, year, hour, minute }) => { + if (!day && !month && !year && !hour && !minute) { + this.onChange(null); + return; + } + hour = this.displayTime ? hour : this.dateFieldOrDefault?.hours; + minute = this.displayTime ? minute : this.dateFieldOrDefault?.minutes; + const second = this.dateFieldOrDefault?.seconds; + this.onChange(this.processDate(year, month, day, hour, minute, second)); + }, + }); + } + + processDate( + year: number | string | undefined, + month: number | string | undefined, + day: number | string | undefined, + hour: number | string | undefined, + minute: number | string | undefined, + second: number | string | undefined + ) { + if (this.isoDate) { + return `${year || ''}-${this.padded(month)}-${this.padded(day)}T${this.padded(hour)}:${this.padded(minute)}:${this.padded(second)}.000`; + } + return `${year || ''}-${this.padded(month)}-${this.padded(day)}`; + } + + padded(n: number | string | undefined, l = 2) { + return n != null && !Number.isNaN(+n) ? String(n).padStart(l, '0') || '' : ''; + } + + /** + * Note: This function is not testable because `validDate` returns a reference that can't be compared to in spec file with `hasValidator` function. + */ + addValidators() { + this.control?.addValidators([DateValidators.validDate(this.displayTime, this.label)]); + this.control?.meta.validators?.push({ + name: ValidatorNames.Custom, + args: DateValidators.validDate(this.displayTime, this.label), + }); + } + + validate() { + this.errors = validateDate(this.day || '', this.month || '', this.year || '', this.label); + } + + elementHasErrors(i: number) { + return this.day || this.month || this.year ? this.errors?.errors?.some((e) => e.index === i) : false; + } + + getId(name: string) { + const id = `${name}-day`; + if (this.control) { + this.control.meta.customId = id; + } + return id; + } } diff --git a/src/app/forms/components/date/focus-next.directive.spec.ts b/src/app/forms/components/date/focus-next.directive.spec.ts index 3d965c28ab..f66abf041a 100644 --- a/src/app/forms/components/date/focus-next.directive.spec.ts +++ b/src/app/forms/components/date/focus-next.directive.spec.ts @@ -4,8 +4,8 @@ import { By } from '@angular/platform-browser'; import { FocusNextDirective } from './focus-next.directive'; @Component({ - selector: 'app-test', - template: ` + selector: 'app-test', + template: `
@@ -16,76 +16,76 @@ import { FocusNextDirective } from './focus-next.directive'; `, }) class TestComponent { - displayTime = false; + displayTime = false; } describe('FocusNextDirective', () => { - let component: TestComponent; - let fixture: ComponentFixture; - let de: DebugElement; + let component: TestComponent; + let fixture: ComponentFixture; + let de: DebugElement; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TestComponent, FocusNextDirective], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TestComponent, FocusNextDirective], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TestComponent); - component = fixture.componentInstance; - de = fixture.debugElement; - }); + beforeEach(() => { + fixture = TestBed.createComponent(TestComponent); + component = fixture.componentInstance; + de = fixture.debugElement; + }); - it('should create an instance', () => { - expect(component).toBeDefined(); - }); + it('should create an instance', () => { + expect(component).toBeDefined(); + }); - it('should tab from day to month after two numbers', () => { - const day: HTMLInputElement = fixture.debugElement.query(By.css('#test-day')).nativeElement; - const month: HTMLInputElement = fixture.debugElement.query(By.css('#test-month')).nativeElement; - day.value = '01'; - day.dispatchEvent(new Event('input')); - fixture.detectChanges(); - const focusedElement = de.query(By.css(':focus')).nativeElement; - expect(month).toBe(focusedElement); - }); + it('should tab from day to month after two numbers', () => { + const day: HTMLInputElement = fixture.debugElement.query(By.css('#test-day')).nativeElement; + const month: HTMLInputElement = fixture.debugElement.query(By.css('#test-month')).nativeElement; + day.value = '01'; + day.dispatchEvent(new Event('input')); + fixture.detectChanges(); + const focusedElement = de.query(By.css(':focus')).nativeElement; + expect(month).toBe(focusedElement); + }); - it('should tab from month to year after two numbers', () => { - const month: HTMLInputElement = fixture.debugElement.query(By.css('#test-month')).nativeElement; - const year: HTMLInputElement = fixture.debugElement.query(By.css('#test-year')).nativeElement; - month.value = '01'; - month.dispatchEvent(new Event('input')); - fixture.detectChanges(); - const focusedElement = de.query(By.css(':focus')).nativeElement; - expect(year).toBe(focusedElement); - }); + it('should tab from month to year after two numbers', () => { + const month: HTMLInputElement = fixture.debugElement.query(By.css('#test-month')).nativeElement; + const year: HTMLInputElement = fixture.debugElement.query(By.css('#test-year')).nativeElement; + month.value = '01'; + month.dispatchEvent(new Event('input')); + fixture.detectChanges(); + const focusedElement = de.query(By.css(':focus')).nativeElement; + expect(year).toBe(focusedElement); + }); - it('should tab from hour to minute after two numbers', () => { - const hour: HTMLInputElement = fixture.debugElement.query(By.css('#test-hour')).nativeElement; - const minute: HTMLInputElement = fixture.debugElement.query(By.css('#test-minute')).nativeElement; - hour.value = '01'; - hour.dispatchEvent(new Event('input')); - fixture.detectChanges(); - const focusedElement = de.query(By.css(':focus')).nativeElement; - expect(minute).toBe(focusedElement); - }); + it('should tab from hour to minute after two numbers', () => { + const hour: HTMLInputElement = fixture.debugElement.query(By.css('#test-hour')).nativeElement; + const minute: HTMLInputElement = fixture.debugElement.query(By.css('#test-minute')).nativeElement; + hour.value = '01'; + hour.dispatchEvent(new Event('input')); + fixture.detectChanges(); + const focusedElement = de.query(By.css(':focus')).nativeElement; + expect(minute).toBe(focusedElement); + }); - it('should tab from year to hour after four numbers if displayTime is true', () => { - const year: HTMLInputElement = fixture.debugElement.query(By.css('#test-year')).nativeElement; - const hour: HTMLInputElement = fixture.debugElement.query(By.css('#test-hour')).nativeElement; + it('should tab from year to hour after four numbers if displayTime is true', () => { + const year: HTMLInputElement = fixture.debugElement.query(By.css('#test-year')).nativeElement; + const hour: HTMLInputElement = fixture.debugElement.query(By.css('#test-hour')).nativeElement; - year.focus(); - year.value = '2000'; - year.dispatchEvent(new Event('input')); - fixture.detectChanges(); - let focusedElement = de.query(By.css(':focus')).nativeElement; - expect(year).toBe(focusedElement); + year.focus(); + year.value = '2000'; + year.dispatchEvent(new Event('input')); + fixture.detectChanges(); + let focusedElement = de.query(By.css(':focus')).nativeElement; + expect(year).toBe(focusedElement); - component.displayTime = true; - fixture.detectChanges(); - year.dispatchEvent(new Event('input')); - fixture.detectChanges(); - focusedElement = de.query(By.css(':focus')).nativeElement; - expect(hour).toBe(focusedElement); - }); + component.displayTime = true; + fixture.detectChanges(); + year.dispatchEvent(new Event('input')); + fixture.detectChanges(); + focusedElement = de.query(By.css(':focus')).nativeElement; + expect(hour).toBe(focusedElement); + }); }); diff --git a/src/app/forms/components/date/focus-next.directive.ts b/src/app/forms/components/date/focus-next.directive.ts index 81c50e94ad..c299e84651 100644 --- a/src/app/forms/components/date/focus-next.directive.ts +++ b/src/app/forms/components/date/focus-next.directive.ts @@ -1,48 +1,46 @@ -import { - Directive, ElementRef, HostListener, Input, -} from '@angular/core'; +import { Directive, ElementRef, HostListener, Input } from '@angular/core'; @Directive({ - selector: '[appFocusNext]', + selector: '[appFocusNext]', }) export class FocusNextDirective { - @Input() displayTime = false; + @Input() displayTime = false; - constructor(private el: ElementRef) {} + constructor(private el: ElementRef) {} - @HostListener('input', ['$event']) - onInput() { - const { - nativeElement: { id, value }, - } = this.el; - const segments = id.split('-'); - const next = this.getNextElement(segments.splice(-1)[0], value); + @HostListener('input', ['$event']) + onInput() { + const { + nativeElement: { id, value }, + } = this.el; + const segments = id.split('-'); + const next = this.getNextElement(segments.splice(-1)[0], value); - if (next) { - document.getElementById(`${segments.join('-')}${next}`)?.focus(); - } - } + if (next) { + document.getElementById(`${segments.join('-')}${next}`)?.focus(); + } + } - private getNextElement(currentSegment: string, value: string): string | undefined { - let nextEl; + private getNextElement(currentSegment: string, value: string): string | undefined { + let nextEl; - if (value.length === 2) { - switch (currentSegment) { - case 'day': - nextEl = '-month'; - break; - case 'month': - nextEl = '-year'; - break; - case 'hour': - nextEl = '-minute'; - break; - default: - } - } else if (value.length === 4 && this.displayTime && currentSegment === 'year') { - nextEl = '-hour'; - } + if (value.length === 2) { + switch (currentSegment) { + case 'day': + nextEl = '-month'; + break; + case 'month': + nextEl = '-year'; + break; + case 'hour': + nextEl = '-minute'; + break; + default: + } + } else if (value.length === 4 && this.displayTime && currentSegment === 'year') { + nextEl = '-hour'; + } - return nextEl; - } + return nextEl; + } } diff --git a/src/app/forms/components/defect-select/defect-select.component.spec.ts b/src/app/forms/components/defect-select/defect-select.component.spec.ts index 47c37812af..abd44145d2 100644 --- a/src/app/forms/components/defect-select/defect-select.component.spec.ts +++ b/src/app/forms/components/defect-select/defect-select.component.spec.ts @@ -10,84 +10,84 @@ import { initialAppState } from '@store/.'; import { DefectSelectComponent } from './defect-select.component'; describe('DefectSelectComponent', () => { - let component: DefectSelectComponent; - let fixture: ComponentFixture; + let component: DefectSelectComponent; + let fixture: ComponentFixture; - const defect: Defect = { - additionalInfo: {}, - forVehicleType: [VehicleTypes.PSV], - imDescription: 'some description', - imNumber: 1, - items: [ - { - deficiencies: [ - { - deficiencyCategory: deficiencyCategory.Advisory, - deficiencyId: 'some id', - deficiencySubId: 'some sub id', - deficiencyText: 'hey yo', - forVehicleType: [VehicleTypes.PSV], - ref: 'some ref', - stdForProhibition: false, - }, - ], - forVehicleType: [VehicleTypes.PSV], - itemDescription: 'yolo', - itemNumber: 2, - }, - ], - }; + const defect: Defect = { + additionalInfo: {}, + forVehicleType: [VehicleTypes.PSV], + imDescription: 'some description', + imNumber: 1, + items: [ + { + deficiencies: [ + { + deficiencyCategory: deficiencyCategory.Advisory, + deficiencyId: 'some id', + deficiencySubId: 'some sub id', + deficiencyText: 'hey yo', + forVehicleType: [VehicleTypes.PSV], + ref: 'some ref', + stdForProhibition: false, + }, + ], + forVehicleType: [VehicleTypes.PSV], + itemDescription: 'yolo', + itemNumber: 2, + }, + ], + }; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [RouterTestingModule], - declarations: [DefectSelectComponent], - providers: [provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [RouterTestingModule], + declarations: [DefectSelectComponent], + providers: [provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(DefectSelectComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(DefectSelectComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it('should return all types', () => { - enum Types { - 'Defect', - 'Item', - 'Deficiency', - } - expect(component.types).toStrictEqual(Types); - }); + it('should return all types', () => { + enum Types { + Defect = 0, + Item = 1, + Deficiency = 2, + } + expect(component.types).toStrictEqual(Types); + }); - describe('hasItems', () => { - it('should correctly detect a defect with items', () => { - expect(component.hasItems(defect)).toBeTruthy(); - }); + describe('hasItems', () => { + it('should correctly detect a defect with items', () => { + expect(component.hasItems(defect)).toBeTruthy(); + }); - it('should correctly detect a defect without items', () => { - const defectWithNoItems: Defect = { ...defect, items: [] }; - expect(component.hasItems(defectWithNoItems)).toBeFalsy(); - }); - }); + it('should correctly detect a defect without items', () => { + const defectWithNoItems: Defect = { ...defect, items: [] }; + expect(component.hasItems(defectWithNoItems)).toBeFalsy(); + }); + }); - describe('hasDeficiencies', () => { - it('should correctly detect an item with deficiencies', () => { - expect(component.hasDeficiencies(defect.items[0])).toBeTruthy(); - }); + describe('hasDeficiencies', () => { + it('should correctly detect an item with deficiencies', () => { + expect(component.hasDeficiencies(defect.items[0])).toBeTruthy(); + }); - it('should correctly detect an item without deficiencies', () => { - const itemWithNoDeficiencies: Item = { - ...defect.items[0], - deficiencies: [], - }; + it('should correctly detect an item without deficiencies', () => { + const itemWithNoDeficiencies: Item = { + ...defect.items[0], + deficiencies: [], + }; - expect(component.hasDeficiencies(itemWithNoDeficiencies)).toBeFalsy(); - }); - }); + expect(component.hasDeficiencies(itemWithNoDeficiencies)).toBeFalsy(); + }); + }); }); diff --git a/src/app/forms/components/defect-select/defect-select.component.ts b/src/app/forms/components/defect-select/defect-select.component.ts index 569b84c93c..59b3c737ff 100644 --- a/src/app/forms/components/defect-select/defect-select.component.ts +++ b/src/app/forms/components/defect-select/defect-select.component.ts @@ -13,103 +13,106 @@ import { TestResultsState } from '@store/test-records/reducers/test-records.redu import { Subject, filter, takeUntil } from 'rxjs'; @Component({ - selector: 'app-defect-select', - templateUrl: './defect-select.component.html', - styleUrls: ['./defect-select.component.scss'], + selector: 'app-defect-select', + templateUrl: './defect-select.component.html', + styleUrls: ['./defect-select.component.scss'], }) export class DefectSelectComponent implements OnInit, OnDestroy { - defects: Defect[] = []; - isEditing = false; - selectedDefect?: Defect; - selectedItem?: Item; - selectedDeficiency?: Deficiency; - vehicleType!: VehicleTypes; + defects: Defect[] = []; + isEditing = false; + selectedDefect?: Defect; + selectedItem?: Item; + selectedDeficiency?: Deficiency; + vehicleType!: VehicleTypes; - onDestroy$ = new Subject(); + onDestroy$ = new Subject(); - constructor( - private testResultsStore: Store, - private defectsStore: Store, - private router: Router, - private route: ActivatedRoute, - ) {} + constructor( + private testResultsStore: Store, + private defectsStore: Store, + private router: Router, + private route: ActivatedRoute + ) {} - ngOnInit(): void { - this.testResultsStore - .select(toEditOrNotToEdit) - .pipe( - takeUntil(this.onDestroy$), - filter((testResult) => !!testResult), - ) - .subscribe((testResult) => { - if (testResult) { - this.vehicleType = testResult.vehicleType; - } - }); + ngOnInit(): void { + this.testResultsStore + .select(toEditOrNotToEdit) + .pipe( + takeUntil(this.onDestroy$), + filter((testResult) => !!testResult) + ) + .subscribe((testResult) => { + if (testResult) { + this.vehicleType = testResult.vehicleType; + } + }); - this.defectsStore.select(filteredDefects(this.vehicleType)).subscribe((defectsTaxonomy) => { - this.defects = defectsTaxonomy; - }); - } + this.defectsStore.select(filteredDefects(this.vehicleType)).subscribe((defectsTaxonomy) => { + this.defects = defectsTaxonomy; + }); + } - ngOnDestroy(): void { - this.onDestroy$.next(true); - this.onDestroy$.complete(); - } + ngOnDestroy(): void { + this.onDestroy$.next(true); + this.onDestroy$.complete(); + } - get types(): typeof Types { - return Types; - } + get types(): typeof Types { + return Types; + } - hasItems(defect: Defect): boolean { - return defect.items && defect.items.length > 0; - } + hasItems(defect: Defect): boolean { + return defect.items && defect.items.length > 0; + } - hasDeficiencies(item: Item): boolean { - return item.deficiencies && item.deficiencies.length > 0; - } + hasDeficiencies(item: Item): boolean { + return item.deficiencies && item.deficiencies.length > 0; + } - categoryColor(category: string): 'red' | 'orange' | 'yellow' | 'green' | 'blue' { - return (>{ - major: 'orange', - minor: 'yellow', - dangerous: 'red', - advisory: 'blue', - })[`${category}`]; - } + categoryColor(category: string): 'red' | 'orange' | 'yellow' | 'green' | 'blue' { + return (>{ + major: 'orange', + minor: 'yellow', + dangerous: 'red', + advisory: 'blue', + })[`${category}`]; + } - handleSelect(selected?: Defect | Item | Deficiency, type?: Types): void { - switch (type) { - case Types.Defect: - this.selectedDefect = selected as Defect; - this.selectedItem = undefined; - this.selectedDeficiency = undefined; - break; - case Types.Item: - this.selectedItem = selected as Item; - this.selectedDeficiency = undefined; - break; - case Types.Deficiency: - this.selectedDeficiency = selected as Deficiency; - void this.router.navigate([this.selectedDeficiency.ref], { relativeTo: this.route, queryParamsHandling: 'merge' }); - break; - default: - let advisoryRoute = `${this.selectedDefect?.imNumber}.${this.selectedItem?.itemNumber}.advisory`; - if (this.selectedDefect?.imNumber === 71 && this.selectedItem?.itemNumber === 1) { - advisoryRoute += this.selectedItem.itemDescription === 'All Roller Brake Test Machines:' ? '.0' : '.1'; - } + handleSelect(selected?: Defect | Item | Deficiency, type?: Types): void { + switch (type) { + case Types.Defect: + this.selectedDefect = selected as Defect; + this.selectedItem = undefined; + this.selectedDeficiency = undefined; + break; + case Types.Item: + this.selectedItem = selected as Item; + this.selectedDeficiency = undefined; + break; + case Types.Deficiency: + this.selectedDeficiency = selected as Deficiency; + void this.router.navigate([this.selectedDeficiency.ref], { + relativeTo: this.route, + queryParamsHandling: 'merge', + }); + break; + default: + let advisoryRoute = `${this.selectedDefect?.imNumber}.${this.selectedItem?.itemNumber}.advisory`; + if (this.selectedDefect?.imNumber === 71 && this.selectedItem?.itemNumber === 1) { + advisoryRoute += this.selectedItem.itemDescription === 'All Roller Brake Test Machines:' ? '.0' : '.1'; + } - void this.router.navigate([advisoryRoute], { - relativeTo: this.route, - queryParamsHandling: 'merge', - }); - break; - } - } + void this.router.navigate([advisoryRoute], { + relativeTo: this.route, + queryParamsHandling: 'merge', + }); + break; + } + } } enum Types { - Defect, - Item, - Deficiency, + Defect = 0, + Item = 1, + Deficiency = 2, } diff --git a/src/app/forms/components/dynamic-form-field/dynamic-form-field.component.spec.ts b/src/app/forms/components/dynamic-form-field/dynamic-form-field.component.spec.ts index 171a06b59b..6d2aea4656 100644 --- a/src/app/forms/components/dynamic-form-field/dynamic-form-field.component.spec.ts +++ b/src/app/forms/components/dynamic-form-field/dynamic-form-field.component.spec.ts @@ -12,74 +12,78 @@ import { of } from 'rxjs'; import { DynamicFormFieldComponent } from './dynamic-form-field.component'; describe('DynamicFormFieldComponent', () => { - let component: DynamicFormFieldComponent; - let fixture: ComponentFixture; - let service: ReferenceDataService; + let component: DynamicFormFieldComponent; + let fixture: ComponentFixture; + let service: ReferenceDataService; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [DynamicFormFieldComponent], - imports: [FormsModule, HttpClientTestingModule, ReactiveFormsModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - ReferenceDataService, - TestStationsService, - { provide: UserService, useValue: {} }, - ], - }).compileComponents(); - service = TestBed.inject(ReferenceDataService); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [DynamicFormFieldComponent], + imports: [FormsModule, HttpClientTestingModule, ReactiveFormsModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + ReferenceDataService, + TestStationsService, + { provide: UserService, useValue: {} }, + ], + }).compileComponents(); + service = TestBed.inject(ReferenceDataService); + }); - beforeEach(() => { - fixture = TestBed.createComponent(DynamicFormFieldComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - component.control = { - key: 'birthday', - value: new CustomFormControl({ - name: 'test', - type: FormNodeTypes.CONTROL, - referenceData: ReferenceDataResourceType.CountryOfRegistration, - }), - }; - }); + beforeEach(() => { + fixture = TestBed.createComponent(DynamicFormFieldComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + component.control = { + key: 'birthday', + value: new CustomFormControl({ + name: 'test', + type: FormNodeTypes.CONTROL, + referenceData: ReferenceDataResourceType.CountryOfRegistration, + }), + }; + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it('should get options', () => { - const options = component.options$; - expect(options).toBeTruthy(); - }); + it('should get options', () => { + const options = component.options$; + expect(options).toBeTruthy(); + }); - it('should return the metadata options', (done) => { - component.control = { - key: 'birthday', - value: new CustomFormControl({ name: 'test', type: FormNodeTypes.CONTROL, options: [{ value: '1', label: 'test' }] }), - }; - component.form = new FormGroup({}); - component.options$.subscribe((value) => { - expect(value).toBeTruthy(); - expect(value).toEqual([{ value: '1', label: 'test' }]); - done(); - }); - }); + it('should return the metadata options', (done) => { + component.control = { + key: 'birthday', + value: new CustomFormControl({ + name: 'test', + type: FormNodeTypes.CONTROL, + options: [{ value: '1', label: 'test' }], + }), + }; + component.form = new FormGroup({}); + component.options$.subscribe((value) => { + expect(value).toBeTruthy(); + expect(value).toEqual([{ value: '1', label: 'test' }]); + done(); + }); + }); - it('should return the reference data options', (done) => { - service.getAll$ = jest.fn().mockReturnValue(of([{ resourceKey: '1', description: 'test' }])); - component.form = new FormGroup({}); - component.options$.subscribe((value) => { - expect(value).toBeTruthy(); - expect(value).toEqual([{ value: '1', label: 'test' }]); - done(); - }); - }); + it('should return the reference data options', (done) => { + service.getAll$ = jest.fn().mockReturnValue(of([{ resourceKey: '1', description: 'test' }])); + component.form = new FormGroup({}); + component.options$.subscribe((value) => { + expect(value).toBeTruthy(); + expect(value).toEqual([{ value: '1', label: 'test' }]); + done(); + }); + }); - it('should fetch the reference data on init', () => { - service.loadReferenceData = jest.fn(); - component.ngAfterContentInit(); - const spy = jest.spyOn(service, 'loadReferenceData'); - expect(spy).toHaveBeenCalled(); - }); + it('should fetch the reference data on init', () => { + service.loadReferenceData = jest.fn(); + component.ngAfterContentInit(); + const spy = jest.spyOn(service, 'loadReferenceData'); + expect(spy).toHaveBeenCalled(); + }); }); diff --git a/src/app/forms/components/dynamic-form-field/dynamic-form-field.component.ts b/src/app/forms/components/dynamic-form-field/dynamic-form-field.component.ts index 041898395b..485609cac6 100644 --- a/src/app/forms/components/dynamic-form-field/dynamic-form-field.component.ts +++ b/src/app/forms/components/dynamic-form-field/dynamic-form-field.component.ts @@ -1,7 +1,5 @@ import { KeyValue } from '@angular/common'; -import { - AfterContentInit, Component, InjectionToken, Injector, Input, OnInit, -} from '@angular/core'; +import { AfterContentInit, Component, InjectionToken, Injector, Input, OnInit } from '@angular/core'; import { FormGroup, NgControl } from '@angular/forms'; // eslint-disable-next-line import/no-cycle import { CustomFormControl, FormNodeEditTypes, FormNodeOption } from '@forms/services/dynamic-form.types'; @@ -9,51 +7,54 @@ import { MultiOptionsService } from '@forms/services/multi-options.service'; import { Observable, map, of } from 'rxjs'; @Component({ - selector: 'app-dynamic-form-field', - templateUrl: './dynamic-form-field.component.html', - providers: [MultiOptionsService], + selector: 'app-dynamic-form-field', + templateUrl: './dynamic-form-field.component.html', + providers: [MultiOptionsService], }) export class DynamicFormFieldComponent implements OnInit, AfterContentInit { - @Input() control?: KeyValue; - @Input() form?: FormGroup; - @Input() customId?: string; - - customFormControlInjector?: Injector; - - constructor(private optionsService: MultiOptionsService, private injector: Injector) {} - - get formNodeEditTypes(): typeof FormNodeEditTypes { - return FormNodeEditTypes; - } - - get options$(): Observable[]> { - const meta = this.control?.value.meta; - - return meta?.referenceData - ? this.optionsService.getOptions(meta.referenceData).pipe(map((l) => (l || []))) - : of((meta?.options as FormNodeOption[]) ?? []); - } - - ngOnInit(): void { - this.createCustomFormControlInjector(); - } - - ngAfterContentInit(): void { - const referenceData = this.control?.value.meta?.referenceData; - - if (referenceData) { - this.optionsService.loadOptions(referenceData); - } - } - - createCustomFormControlInjector() { - this.customFormControlInjector = Injector.create({ - providers: [ - { provide: FORM_INJECTION_TOKEN, useValue: this.form }, - { provide: NgControl, useValue: { control: this.control } }, - ], - parent: this.injector, - }); - } + @Input() control?: KeyValue; + @Input() form?: FormGroup; + @Input() customId?: string; + + customFormControlInjector?: Injector; + + constructor( + private optionsService: MultiOptionsService, + private injector: Injector + ) {} + + get formNodeEditTypes(): typeof FormNodeEditTypes { + return FormNodeEditTypes; + } + + get options$(): Observable[]> { + const meta = this.control?.value.meta; + + return meta?.referenceData + ? this.optionsService.getOptions(meta.referenceData).pipe(map((l) => l || [])) + : of((meta?.options as FormNodeOption[]) ?? []); + } + + ngOnInit(): void { + this.createCustomFormControlInjector(); + } + + ngAfterContentInit(): void { + const referenceData = this.control?.value.meta?.referenceData; + + if (referenceData) { + this.optionsService.loadOptions(referenceData); + } + } + + createCustomFormControlInjector() { + this.customFormControlInjector = Injector.create({ + providers: [ + { provide: FORM_INJECTION_TOKEN, useValue: this.form }, + { provide: NgControl, useValue: { control: this.control } }, + ], + parent: this.injector, + }); + } } export const FORM_INJECTION_TOKEN = new InjectionToken('form'); diff --git a/src/app/forms/components/dynamic-form-group/dynamic-form-group.component.spec.ts b/src/app/forms/components/dynamic-form-group/dynamic-form-group.component.spec.ts index 93fa604f86..a13d9dc031 100644 --- a/src/app/forms/components/dynamic-form-group/dynamic-form-group.component.spec.ts +++ b/src/app/forms/components/dynamic-form-group/dynamic-form-group.component.spec.ts @@ -1,7 +1,5 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { - ComponentFixture, fakeAsync, inject, TestBed, tick, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, inject, tick } from '@angular/core/testing'; import { FormGroup } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { RouterTestingModule } from '@angular/router/testing'; @@ -16,448 +14,511 @@ import { FormNode, FormNodeTypes, FormNodeViewTypes } from '../../services/dynam import { DynamicFormGroupComponent } from './dynamic-form-group.component'; describe('DynamicFormGroupComponent', () => { - let component: DynamicFormGroupComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - ReferenceDataService, - TestStationsService, - { provide: UserService, useValue: {} }, - ], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(DynamicFormGroupComponent); - component = fixture.componentInstance; - // Don't detect changes on the first load as it will prevent change detection - // from working in the test function due to change detection being OnPush - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('DynamicFormGroupComponent.prototype.trackByFn.name', () => { - it.each([ - [3, [3, 'some value']], - ['foo', [3, { key: 'foo' }]], - ])('should return %s when given %o', (expected, props) => { - const [index, item] = props; - expect(component.trackByFn(index as number, item)).toBe(expected); - }); - }); - - it.each([ - [ - { a: 'b', c: 1 }, - [ - { key: 'a', value: 'b' }, - { key: 'c', value: 1 }, - ], - ], - [ - { - name: 'test-name', - label: 'test-label', - type: 'test-type', - children: [ - { - name: 'test-c-name', label: 'test-c-label', value: 'test-c-value', children: [], type: 'test-c-control', viewType: 'test-c-viewType', - }, - ], - }, - [ - { key: 'name', value: 'test-name' }, - { key: 'label', value: 'test-label' }, - { key: 'type', value: 'test-type' }, - { - key: 'children', - value: [ - { - name: 'test-c-name', label: 'test-c-label', value: 'test-c-value', children: [], type: 'test-c-control', viewType: 'test-c-viewType', - }, - ], - }, - ], - ], - ])('entriesOf: should split the keys out into values', (input, expected) => { - expect(component.entriesOf(input as unknown as FormGroup)).toStrictEqual(expected); - }); - - describe('formNodeTypes', () => { - it('should return FormNodeTypes enum', () => { - Object.entries(FormNodeTypes).forEach((entry) => { - expect(FormNodeTypes).toEqual(component.formNodeTypes); - expect(component.formNodeTypes[entry[0] as keyof typeof FormNodeTypes]).toBe(entry[1]); - }); - }); - }); - - describe('formNodeViewTypes', () => { - it('should return FormNodeViewTypes enum', () => { - Object.entries(FormNodeViewTypes).forEach((entry) => { - expect(FormNodeViewTypes).toEqual(component.formNodeViewTypes); - expect(component.formNodeViewTypes[entry[0] as keyof typeof FormNodeViewTypes]).toBe(entry[1]); - }); - }); - }); - - describe('template', () => { - const template = { - name: 'myForm', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'levelOneControl', type: FormNodeTypes.CONTROL, label: 'Level one control', value: 'some string', - }, - { - name: 'levelOneGroup', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'levelTwoControl', type: FormNodeTypes.CONTROL, label: 'Level two control', value: 'some string', - }, - { - name: 'levelTwoArray', - type: FormNodeTypes.ARRAY, - children: [ - { name: 'levelTwoArrayControlOne', type: FormNodeTypes.CONTROL, value: '1' }, - { name: 'levelTwoArrayControlTwo', type: FormNodeTypes.CONTROL, value: '2' }, - ], - }, - ], - }, - ], - }; - - const data = { - levelOneControl: 'some string', - levelOneGroup: { - levelTwoControl: 'some string', - levelTwoArray: [ - { - levelTwoArrayControlOne: 'some string', - levelTwoArrayControlTwo: 'some string', - }, - ], - }, - }; - - it('should generate the correct number of detail summary elements', inject([DynamicFormService], (dfs: DynamicFormService) => { - component.form = dfs.createForm(template, data); - - fixture.detectChanges(); - - const trList = fixture.debugElement.queryAll(By.css('tr')); - const tdList = fixture.debugElement.queryAll(By.css('td')); - - expect(trList).toHaveLength(4); - expect(tdList).toHaveLength(8); - })); - - it('should generate the correct number of input elements', inject([DynamicFormService], (dfs: DynamicFormService) => { - component.edit = true; - component.form = dfs.createForm(template, data); - - fixture.detectChanges(); - - const inputList = fixture.debugElement.queryAll(By.css('input')); - - expect(inputList).toHaveLength(4); - })); - }); - - describe('template for nested array with groups', () => { - const template = { - name: 'myForm', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'levelOneControl', type: FormNodeTypes.CONTROL, label: 'Level one control', value: 'some string', - }, - { - name: 'levelOneGroup', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'levelTwoControl', type: FormNodeTypes.CONTROL, label: 'Level two control', value: 'some string', - }, - { - name: 'levelTwoArray', - type: FormNodeTypes.ARRAY, - children: [ - { - name: 'levelThreeArray', - type: FormNodeTypes.ARRAY, - children: [ - { - name: 'levelThreeGroup', - type: FormNodeTypes.GROUP, - children: [ - { name: 'levelThreeArrayControlOne', type: FormNodeTypes.CONTROL, value: '1' }, - { name: 'levelThreeArrayControlTwo', type: FormNodeTypes.CONTROL, value: '2' }, - ], - }, - ], - }, - ], - }, - ], - }, - ], - }; - - const data = { - levelOneControl: 'some string', - levelOneGroup: { - levelTwoControl: 'some string', - levelTwoArray: [ - [ - { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, - { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, - ], - [ - { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, - { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, - ], - ], - }, - }; - - it('should generate the correct number of detail summary elements', inject([DynamicFormService], (dfs: DynamicFormService) => { - component.form = dfs.createForm(template, data); - - fixture.detectChanges(); - - const trList = fixture.debugElement.queryAll(By.css('tr')); - const tdList = fixture.debugElement.queryAll(By.css('td')); - - expect(trList).toHaveLength(10); - expect(tdList).toHaveLength(20); - })); - - it('should generate the correct number of input elements', inject([DynamicFormService], (dfs: DynamicFormService) => { - component.edit = true; - component.form = dfs.createForm(template, data); - - fixture.detectChanges(); - - const inputList = fixture.debugElement.queryAll(By.css('input')); - - expect(inputList).toHaveLength(10); - })); - - it('should generate the correct number of input elements if I reduce the data', inject([DynamicFormService], (dfs: DynamicFormService) => { - const newData = { - levelOneControl: 'some string', - levelOneGroup: { - levelTwoControl: 'some string', - levelTwoArray: [ - [{ levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }], - [{ levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }], - ], - }, - }; - component.edit = true; - component.form = dfs.createForm(template, newData); - - fixture.detectChanges(); - - const inputList = fixture.debugElement.queryAll(By.css('input')); - - expect(inputList).toHaveLength(6); - })); - - it('should generate the correct number of input elements if I increase the data', inject([DynamicFormService], (dfs: DynamicFormService) => { - const newData = { - levelOneControl: 'some string', - levelOneGroup: { - levelTwoControl: 'some string', - levelTwoArray: [ - [ - { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, - { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, - { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, - ], - [ - { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, - { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, - { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, - ], - ], - }, - }; - component.edit = true; - component.form = dfs.createForm(template, newData); - - fixture.detectChanges(); - - const inputList = fixture.debugElement.queryAll(By.css('input')); - - expect(inputList).toHaveLength(14); - })); - }); - - describe('template for array with groups', () => { - const template = { - name: 'myForm', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'levelOneControl', type: FormNodeTypes.CONTROL, label: 'Level one control', value: 'some string', - }, - { - name: 'levelOneGroup', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'levelTwoControl', type: FormNodeTypes.CONTROL, label: 'Level two control', value: 'some string', - }, - { - name: 'levelTwoArray', - type: FormNodeTypes.ARRAY, - children: [ - { - name: 'levelTwoGroup', - type: FormNodeTypes.GROUP, - children: [ - { name: 'levelTwoArrayControlOne', type: FormNodeTypes.CONTROL, value: '1' }, - { name: 'levelTwoArrayControlTwo', type: FormNodeTypes.CONTROL, value: '2' }, - ], - }, - ], - }, - ], - }, - ], - }; - - const data = { - levelOneControl: 'some string', - levelOneGroup: { - levelTwoControl: 'some string', - levelTwoArray: [ - { - levelTwoArrayControlOne: 'some string', - levelTwoArrayControlTwo: 'some string', - }, - { - levelTwoArrayControlOne: 'some string', - levelTwoArrayControlTwo: 'some string', - }, - ], - }, - }; - - it('should generate the correct number of detail summary elements', inject([DynamicFormService], (dfs: DynamicFormService) => { - component.form = dfs.createForm(template, data); - - fixture.detectChanges(); - - const trList = fixture.debugElement.queryAll(By.css('tr')); - const tdList = fixture.debugElement.queryAll(By.css('td')); - - expect(trList).toHaveLength(6); - expect(tdList).toHaveLength(12); - })); - - it('should generate the correct number of input elements', inject([DynamicFormService], (dfs: DynamicFormService) => { - component.edit = true; - component.form = dfs.createForm(template, data); - - fixture.detectChanges(); - - const inputList = fixture.debugElement.queryAll(By.css('input')); - - expect(inputList).toHaveLength(6); - })); - - it('should generate the correct number of input elements if I reduce the data', inject([DynamicFormService], (dfs: DynamicFormService) => { - const newData = { - levelOneControl: 'some string', - levelOneGroup: { - levelTwoControl: 'some string', - levelTwoArray: [ - { - levelTwoArrayControlOne: 'some string', - levelTwoArrayControlTwo: 'some string', - }, - ], - }, - }; - component.edit = true; - component.form = dfs.createForm(template, newData); - - fixture.detectChanges(); - - const inputList = fixture.debugElement.queryAll(By.css('input')); - - expect(inputList).toHaveLength(4); - })); - - it('should generate the correct number of input elements if I increase the data', inject([DynamicFormService], (dfs: DynamicFormService) => { - const newData = { - levelOneControl: 'some string', - levelOneGroup: { - levelTwoControl: 'some string', - levelTwoArray: [ - { - levelTwoArrayControlOne: 'some string', - levelTwoArrayControlTwo: 'some string', - }, - { - levelTwoArrayControlOne: 'some string', - levelTwoArrayControlTwo: 'some string', - }, - { - levelTwoArrayControlOne: 'some string', - levelTwoArrayControlTwo: 'some string', - }, - ], - }, - }; - component.edit = true; - component.form = dfs.createForm(template, newData); - - fixture.detectChanges(); - - const inputList = fixture.debugElement.queryAll(By.css('input')); - - expect(inputList).toHaveLength(8); - })); - }); - - describe('value changes', () => { - const template = { - name: 'myForm', - type: FormNodeTypes.GROUP, - children: [{ - name: 'levelOneControl', type: FormNodeTypes.CONTROL, label: 'Level one control', value: 'some string', - }], - }; - - const data = { - levelOneControl: 'some string', - }; - it('should output an event when the value of the control changes', fakeAsync( - inject([DynamicFormService], (dfs: DynamicFormService) => { - component.edit = true; - component.form = dfs.createForm(template, data); - - fixture.detectChanges(); - - const control = component.form.get('levelOneControl'); - control?.patchValue('foo'); - const emitter = jest.spyOn(component.formChange, 'emit'); - tick(500); - expect(emitter).toHaveBeenCalledWith({ ...data, levelOneControl: 'foo' }); - expect(emitter).toHaveBeenCalledTimes(1); - }), - )); - }); + let component: DynamicFormGroupComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + ReferenceDataService, + TestStationsService, + { provide: UserService, useValue: {} }, + ], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(DynamicFormGroupComponent); + component = fixture.componentInstance; + // Don't detect changes on the first load as it will prevent change detection + // from working in the test function due to change detection being OnPush + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('DynamicFormGroupComponent.prototype.trackByFn.name', () => { + it.each([ + [3, [3, 'some value']], + ['foo', [3, { key: 'foo' }]], + ])('should return %s when given %o', (expected, props) => { + const [index, item] = props; + expect(component.trackByFn(index as number, item)).toBe(expected); + }); + }); + + it.each([ + [ + { a: 'b', c: 1 }, + [ + { key: 'a', value: 'b' }, + { key: 'c', value: 1 }, + ], + ], + [ + { + name: 'test-name', + label: 'test-label', + type: 'test-type', + children: [ + { + name: 'test-c-name', + label: 'test-c-label', + value: 'test-c-value', + children: [], + type: 'test-c-control', + viewType: 'test-c-viewType', + }, + ], + }, + [ + { key: 'name', value: 'test-name' }, + { key: 'label', value: 'test-label' }, + { key: 'type', value: 'test-type' }, + { + key: 'children', + value: [ + { + name: 'test-c-name', + label: 'test-c-label', + value: 'test-c-value', + children: [], + type: 'test-c-control', + viewType: 'test-c-viewType', + }, + ], + }, + ], + ], + ])('entriesOf: should split the keys out into values', (input, expected) => { + expect(component.entriesOf(input as unknown as FormGroup)).toStrictEqual(expected); + }); + + describe('formNodeTypes', () => { + it('should return FormNodeTypes enum', () => { + Object.entries(FormNodeTypes).forEach((entry) => { + expect(FormNodeTypes).toEqual(component.formNodeTypes); + expect(component.formNodeTypes[entry[0] as keyof typeof FormNodeTypes]).toBe(entry[1]); + }); + }); + }); + + describe('formNodeViewTypes', () => { + it('should return FormNodeViewTypes enum', () => { + Object.entries(FormNodeViewTypes).forEach((entry) => { + expect(FormNodeViewTypes).toEqual(component.formNodeViewTypes); + expect(component.formNodeViewTypes[entry[0] as keyof typeof FormNodeViewTypes]).toBe(entry[1]); + }); + }); + }); + + describe('template', () => { + const template = { + name: 'myForm', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'levelOneControl', + type: FormNodeTypes.CONTROL, + label: 'Level one control', + value: 'some string', + }, + { + name: 'levelOneGroup', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'levelTwoControl', + type: FormNodeTypes.CONTROL, + label: 'Level two control', + value: 'some string', + }, + { + name: 'levelTwoArray', + type: FormNodeTypes.ARRAY, + children: [ + { name: 'levelTwoArrayControlOne', type: FormNodeTypes.CONTROL, value: '1' }, + { name: 'levelTwoArrayControlTwo', type: FormNodeTypes.CONTROL, value: '2' }, + ], + }, + ], + }, + ], + }; + + const data = { + levelOneControl: 'some string', + levelOneGroup: { + levelTwoControl: 'some string', + levelTwoArray: [ + { + levelTwoArrayControlOne: 'some string', + levelTwoArrayControlTwo: 'some string', + }, + ], + }, + }; + + it('should generate the correct number of detail summary elements', inject( + [DynamicFormService], + (dfs: DynamicFormService) => { + component.form = dfs.createForm(template, data); + + fixture.detectChanges(); + + const trList = fixture.debugElement.queryAll(By.css('tr')); + const tdList = fixture.debugElement.queryAll(By.css('td')); + + expect(trList).toHaveLength(4); + expect(tdList).toHaveLength(8); + } + )); + + it('should generate the correct number of input elements', inject( + [DynamicFormService], + (dfs: DynamicFormService) => { + component.edit = true; + component.form = dfs.createForm(template, data); + + fixture.detectChanges(); + + const inputList = fixture.debugElement.queryAll(By.css('input')); + + expect(inputList).toHaveLength(4); + } + )); + }); + + describe('template for nested array with groups', () => { + const template = { + name: 'myForm', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'levelOneControl', + type: FormNodeTypes.CONTROL, + label: 'Level one control', + value: 'some string', + }, + { + name: 'levelOneGroup', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'levelTwoControl', + type: FormNodeTypes.CONTROL, + label: 'Level two control', + value: 'some string', + }, + { + name: 'levelTwoArray', + type: FormNodeTypes.ARRAY, + children: [ + { + name: 'levelThreeArray', + type: FormNodeTypes.ARRAY, + children: [ + { + name: 'levelThreeGroup', + type: FormNodeTypes.GROUP, + children: [ + { name: 'levelThreeArrayControlOne', type: FormNodeTypes.CONTROL, value: '1' }, + { name: 'levelThreeArrayControlTwo', type: FormNodeTypes.CONTROL, value: '2' }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }; + + const data = { + levelOneControl: 'some string', + levelOneGroup: { + levelTwoControl: 'some string', + levelTwoArray: [ + [ + { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, + { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, + ], + [ + { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, + { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, + ], + ], + }, + }; + + it('should generate the correct number of detail summary elements', inject( + [DynamicFormService], + (dfs: DynamicFormService) => { + component.form = dfs.createForm(template, data); + + fixture.detectChanges(); + + const trList = fixture.debugElement.queryAll(By.css('tr')); + const tdList = fixture.debugElement.queryAll(By.css('td')); + + expect(trList).toHaveLength(10); + expect(tdList).toHaveLength(20); + } + )); + + it('should generate the correct number of input elements', inject( + [DynamicFormService], + (dfs: DynamicFormService) => { + component.edit = true; + component.form = dfs.createForm(template, data); + + fixture.detectChanges(); + + const inputList = fixture.debugElement.queryAll(By.css('input')); + + expect(inputList).toHaveLength(10); + } + )); + + it('should generate the correct number of input elements if I reduce the data', inject( + [DynamicFormService], + (dfs: DynamicFormService) => { + const newData = { + levelOneControl: 'some string', + levelOneGroup: { + levelTwoControl: 'some string', + levelTwoArray: [ + [{ levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }], + [{ levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }], + ], + }, + }; + component.edit = true; + component.form = dfs.createForm(template, newData); + + fixture.detectChanges(); + + const inputList = fixture.debugElement.queryAll(By.css('input')); + + expect(inputList).toHaveLength(6); + } + )); + + it('should generate the correct number of input elements if I increase the data', inject( + [DynamicFormService], + (dfs: DynamicFormService) => { + const newData = { + levelOneControl: 'some string', + levelOneGroup: { + levelTwoControl: 'some string', + levelTwoArray: [ + [ + { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, + { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, + { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, + ], + [ + { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, + { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, + { levelThreeArrayControlOne: 'some string', levelThreeArrayControlTwo: 'some string' }, + ], + ], + }, + }; + component.edit = true; + component.form = dfs.createForm(template, newData); + + fixture.detectChanges(); + + const inputList = fixture.debugElement.queryAll(By.css('input')); + + expect(inputList).toHaveLength(14); + } + )); + }); + + describe('template for array with groups', () => { + const template = { + name: 'myForm', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'levelOneControl', + type: FormNodeTypes.CONTROL, + label: 'Level one control', + value: 'some string', + }, + { + name: 'levelOneGroup', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'levelTwoControl', + type: FormNodeTypes.CONTROL, + label: 'Level two control', + value: 'some string', + }, + { + name: 'levelTwoArray', + type: FormNodeTypes.ARRAY, + children: [ + { + name: 'levelTwoGroup', + type: FormNodeTypes.GROUP, + children: [ + { name: 'levelTwoArrayControlOne', type: FormNodeTypes.CONTROL, value: '1' }, + { name: 'levelTwoArrayControlTwo', type: FormNodeTypes.CONTROL, value: '2' }, + ], + }, + ], + }, + ], + }, + ], + }; + + const data = { + levelOneControl: 'some string', + levelOneGroup: { + levelTwoControl: 'some string', + levelTwoArray: [ + { + levelTwoArrayControlOne: 'some string', + levelTwoArrayControlTwo: 'some string', + }, + { + levelTwoArrayControlOne: 'some string', + levelTwoArrayControlTwo: 'some string', + }, + ], + }, + }; + + it('should generate the correct number of detail summary elements', inject( + [DynamicFormService], + (dfs: DynamicFormService) => { + component.form = dfs.createForm(template, data); + + fixture.detectChanges(); + + const trList = fixture.debugElement.queryAll(By.css('tr')); + const tdList = fixture.debugElement.queryAll(By.css('td')); + + expect(trList).toHaveLength(6); + expect(tdList).toHaveLength(12); + } + )); + + it('should generate the correct number of input elements', inject( + [DynamicFormService], + (dfs: DynamicFormService) => { + component.edit = true; + component.form = dfs.createForm(template, data); + + fixture.detectChanges(); + + const inputList = fixture.debugElement.queryAll(By.css('input')); + + expect(inputList).toHaveLength(6); + } + )); + + it('should generate the correct number of input elements if I reduce the data', inject( + [DynamicFormService], + (dfs: DynamicFormService) => { + const newData = { + levelOneControl: 'some string', + levelOneGroup: { + levelTwoControl: 'some string', + levelTwoArray: [ + { + levelTwoArrayControlOne: 'some string', + levelTwoArrayControlTwo: 'some string', + }, + ], + }, + }; + component.edit = true; + component.form = dfs.createForm(template, newData); + + fixture.detectChanges(); + + const inputList = fixture.debugElement.queryAll(By.css('input')); + + expect(inputList).toHaveLength(4); + } + )); + + it('should generate the correct number of input elements if I increase the data', inject( + [DynamicFormService], + (dfs: DynamicFormService) => { + const newData = { + levelOneControl: 'some string', + levelOneGroup: { + levelTwoControl: 'some string', + levelTwoArray: [ + { + levelTwoArrayControlOne: 'some string', + levelTwoArrayControlTwo: 'some string', + }, + { + levelTwoArrayControlOne: 'some string', + levelTwoArrayControlTwo: 'some string', + }, + { + levelTwoArrayControlOne: 'some string', + levelTwoArrayControlTwo: 'some string', + }, + ], + }, + }; + component.edit = true; + component.form = dfs.createForm(template, newData); + + fixture.detectChanges(); + + const inputList = fixture.debugElement.queryAll(By.css('input')); + + expect(inputList).toHaveLength(8); + } + )); + }); + + describe('value changes', () => { + const template = { + name: 'myForm', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'levelOneControl', + type: FormNodeTypes.CONTROL, + label: 'Level one control', + value: 'some string', + }, + ], + }; + + const data = { + levelOneControl: 'some string', + }; + it('should output an event when the value of the control changes', fakeAsync( + inject([DynamicFormService], (dfs: DynamicFormService) => { + component.edit = true; + component.form = dfs.createForm(template, data); + + fixture.detectChanges(); + + const control = component.form.get('levelOneControl'); + control?.patchValue('foo'); + const emitter = jest.spyOn(component.formChange, 'emit'); + tick(500); + expect(emitter).toHaveBeenCalledWith({ ...data, levelOneControl: 'foo' }); + expect(emitter).toHaveBeenCalledTimes(1); + }) + )); + }); }); diff --git a/src/app/forms/components/dynamic-form-group/dynamic-form-group.component.ts b/src/app/forms/components/dynamic-form-group/dynamic-form-group.component.ts index 96f3eb6ad6..4989d18fb6 100644 --- a/src/app/forms/components/dynamic-form-group/dynamic-form-group.component.ts +++ b/src/app/forms/components/dynamic-form-group/dynamic-form-group.component.ts @@ -1,69 +1,86 @@ import { - ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + OnChanges, + OnDestroy, + OnInit, + Output, + SimpleChanges, } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { Subject, debounceTime, takeUntil } from 'rxjs'; import { DynamicFormService } from '../../services/dynamic-form.service'; import { - CustomFormArray, CustomFormGroup, FormNode, FormNodeTypes, FormNodeViewTypes, + CustomFormArray, + CustomFormGroup, + FormNode, + FormNodeTypes, + FormNodeViewTypes, } from '../../services/dynamic-form.types'; @Component({ - selector: 'app-dynamic-form-group', - templateUrl: './dynamic-form-group.component.html', - styleUrls: ['./dynamic-form-group.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-dynamic-form-group', + templateUrl: './dynamic-form-group.component.html', + styleUrls: ['./dynamic-form-group.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class DynamicFormGroupComponent implements OnChanges, OnInit, OnDestroy { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - @Input() data: any = {}; - @Input() template?: FormNode; - @Input() edit = false; - @Output() formChange = new EventEmitter(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + @Input() data: any = {}; + @Input() template?: FormNode; + @Input() edit = false; + @Output() formChange = new EventEmitter(); - form: CustomFormGroup | CustomFormArray = new CustomFormGroup({ name: 'dynamic-form', type: FormNodeTypes.GROUP, children: [] }, {}); + form: CustomFormGroup | CustomFormArray = new CustomFormGroup( + { name: 'dynamic-form', type: FormNodeTypes.GROUP, children: [] }, + {} + ); - private destroy$ = new Subject(); + private destroy$ = new Subject(); - constructor(private dfs: DynamicFormService) {} + constructor(private dfs: DynamicFormService) {} - ngOnChanges(changes: SimpleChanges): void { - const { template, data } = changes; - if (template && template.currentValue) { - this.form = this.dfs.createForm(template.currentValue, this.data); - } - if (data?.currentValue && data.currentValue !== data.previousValue) { - this.form.patchValue(data.currentValue, { emitEvent: false }); - } - } + ngOnChanges(changes: SimpleChanges): void { + const { template, data } = changes; + if (template && template.currentValue) { + this.form = this.dfs.createForm(template.currentValue, this.data); + } + if (data?.currentValue && data.currentValue !== data.previousValue) { + this.form.patchValue(data.currentValue, { emitEvent: false }); + } + } - ngOnInit(): void { - this.form.cleanValueChanges.pipe(debounceTime(400), takeUntil(this.destroy$)).subscribe((e) => this.formChange.emit(e)); - } + ngOnInit(): void { + this.form.cleanValueChanges + .pipe(debounceTime(400), takeUntil(this.destroy$)) + .subscribe((e) => this.formChange.emit(e)); + } - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - entriesOf(obj: FormGroup): { key: string; value: any }[] { - return Object.entries(obj).map(([key, value]) => ({ - key, - value, - })); - } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + entriesOf(obj: FormGroup): { key: string; value: any }[] { + return Object.entries(obj).map(([key, value]) => ({ + key, + value, + })); + } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - trackByFn(index: number, item: any) { - return Object.prototype.hasOwnProperty.call(item, 'key') ? item.key : index; - } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + trackByFn(index: number, item: any) { + return Object.prototype.hasOwnProperty.call(item, 'key') ? item.key : index; + } - get formNodeTypes(): typeof FormNodeTypes { - return FormNodeTypes; - } + get formNodeTypes(): typeof FormNodeTypes { + return FormNodeTypes; + } - get formNodeViewTypes(): typeof FormNodeViewTypes { - return FormNodeViewTypes; - } + get formNodeViewTypes(): typeof FormNodeViewTypes { + return FormNodeViewTypes; + } } diff --git a/src/app/forms/components/field-error-message/field-error-message.component.spec.ts b/src/app/forms/components/field-error-message/field-error-message.component.spec.ts index 7afdf48b71..d5aa120cbc 100644 --- a/src/app/forms/components/field-error-message/field-error-message.component.spec.ts +++ b/src/app/forms/components/field-error-message/field-error-message.component.spec.ts @@ -3,22 +3,22 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FieldErrorMessageComponent } from './field-error-message.component'; describe('FieldErrorMessageComponent', () => { - let component: FieldErrorMessageComponent; - let fixture: ComponentFixture; + let component: FieldErrorMessageComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [FieldErrorMessageComponent], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [FieldErrorMessageComponent], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(FieldErrorMessageComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(FieldErrorMessageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/components/field-error-message/field-error-message.component.ts b/src/app/forms/components/field-error-message/field-error-message.component.ts index 295d923983..63915294d5 100644 --- a/src/app/forms/components/field-error-message/field-error-message.component.ts +++ b/src/app/forms/components/field-error-message/field-error-message.component.ts @@ -1,10 +1,10 @@ import { Component, Input } from '@angular/core'; @Component({ - selector: 'app-field-error-message', - templateUrl: './field-error-message.component.html', + selector: 'app-field-error-message', + templateUrl: './field-error-message.component.html', }) export class FieldErrorMessageComponent { - @Input() name = ''; - @Input() error?: string | null; + @Input() name = ''; + @Input() error?: string | null; } diff --git a/src/app/forms/components/field-warning-message/field-warning-message.component.spec.ts b/src/app/forms/components/field-warning-message/field-warning-message.component.spec.ts index b4f1fe5fe1..05449e3ca4 100644 --- a/src/app/forms/components/field-warning-message/field-warning-message.component.spec.ts +++ b/src/app/forms/components/field-warning-message/field-warning-message.component.spec.ts @@ -3,21 +3,20 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FieldWarningMessageComponent } from './field-warning-message.component'; describe('FieldWarningMessageComponent', () => { - let component: FieldWarningMessageComponent; - let fixture: ComponentFixture; + let component: FieldWarningMessageComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [FieldWarningMessageComponent], - }) - .compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [FieldWarningMessageComponent], + }).compileComponents(); - fixture = TestBed.createComponent(FieldWarningMessageComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(FieldWarningMessageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/components/field-warning-message/field-warning-message.component.ts b/src/app/forms/components/field-warning-message/field-warning-message.component.ts index 72d1b782f1..9a0f7e52ae 100644 --- a/src/app/forms/components/field-warning-message/field-warning-message.component.ts +++ b/src/app/forms/components/field-warning-message/field-warning-message.component.ts @@ -1,10 +1,10 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; @Component({ - selector: 'app-field-warning-message', - templateUrl: './field-warning-message.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-field-warning-message', + templateUrl: './field-warning-message.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class FieldWarningMessageComponent { - @Input() warningMessage: string | undefined; + @Input() warningMessage: string | undefined; } diff --git a/src/app/forms/components/number-input/number-input.component.spec.ts b/src/app/forms/components/number-input/number-input.component.spec.ts index 20c2e2942e..e75b95bb90 100644 --- a/src/app/forms/components/number-input/number-input.component.spec.ts +++ b/src/app/forms/components/number-input/number-input.component.spec.ts @@ -8,36 +8,42 @@ import { FieldWarningMessageComponent } from '../field-warning-message/field-war import { NumberInputComponent } from './number-input.component'; @Component({ - selector: 'app-host-component', - template: `
+ selector: 'app-host-component', + template: `
`, - styles: [], + styles: [], }) class HostComponent { - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL }, ''), - }); + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL }, ''), + }); } describe('NumberInputComponent', () => { - let component: HostComponent; - let fixture: ComponentFixture; + let component: HostComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [HostComponent, NumberInputComponent, BaseControlComponent, FieldErrorMessageComponent, FieldWarningMessageComponent], - imports: [FormsModule, ReactiveFormsModule], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + HostComponent, + NumberInputComponent, + BaseControlComponent, + FieldErrorMessageComponent, + FieldWarningMessageComponent, + ], + imports: [FormsModule, ReactiveFormsModule], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(HostComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(HostComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/components/number-input/number-input.component.ts b/src/app/forms/components/number-input/number-input.component.ts index d099ed761a..9292c1c4a7 100644 --- a/src/app/forms/components/number-input/number-input.component.ts +++ b/src/app/forms/components/number-input/number-input.component.ts @@ -3,48 +3,49 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { BaseControlComponent } from '../base-control/base-control.component'; @Component({ - selector: 'app-number-input', - templateUrl: './number-input.component.html', - styleUrls: ['./number-input.component.scss'], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: NumberInputComponent, - multi: true, - }, - ], + selector: 'app-number-input', + templateUrl: './number-input.component.html', + styleUrls: ['./number-input.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: NumberInputComponent, + multi: true, + }, + ], }) export class NumberInputComponent extends BaseControlComponent implements AfterContentInit { - @Input() vehicleType?: string | null; - @Input() enableDecimals: boolean | undefined = false; - get style(): string { - return `govuk-input ${this.width ? `govuk-input--width-${this.width}` : ''}`; - } + @Input() vehicleType?: string | null; + @Input() enableDecimals: boolean | undefined = false; + get style(): string { + return `govuk-input ${this.width ? `govuk-input--width-${this.width}` : ''}`; + } - get getWarningMessage(): string { + get getWarningMessage(): string { + if (this.isCorrectVehicleType()) { + if (this.shouldDisplayLengthWarning()) + return 'This length dimension field value is greater than 12,000mm. Check your input before proceeding'; + if (this.shouldDisplayWidthWarning()) + return 'This width dimension field value is greater than 2,600mm. Check your input before proceeding'; + } + return ''; + } - if (this.isCorrectVehicleType()) { - if (this.shouldDisplayLengthWarning()) return 'This length dimension field value is greater than 12,000mm. Check your input before proceeding'; - if (this.shouldDisplayWidthWarning()) return 'This width dimension field value is greater than 2,600mm. Check your input before proceeding'; - } - return ''; - } + shouldDisplayLengthWarning(): boolean { + return this.label === 'Length' && Number.parseInt(this.value, 10) > 12000; + } + shouldDisplayWidthWarning(): boolean { + return this.label === 'Width' && Number.parseInt(this.value, 10) > 2600; + } - shouldDisplayLengthWarning(): boolean { - return this.label === 'Length' && parseInt(this.value, 10) > 12000; - } - shouldDisplayWidthWarning(): boolean { - return this.label === 'Width' && parseInt(this.value, 10) > 2600; - } + isCorrectVehicleType(): boolean { + return this.vehicleType === 'hgv' || this.vehicleType === 'trl'; + } - isCorrectVehicleType(): boolean { - return this.vehicleType === 'hgv' || this.vehicleType === 'trl'; - } - - override ngAfterContentInit(): void { - super.ngAfterContentInit(); - if (this.control) { - this.control.meta.customId = this.name; - } - } + override ngAfterContentInit(): void { + super.ngAfterContentInit(); + if (this.control) { + this.control.meta.customId = this.name; + } + } } diff --git a/src/app/forms/components/radio-group/radio-group.component.spec.ts b/src/app/forms/components/radio-group/radio-group.component.spec.ts index 79c2881a0f..bda7a4d031 100644 --- a/src/app/forms/components/radio-group/radio-group.component.spec.ts +++ b/src/app/forms/components/radio-group/radio-group.component.spec.ts @@ -2,75 +2,75 @@ import { Component } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; -import { ReferenceDataService } from '@services/reference-data/reference-data.service'; import { provideMockStore } from '@ngrx/store/testing'; +import { ReferenceDataService } from '@services/reference-data/reference-data.service'; import { initialAppState } from '@store/.'; -import { CustomFormControl, FormNodeTypes, FormNodeOption } from '../../services/dynamic-form.types'; -import { RadioGroupComponent } from './radio-group.component'; +import { CustomFormControl, FormNodeOption, FormNodeTypes } from '../../services/dynamic-form.types'; import { BaseControlComponent } from '../base-control/base-control.component'; import { FieldErrorMessageComponent } from '../field-error-message/field-error-message.component'; +import { RadioGroupComponent } from './radio-group.component'; @Component({ - selector: 'app-host-component', - template: `
+ selector: 'app-host-component', + template: `
`, - styles: [], + styles: [], }) class HostComponent { - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), - }); - options: FormNodeOption[] = [ - { label: 'Value 1', value: '1' }, - { label: 'Value 2', value: '2' }, - { label: 'Value 3', value: '3' }, - ]; + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), + }); + options: FormNodeOption[] = [ + { label: 'Value 1', value: '1' }, + { label: 'Value 2', value: '2' }, + { label: 'Value 3', value: '3' }, + ]; } describe('RadioGroupComponent', () => { - let component: HostComponent; - let fixture: ComponentFixture; + let component: HostComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [HostComponent, RadioGroupComponent, BaseControlComponent, FieldErrorMessageComponent], - imports: [FormsModule, ReactiveFormsModule], - providers: [ReferenceDataService, provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [HostComponent, RadioGroupComponent, BaseControlComponent, FieldErrorMessageComponent], + imports: [FormsModule, ReactiveFormsModule], + providers: [ReferenceDataService, provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(HostComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(HostComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - describe('value', () => { - it('should be propagated from element to the form control', () => { - const foo = component.form.get('foo'); - const radios = fixture.debugElement.queryAll(By.css('input[type="radio"]')); - expect(radios).toHaveLength(3); + describe('value', () => { + it('should be propagated from element to the form control', () => { + const foo = component.form.get('foo'); + const radios = fixture.debugElement.queryAll(By.css('input[type="radio"]')); + expect(radios).toHaveLength(3); - (radios[0].nativeElement as HTMLInputElement).click(); - expect(foo?.value).toBe('1'); - (radios[1].nativeElement as HTMLInputElement).click(); - expect(foo?.value).toBe('2'); - (radios[1].nativeElement as HTMLInputElement).click(); - expect(foo?.value).not.toBeNull(); - }); + (radios[0].nativeElement as HTMLInputElement).click(); + expect(foo?.value).toBe('1'); + (radios[1].nativeElement as HTMLInputElement).click(); + expect(foo?.value).toBe('2'); + (radios[1].nativeElement as HTMLInputElement).click(); + expect(foo?.value).not.toBeNull(); + }); - it('should check a radio button when the form value is updated', () => { - component.form.patchValue({ foo: '2' }); - fixture.detectChanges(); - const radios2 = fixture.debugElement.queryAll(By.css('input[checked=true]')); - expect(radios2).toHaveLength(1); - expect(radios2[0].nativeElement.id).toBe('foo-2-radio'); - component.form.patchValue({ foo: '3' }); - fixture.detectChanges(); - const radios3 = fixture.debugElement.queryAll(By.css('input[checked=true]')); - expect(radios3).toHaveLength(1); - expect(radios3[0].nativeElement.id).toBe('foo-3-radio'); - }); - }); + it('should check a radio button when the form value is updated', () => { + component.form.patchValue({ foo: '2' }); + fixture.detectChanges(); + const radios2 = fixture.debugElement.queryAll(By.css('input[checked=true]')); + expect(radios2).toHaveLength(1); + expect(radios2[0].nativeElement.id).toBe('foo-2-radio'); + component.form.patchValue({ foo: '3' }); + fixture.detectChanges(); + const radios3 = fixture.debugElement.queryAll(By.css('input[checked=true]')); + expect(radios3).toHaveLength(1); + expect(radios3[0].nativeElement.id).toBe('foo-3-radio'); + }); + }); }); diff --git a/src/app/forms/components/radio-group/radio-group.component.ts b/src/app/forms/components/radio-group/radio-group.component.ts index c57aa7116f..eb8873fd8f 100644 --- a/src/app/forms/components/radio-group/radio-group.component.ts +++ b/src/app/forms/components/radio-group/radio-group.component.ts @@ -4,33 +4,32 @@ import { FormNodeOption } from '@forms/services/dynamic-form.types'; import { BaseControlComponent } from '../base-control/base-control.component'; @Component({ - selector: 'app-radio-group', - templateUrl: './radio-group.component.html', - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: RadioGroupComponent, - multi: true, - }, - ], - styleUrls: ['./radio-group.component.scss'], + selector: 'app-radio-group', + templateUrl: './radio-group.component.html', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: RadioGroupComponent, + multi: true, + }, + ], + styleUrls: ['./radio-group.component.scss'], }) export class RadioGroupComponent extends BaseControlComponent { - @Input() options: FormNodeOption[] = []; - @Input() inline = false; + @Input() options: FormNodeOption[] = []; + @Input() inline = false; - getLabel(value: string | number | boolean | null): string | undefined { - return this.options.find((option) => option.value === value)?.label; - } + getLabel(value: string | number | boolean | null): string | undefined { + return this.options.find((option) => option.value === value)?.label; + } - trackByFn = (index: number): number => index; - - getId(value: string | number | boolean | null, name: string) { - const id = `${name}-${value}-radio`; - if (this.control) { - this.control.meta.customId = id; - } - return id; - } + trackByFn = (index: number): number => index; + getId(value: string | number | boolean | null, name: string) { + const id = `${name}-${value}-radio`; + if (this.control) { + this.control.meta.customId = id; + } + return id; + } } diff --git a/src/app/forms/components/radio-group/radio-group.stories.ts b/src/app/forms/components/radio-group/radio-group.stories.ts index 7bcde00aad..38ea5fee0b 100644 --- a/src/app/forms/components/radio-group/radio-group.stories.ts +++ b/src/app/forms/components/radio-group/radio-group.stories.ts @@ -1,60 +1,60 @@ import { CommonModule } from '@angular/common'; import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { Meta, moduleMetadata, Story } from '@storybook/angular'; +import { Meta, Story, moduleMetadata } from '@storybook/angular'; import { BaseControlComponent } from '../base-control/base-control.component'; import { RadioGroupComponent } from './radio-group.component'; export default { - title: 'Forms/Radio button group', - component: RadioGroupComponent, - decorators: [ - moduleMetadata({ - declarations: [RadioGroupComponent, BaseControlComponent], - imports: [CommonModule, FormsModule, ReactiveFormsModule] - }) - ] + title: 'Forms/Radio button group', + component: RadioGroupComponent, + decorators: [ + moduleMetadata({ + declarations: [RadioGroupComponent, BaseControlComponent], + imports: [CommonModule, FormsModule, ReactiveFormsModule], + }), + ], } as Meta; -const Template: Story = args => { - const { label, options, name, hint, value = null, disabled = false, validators = [] } = args; - const form = new FormGroup({ [name]: new FormControl({ value, disabled }, validators) }); - return { - component: RadioGroupComponent, - template: `
{{ form.value | json }}
`, - props: { - form, - label, - name, - options, - hint - } - }; +const Template: Story = (args) => { + const { label, options, name, hint, value = null, disabled = false, validators = [] } = args; + const form = new FormGroup({ [name]: new FormControl({ value, disabled }, validators) }); + return { + component: RadioGroupComponent, + template: `
{{ form.value | json }}
`, + props: { + form, + label, + name, + options, + hint, + }, + }; }; const defaultArgs = { - label: 'Colour picker', - name: 'color', - options: [ - { label: 'Red', value: 'red' }, - { label: 'Yellow', value: 'yellow', hint: 'this is the colour of the sun' }, - { label: 'Blue', value: 'blue', hint: 'this is the colour of the sea' } - ], - hint: 'These are the three primary colours' + label: 'Colour picker', + name: 'color', + options: [ + { label: 'Red', value: 'red' }, + { label: 'Yellow', value: 'yellow', hint: 'this is the colour of the sun' }, + { label: 'Blue', value: 'blue', hint: 'this is the colour of the sea' }, + ], + hint: 'These are the three primary colours', }; export const Enabled = Template.bind({}); Enabled.args = { - ...defaultArgs + ...defaultArgs, }; export const Disabled = Template.bind({}); Disabled.args = { - ...defaultArgs, - disabled: true + ...defaultArgs, + disabled: true, }; export const Initilisation = Template.bind({}); Initilisation.args = { - ...defaultArgs, - value: 'red' + ...defaultArgs, + value: 'red', }; diff --git a/src/app/forms/components/read-only/read-only.component.spec.ts b/src/app/forms/components/read-only/read-only.component.spec.ts index 357a5516ee..ec72b6c376 100644 --- a/src/app/forms/components/read-only/read-only.component.spec.ts +++ b/src/app/forms/components/read-only/read-only.component.spec.ts @@ -7,36 +7,36 @@ import { BaseControlComponent } from '../base-control/base-control.component'; import { ReadOnlyComponent } from './read-only.component'; @Component({ - selector: 'app-host-component', - template: `
+ selector: 'app-host-component', + template: `
`, - styles: [], + styles: [], }) class HostComponent { - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL }, ''), - }); + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL }, ''), + }); } describe('ReadOnlyComponent', () => { - let component: HostComponent; - let fixture: ComponentFixture; + let component: HostComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [BaseControlComponent, HostComponent, ReadOnlyComponent], - imports: [FormsModule, ReactiveFormsModule, SharedModule], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BaseControlComponent, HostComponent, ReadOnlyComponent], + imports: [FormsModule, ReactiveFormsModule, SharedModule], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(HostComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(HostComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/components/read-only/read-only.component.ts b/src/app/forms/components/read-only/read-only.component.ts index c0225c4ee4..0764f64076 100644 --- a/src/app/forms/components/read-only/read-only.component.ts +++ b/src/app/forms/components/read-only/read-only.component.ts @@ -3,17 +3,17 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { BaseControlComponent } from '../base-control/base-control.component'; @Component({ - selector: 'app-read-only', - templateUrl: './read-only.component.html', - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: ReadOnlyComponent, - multi: true, - }, - ], + selector: 'app-read-only', + templateUrl: './read-only.component.html', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: ReadOnlyComponent, + multi: true, + }, + ], }) export class ReadOnlyComponent extends BaseControlComponent { - @Input() readOnlySuffix?: string; - @Input() date?: boolean = false; + @Input() readOnlySuffix?: string; + @Input() date?: boolean = false; } diff --git a/src/app/forms/components/required-standard-select/required-standard-select.component.spec.ts b/src/app/forms/components/required-standard-select/required-standard-select.component.spec.ts index c037993ff8..acd4a5827d 100644 --- a/src/app/forms/components/required-standard-select/required-standard-select.component.spec.ts +++ b/src/app/forms/components/required-standard-select/required-standard-select.component.spec.ts @@ -2,101 +2,116 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { EUVehicleCategory } from '@dvsa/cvs-type-definitions/types/required-standards/defects/enums/euVehicleCategory.enum.js'; -import { RequiredStandard, RequiredStandardTaxonomySection } from '@dvsa/cvs-type-definitions/types/required-standards/defects/get'; +import { + RequiredStandard, + RequiredStandardTaxonomySection, +} from '@dvsa/cvs-type-definitions/types/required-standards/defects/get'; import { INSPECTION_TYPE } from '@models/test-results/test-result-required-standard.model'; import { provideMockStore } from '@ngrx/store/testing'; import { initialAppState } from '@store/index'; import { RequiredStandardSelectComponent } from './required-standard-select.component'; describe('RequiredStandardSelectComponent', () => { - let component: RequiredStandardSelectComponent; - let fixture: ComponentFixture; - let router: Router; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [RouterTestingModule], - declarations: [RequiredStandardSelectComponent], - providers: [provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(RequiredStandardSelectComponent); - router = TestBed.inject(Router); - component = fixture.componentInstance; - fixture.detectChanges(); - jest.clearAllMocks(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('handleSelectBasicOrNormal', () => { - it('should work for basic inspection', () => { - component.basicAndNormalRequiredStandards = { - basic: ['basic' as unknown as RequiredStandardTaxonomySection, 'basic1' as unknown as RequiredStandardTaxonomySection], - normal: ['normal' as unknown as RequiredStandardTaxonomySection, 'normal1' as unknown as RequiredStandardTaxonomySection], - euVehicleCategories: [EUVehicleCategory.M1], - }; - - component.handleSelectBasicOrNormal(INSPECTION_TYPE.BASIC); - - expect(component.requiredStandards).toStrictEqual(['basic', 'basic1']); - }); - it('should work for normal inspection', () => { - component.basicAndNormalRequiredStandards = { - basic: ['basic' as unknown as RequiredStandardTaxonomySection, 'basic1' as unknown as RequiredStandardTaxonomySection], - normal: ['normal' as unknown as RequiredStandardTaxonomySection, 'normal1' as unknown as RequiredStandardTaxonomySection], - euVehicleCategories: [EUVehicleCategory.M1], - }; - - component.handleSelectBasicOrNormal(INSPECTION_TYPE.NORMAL); - - expect(component.requiredStandards).toStrictEqual(['normal', 'normal1']); - }); - }); - - describe('handleSelect', () => { - it('should handle when I pick an inspection type', () => { - const spy = jest.spyOn(component, 'handleSelectBasicOrNormal'); - - component.handleSelect(INSPECTION_TYPE.BASIC, Types.InspectionType); - - expect(spy).toHaveBeenCalled(); - expect(component.selectedInspectionType).toBe(INSPECTION_TYPE.BASIC); - expect(component.selectedSection).toBeUndefined(); - expect(component.selectedRequiredStandard).toBeUndefined(); - }); - it('should handle when I pick a section', () => { - component.handleSelect('section' as unknown as RequiredStandardTaxonomySection, Types.Section); - - expect(component.selectedSection).toBe('section'); - expect(component.selectedRequiredStandard).toBeUndefined(); - }); - it('should handle when I pick a required standard', () => { - const spy = jest.spyOn(router, 'navigate'); - - component.handleSelect({ refCalculation: '1.2' } as unknown as RequiredStandard, Types.RequiredStandard); - - expect(spy).toHaveBeenCalled(); - expect(spy).toHaveBeenCalledWith(['normal/1.2'], expect.anything()); - expect(component.selectedRequiredStandard).toStrictEqual({ refCalculation: '1.2' }); - }); - it('should error when I try call it with another type', () => { - const spy = jest.spyOn(console, 'error'); - - component.handleSelect(undefined, undefined); - - expect(spy).toHaveBeenCalled(); - }); - }); + let component: RequiredStandardSelectComponent; + let fixture: ComponentFixture; + let router: Router; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [RouterTestingModule], + declarations: [RequiredStandardSelectComponent], + providers: [provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(RequiredStandardSelectComponent); + router = TestBed.inject(Router); + component = fixture.componentInstance; + fixture.detectChanges(); + jest.clearAllMocks(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('handleSelectBasicOrNormal', () => { + it('should work for basic inspection', () => { + component.basicAndNormalRequiredStandards = { + basic: [ + 'basic' as unknown as RequiredStandardTaxonomySection, + 'basic1' as unknown as RequiredStandardTaxonomySection, + ], + normal: [ + 'normal' as unknown as RequiredStandardTaxonomySection, + 'normal1' as unknown as RequiredStandardTaxonomySection, + ], + euVehicleCategories: [EUVehicleCategory.M1], + }; + + component.handleSelectBasicOrNormal(INSPECTION_TYPE.BASIC); + + expect(component.requiredStandards).toStrictEqual(['basic', 'basic1']); + }); + it('should work for normal inspection', () => { + component.basicAndNormalRequiredStandards = { + basic: [ + 'basic' as unknown as RequiredStandardTaxonomySection, + 'basic1' as unknown as RequiredStandardTaxonomySection, + ], + normal: [ + 'normal' as unknown as RequiredStandardTaxonomySection, + 'normal1' as unknown as RequiredStandardTaxonomySection, + ], + euVehicleCategories: [EUVehicleCategory.M1], + }; + + component.handleSelectBasicOrNormal(INSPECTION_TYPE.NORMAL); + + expect(component.requiredStandards).toStrictEqual(['normal', 'normal1']); + }); + }); + + describe('handleSelect', () => { + it('should handle when I pick an inspection type', () => { + const spy = jest.spyOn(component, 'handleSelectBasicOrNormal'); + + component.handleSelect(INSPECTION_TYPE.BASIC, Types.InspectionType); + + expect(spy).toHaveBeenCalled(); + expect(component.selectedInspectionType).toBe(INSPECTION_TYPE.BASIC); + expect(component.selectedSection).toBeUndefined(); + expect(component.selectedRequiredStandard).toBeUndefined(); + }); + it('should handle when I pick a section', () => { + component.handleSelect('section' as unknown as RequiredStandardTaxonomySection, Types.Section); + + expect(component.selectedSection).toBe('section'); + expect(component.selectedRequiredStandard).toBeUndefined(); + }); + it('should handle when I pick a required standard', () => { + const spy = jest.spyOn(router, 'navigate'); + + component.handleSelect({ refCalculation: '1.2' } as unknown as RequiredStandard, Types.RequiredStandard); + + expect(spy).toHaveBeenCalled(); + expect(spy).toHaveBeenCalledWith(['normal/1.2'], expect.anything()); + expect(component.selectedRequiredStandard).toStrictEqual({ refCalculation: '1.2' }); + }); + it('should error when I try call it with another type', () => { + const spy = jest.spyOn(console, 'error'); + + component.handleSelect(undefined, undefined); + + expect(spy).toHaveBeenCalled(); + }); + }); }); enum Types { - InspectionType, - Section, - // eslint-disable-next-line @typescript-eslint/no-shadow - RequiredStandard, + InspectionType = 0, + Section = 1, + // eslint-disable-next-line @typescript-eslint/no-shadow + RequiredStandard = 2, } diff --git a/src/app/forms/components/required-standard-select/required-standard-select.component.ts b/src/app/forms/components/required-standard-select/required-standard-select.component.ts index b9aa6d2bb8..ee794eae54 100644 --- a/src/app/forms/components/required-standard-select/required-standard-select.component.ts +++ b/src/app/forms/components/required-standard-select/required-standard-select.component.ts @@ -1,9 +1,9 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { - DefectGETRequiredStandards, - RequiredStandard, - RequiredStandardTaxonomySection, + DefectGETRequiredStandards, + RequiredStandard, + RequiredStandardTaxonomySection, } from '@dvsa/cvs-type-definitions/types/required-standards/defects/get'; import { INSPECTION_TYPE } from '@models/test-results/test-result-required-standard.model'; import { Store } from '@ngrx/store'; @@ -12,91 +12,97 @@ import { getRequiredStandardsState } from '@store/required-standards/selectors/r import { Subject, takeUntil } from 'rxjs'; @Component({ - selector: 'app-required-standard-select', - templateUrl: './required-standard-select.component.html', - styleUrls: ['./required-standard-select.component.scss'], + selector: 'app-required-standard-select', + templateUrl: './required-standard-select.component.html', + styleUrls: ['./required-standard-select.component.scss'], }) export class RequiredStandardSelectComponent implements OnInit, OnDestroy { + requiredStandards?: RequiredStandardTaxonomySection[]; + normalAndBasic?: boolean; + isEditing = false; + selectedInspectionType?: INSPECTION_TYPE; + selectedSection?: RequiredStandardTaxonomySection; + selectedRequiredStandard?: RequiredStandard; + basicAndNormalRequiredStandards?: DefectGETRequiredStandards; - requiredStandards?: RequiredStandardTaxonomySection[]; - normalAndBasic?: boolean; - isEditing = false; - selectedInspectionType?: INSPECTION_TYPE; - selectedSection?: RequiredStandardTaxonomySection; - selectedRequiredStandard?: RequiredStandard; - basicAndNormalRequiredStandards?: DefectGETRequiredStandards; + onDestroy$ = new Subject(); - onDestroy$ = new Subject(); + constructor( + private requiredStandardsStore: Store, + private router: Router, + private route: ActivatedRoute + ) {} - constructor( - private requiredStandardsStore: Store, - private router: Router, - private route: ActivatedRoute, - ) {} + ngOnInit(): void { + this.requiredStandardsStore + .select(getRequiredStandardsState) + .pipe(takeUntil(this.onDestroy$)) + .subscribe((requiredStandards) => { + if (requiredStandards.basic.length) { + this.normalAndBasic = true; + this.requiredStandards = []; + this.basicAndNormalRequiredStandards = requiredStandards; + } else { + this.requiredStandards = requiredStandards.normal; + this.selectedInspectionType = INSPECTION_TYPE.NORMAL; + } + }); + } - ngOnInit(): void { - this.requiredStandardsStore.select(getRequiredStandardsState).pipe(takeUntil(this.onDestroy$)).subscribe((requiredStandards) => { - if (requiredStandards.basic.length) { - this.normalAndBasic = true; - this.requiredStandards = []; - this.basicAndNormalRequiredStandards = requiredStandards; - } else { - this.requiredStandards = requiredStandards.normal; - this.selectedInspectionType = INSPECTION_TYPE.NORMAL; - } - }); + ngOnDestroy(): void { + this.onDestroy$.next(true); + this.onDestroy$.complete(); + } - } + handleSelectBasicOrNormal(inspectionType: INSPECTION_TYPE): void { + this.requiredStandards = + inspectionType === INSPECTION_TYPE.BASIC + ? this.basicAndNormalRequiredStandards?.basic + : this.basicAndNormalRequiredStandards?.normal; + } - ngOnDestroy(): void { - this.onDestroy$.next(true); - this.onDestroy$.complete(); - } + handleSelect(selected?: INSPECTION_TYPE | RequiredStandardTaxonomySection | RequiredStandard, type?: Types): void { + switch (type) { + case Types.InspectionType: + this.handleSelectBasicOrNormal(selected as INSPECTION_TYPE); + this.selectedInspectionType = selected as INSPECTION_TYPE; + this.selectedSection = undefined; + this.selectedRequiredStandard = undefined; + break; + case Types.Section: + this.selectedSection = selected as RequiredStandardTaxonomySection; + this.selectedRequiredStandard = undefined; + break; + case Types.RequiredStandard: + this.selectedRequiredStandard = selected as RequiredStandard; + if (this.selectedRequiredStandard) { + void this.router.navigate( + [`${this.selectedInspectionType}/${this.selectedRequiredStandard.refCalculation}`], + { + relativeTo: this.route, + queryParamsHandling: 'merge', + } + ); + } + break; + default: + console.error('Unsupported:'); + break; + } + } - handleSelectBasicOrNormal(inspectionType: INSPECTION_TYPE): void { - this.requiredStandards = inspectionType === INSPECTION_TYPE.BASIC - ? this.basicAndNormalRequiredStandards?.basic : this.basicAndNormalRequiredStandards?.normal; - } + get types(): typeof Types { + return Types; + } - handleSelect(selected?: INSPECTION_TYPE | RequiredStandardTaxonomySection | RequiredStandard, type?: Types): void { - switch (type) { - case Types.InspectionType: - this.handleSelectBasicOrNormal(selected as INSPECTION_TYPE); - this.selectedInspectionType = selected as INSPECTION_TYPE; - this.selectedSection = undefined; - this.selectedRequiredStandard = undefined; - break; - case Types.Section: - this.selectedSection = selected as RequiredStandardTaxonomySection; - this.selectedRequiredStandard = undefined; - break; - case Types.RequiredStandard: - this.selectedRequiredStandard = selected as RequiredStandard; - if (this.selectedRequiredStandard) { - void this.router.navigate([`${this.selectedInspectionType}/${this.selectedRequiredStandard.refCalculation}`], { - relativeTo: this.route, - queryParamsHandling: 'merge', - }); - } - break; - default: - console.error('Unsupported:'); - break; - } - } - - get types(): typeof Types { - return Types; - } - - get inspectionTypes(): INSPECTION_TYPE[] { - return Object.values(INSPECTION_TYPE) as INSPECTION_TYPE[]; - } + get inspectionTypes(): INSPECTION_TYPE[] { + return Object.values(INSPECTION_TYPE) as INSPECTION_TYPE[]; + } } enum Types { - InspectionType, - Section, - // eslint-disable-next-line @typescript-eslint/no-shadow - RequiredStandard, + InspectionType = 0, + Section = 1, + // eslint-disable-next-line @typescript-eslint/no-shadow + RequiredStandard = 2, } diff --git a/src/app/forms/components/select/select.component.spec.ts b/src/app/forms/components/select/select.component.spec.ts index 2fd78b8035..5d599a2047 100644 --- a/src/app/forms/components/select/select.component.spec.ts +++ b/src/app/forms/components/select/select.component.spec.ts @@ -9,63 +9,63 @@ import { FieldErrorMessageComponent } from '../field-error-message/field-error-m import { SelectComponent } from './select.component'; @Component({ - selector: 'app-host-component', - template: `
+ selector: 'app-host-component', + template: `
`, - styles: [], + styles: [], }) class HostComponent { - @ViewChild(SelectComponent) select?: SelectComponent; + @ViewChild(SelectComponent) select?: SelectComponent; - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), - }); - options: FormNodeOption[] = [ - { label: 'Value 1', value: '1' }, - { label: 'Value 2', value: '2' }, - { label: 'Value 3', value: '3' }, - ]; + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), + }); + options: FormNodeOption[] = [ + { label: 'Value 1', value: '1' }, + { label: 'Value 2', value: '2' }, + { label: 'Value 3', value: '3' }, + ]; } describe('SelectComponent', () => { - let component: HostComponent; - let fixture: ComponentFixture; + let component: HostComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [BaseControlComponent, FieldErrorMessageComponent, HostComponent, SelectComponent], - imports: [FormsModule, ReactiveFormsModule], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BaseControlComponent, FieldErrorMessageComponent, HostComponent, SelectComponent], + imports: [FormsModule, ReactiveFormsModule], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(HostComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(HostComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - describe('value', () => { - it('should be propagated from element to the form control', () => { - const select = fixture.debugElement.query(By.css('select')).nativeElement as HTMLSelectElement; - const foo = component.form.get('foo'); - select.selectedIndex = 1; - select.dispatchEvent(new Event('change')); + describe('value', () => { + it('should be propagated from element to the form control', () => { + const select = fixture.debugElement.query(By.css('select')).nativeElement as HTMLSelectElement; + const foo = component.form.get('foo'); + select.selectedIndex = 1; + select.dispatchEvent(new Event('change')); - expect(foo?.value).toBe('1'); - expect(foo?.value).not.toBeNull(); - }); + expect(foo?.value).toBe('1'); + expect(foo?.value).not.toBeNull(); + }); - it('should select the right option when the form value is updated', () => { - component.form.patchValue({ foo: '2' }); - fixture.detectChanges(); - const select = fixture.debugElement.query(By.css('select')); - expect(select).toBeTruthy(); - expect(select.nativeElement.value).toBe('2: 2'); - }); - }); + it('should select the right option when the form value is updated', () => { + component.form.patchValue({ foo: '2' }); + fixture.detectChanges(); + const select = fixture.debugElement.query(By.css('select')); + expect(select).toBeTruthy(); + expect(select.nativeElement.value).toBe('2: 2'); + }); + }); }); diff --git a/src/app/forms/components/select/select.component.ts b/src/app/forms/components/select/select.component.ts index 31b2809ccf..290e91da29 100644 --- a/src/app/forms/components/select/select.component.ts +++ b/src/app/forms/components/select/select.component.ts @@ -1,27 +1,25 @@ -import { - Component, EventEmitter, Input, Output, -} from '@angular/core'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { FormNodeOption } from '@forms/services/dynamic-form.types'; import { BaseControlComponent } from '../base-control/base-control.component'; @Component({ - selector: 'app-select[options]', - templateUrl: './select.component.html', - styleUrls: ['./select.component.scss'], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: SelectComponent, - multi: true, - }, - ], + selector: 'app-select[options]', + templateUrl: './select.component.html', + styleUrls: ['./select.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: SelectComponent, + multi: true, + }, + ], }) export class SelectComponent extends BaseControlComponent { - @Input() options!: Array>; - @Output() blur = new EventEmitter(); + @Input() options!: Array>; + @Output() blur = new EventEmitter(); - get style(): string { - return `govuk-select ${this.width ? `govuk-input--width-${this.width}` : ''}`; - } + get style(): string { + return `govuk-select ${this.width ? `govuk-input--width-${this.width}` : ''}`; + } } diff --git a/src/app/forms/components/select/select.stories.ts b/src/app/forms/components/select/select.stories.ts index 21fc3c0959..6f51c82cb4 100644 --- a/src/app/forms/components/select/select.stories.ts +++ b/src/app/forms/components/select/select.stories.ts @@ -1,60 +1,60 @@ import { CommonModule } from '@angular/common'; import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { Meta, moduleMetadata, Story } from '@storybook/angular'; +import { Meta, Story, moduleMetadata } from '@storybook/angular'; import { BaseControlComponent } from '../base-control/base-control.component'; import { SelectComponent } from './select.component'; export default { - title: 'Forms/Select', - component: SelectComponent, - decorators: [ - moduleMetadata({ - declarations: [SelectComponent, BaseControlComponent], - imports: [CommonModule, FormsModule, ReactiveFormsModule] - }) - ] + title: 'Forms/Select', + component: SelectComponent, + decorators: [ + moduleMetadata({ + declarations: [SelectComponent, BaseControlComponent], + imports: [CommonModule, FormsModule, ReactiveFormsModule], + }), + ], } as Meta; -const Template: Story = args => { - const { label, options, name, hint, value = null, disabled = false, validators = [] } = args; - const form = new FormGroup({ [name]: new FormControl({ value, disabled }, validators) }); - return { - component: SelectComponent, - template: `
{{ form.value | json }}
`, - props: { - form, - label, - name, - options, - hint - } - }; +const Template: Story = (args) => { + const { label, options, name, hint, value = null, disabled = false, validators = [] } = args; + const form = new FormGroup({ [name]: new FormControl({ value, disabled }, validators) }); + return { + component: SelectComponent, + template: `
{{ form.value | json }}
`, + props: { + form, + label, + name, + options, + hint, + }, + }; }; const defaultArgs = { - label: 'Colour picker', - name: 'color', - options: [ - { label: 'Red', value: 'red' }, - { label: 'Yellow', value: 'yellow', hint: 'this is the colour of the sun' }, - { label: 'Blue', value: 'blue', hint: 'this is the colour of the sea' } - ], - hint: 'These are the three primary colours' + label: 'Colour picker', + name: 'color', + options: [ + { label: 'Red', value: 'red' }, + { label: 'Yellow', value: 'yellow', hint: 'this is the colour of the sun' }, + { label: 'Blue', value: 'blue', hint: 'this is the colour of the sea' }, + ], + hint: 'These are the three primary colours', }; export const Enabled = Template.bind({}); Enabled.args = { - ...defaultArgs + ...defaultArgs, }; export const Disabled = Template.bind({}); Disabled.args = { - ...defaultArgs, - disabled: true + ...defaultArgs, + disabled: true, }; export const Initilisation = Template.bind({}); Initilisation.args = { - ...defaultArgs, - value: 'red' + ...defaultArgs, + value: 'red', }; diff --git a/src/app/forms/components/suggestive-input/suggestive-input.component.spec.ts b/src/app/forms/components/suggestive-input/suggestive-input.component.spec.ts index 8bd077eb04..ad37755123 100644 --- a/src/app/forms/components/suggestive-input/suggestive-input.component.spec.ts +++ b/src/app/forms/components/suggestive-input/suggestive-input.component.spec.ts @@ -9,70 +9,70 @@ import { FieldErrorMessageComponent } from '../field-error-message/field-error-m import { SuggestiveInputComponent } from './suggestive-input.component'; @Component({ - selector: 'app-host-component', - template: `
+ selector: 'app-host-component', + template: `
`, - styles: [], + styles: [], }) class HostComponent { - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, ''), - }); - options$: Observable = of([ - { label: 'Banana', value: 'banana' }, - { label: 'Apple', value: 'apple' }, - ]); + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, ''), + }); + options$: Observable = of([ + { label: 'Banana', value: 'banana' }, + { label: 'Apple', value: 'apple' }, + ]); } describe('SuggestiveInputComponent', () => { - let component: HostComponent; - let fixture: ComponentFixture; - let suggestiveInput: SuggestiveInputComponent; + let component: HostComponent; + let fixture: ComponentFixture; + let suggestiveInput: SuggestiveInputComponent; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [HostComponent, SuggestiveInputComponent, FieldErrorMessageComponent], - imports: [FormsModule, ReactiveFormsModule], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [HostComponent, SuggestiveInputComponent, FieldErrorMessageComponent], + imports: [FormsModule, ReactiveFormsModule], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(HostComponent); - component = fixture.componentInstance; - suggestiveInput = fixture.debugElement.query(By.directive(SuggestiveInputComponent)).componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(HostComponent); + component = fixture.componentInstance; + suggestiveInput = fixture.debugElement.query(By.directive(SuggestiveInputComponent)).componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - describe('getters', () => { - it('should retutn the correct class', () => { - suggestiveInput.width = FormNodeWidth.L; - expect(suggestiveInput.style).toBe('govuk-input govuk-input--width-10'); - suggestiveInput.width = undefined; - expect(suggestiveInput.style).toBe('govuk-input'); - }); - }); + describe('getters', () => { + it('should retutn the correct class', () => { + suggestiveInput.width = FormNodeWidth.L; + expect(suggestiveInput.style).toBe('govuk-input govuk-input--width-10'); + suggestiveInput.width = undefined; + expect(suggestiveInput.style).toBe('govuk-input'); + }); + }); - describe('SuggestiveInputComponent.prototype.handleChangeForOption.name', () => { - it('should find matching option and patch value', async () => { - await suggestiveInput.handleChangeForOption('Banana'); - expect(component.form.get('foo')?.value).toBe('banana'); - }); + describe('SuggestiveInputComponent.prototype.handleChangeForOption.name', () => { + it('should find matching option and patch value', async () => { + await suggestiveInput.handleChangeForOption('Banana'); + expect(component.form.get('foo')?.value).toBe('banana'); + }); - it('should not find matching option and patch `[INVALID_OPTION]`, control should also be invalid', async () => { - await suggestiveInput.handleChangeForOption('Orange'); - const foo = component.form.get('foo'); - expect(foo?.value).toBe('[INVALID_OPTION]'); - expect(foo?.invalid).toBeTruthy(); - }); + it('should not find matching option and patch `[INVALID_OPTION]`, control should also be invalid', async () => { + await suggestiveInput.handleChangeForOption('Orange'); + const foo = component.form.get('foo'); + expect(foo?.value).toBe('[INVALID_OPTION]'); + expect(foo?.invalid).toBeTruthy(); + }); - it('should not find matching option and patch empty string', async () => { - await suggestiveInput.handleChangeForOption(''); - expect(component.form.get('foo')?.value).toBe(''); - }); - }); + it('should not find matching option and patch empty string', async () => { + await suggestiveInput.handleChangeForOption(''); + expect(component.form.get('foo')?.value).toBe(''); + }); + }); }); diff --git a/src/app/forms/components/suggestive-input/suggestive-input.component.ts b/src/app/forms/components/suggestive-input/suggestive-input.component.ts index f60e0d2e11..ee36c0ce77 100644 --- a/src/app/forms/components/suggestive-input/suggestive-input.component.ts +++ b/src/app/forms/components/suggestive-input/suggestive-input.component.ts @@ -1,84 +1,78 @@ -import { - AfterContentInit, ChangeDetectionStrategy, - Component, - Input, OnInit, -} from '@angular/core'; +import { AfterContentInit, ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { MultiOption } from '@forms/models/options.model'; import { CustomValidators } from '@forms/validators/custom-validators'; -import { - Observable, - firstValueFrom, - skipWhile, take, -} from 'rxjs'; +import { Observable, firstValueFrom, skipWhile, take } from 'rxjs'; import { BaseControlComponent } from '../base-control/base-control.component'; @Component({ - selector: 'app-suggestive-input', - templateUrl: './suggestive-input.component.html', - styleUrls: ['./suggestive-input.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: SuggestiveInputComponent, - multi: true, - }, - ], + selector: 'app-suggestive-input', + templateUrl: './suggestive-input.component.html', + styleUrls: ['./suggestive-input.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: SuggestiveInputComponent, + multi: true, + }, + ], }) export class SuggestiveInputComponent extends BaseControlComponent implements AfterContentInit, OnInit { - @Input() options$!: Observable; - @Input() defaultValue = ''; + @Input() options$!: Observable; + @Input() defaultValue = ''; - field_value = ''; + field_value = ''; - ngOnInit(): void { - this.options$ - .pipe( - skipWhile((options) => !options.length), - take(1), - ) - // eslint-disable-next-line @typescript-eslint/no-misused-promises - .subscribe(async () => { - this.field_value = (await this.findOption(this.value, 'value'))?.label ?? ''; - }); - } + ngOnInit(): void { + this.options$ + .pipe( + skipWhile((options) => !options.length), + take(1) + ) + // eslint-disable-next-line @typescript-eslint/no-misused-promises + .subscribe(async () => { + this.field_value = (await this.findOption(this.value, 'value'))?.label ?? ''; + }); + } - override ngAfterContentInit() { - super.ngAfterContentInit(); - this.addValidators(); - } + override ngAfterContentInit() { + super.ngAfterContentInit(); + this.addValidators(); + } - get style(): string { - return `govuk-input${this.width ? ` govuk-input--width-${this.width}` : ''}`; - } + get style(): string { + return `govuk-input${this.width ? ` govuk-input--width-${this.width}` : ''}`; + } - async handleChangeForOption(value: string) { - const option = await this.findOption(value); + async handleChangeForOption(value: string) { + const option = await this.findOption(value); - this.field_value = option?.label ?? value; - // if option found, patch option value else if value patch `[INVALID_OPTION]` else value (empty string) - // eslint-disable-next-line no-nested-ternary - this.control?.patchValue(option ? option.value : value ? '[INVALID_OPTION]' : value); - this.cdr.markForCheck(); - } + this.field_value = option?.label ?? value; + // if option found, patch option value else if value patch `[INVALID_OPTION]` else value (empty string) + // eslint-disable-next-line no-nested-ternary + this.control?.patchValue(option ? option.value : value ? '[INVALID_OPTION]' : value); + this.cdr.markForCheck(); + } - /** - * Takes the value from the autocomplete element and looks for a matching option in the options array. - * Returns a promise of the found option or undefined if no match. - * @param {string} value - value to get option for - * @param {string} key - option search key. Defaults to `label` - * @returns `MultiOption | undefined` - */ - async findOption(val: string, key = 'label'): Promise { - return firstValueFrom(this.options$).then((options) => options.find((option) => option[key as keyof MultiOption] === val)); - } + /** + * Takes the value from the autocomplete element and looks for a matching option in the options array. + * Returns a promise of the found option or undefined if no match. + * @param {string} value - value to get option for + * @param {string} key - option search key. Defaults to `label` + * @returns `MultiOption | undefined` + */ + async findOption(val: string, key = 'label'): Promise { + return firstValueFrom(this.options$).then((options) => + options.find((option) => option[key as keyof MultiOption] === val) + ); + } - addValidators() { - this.control?.addValidators([CustomValidators.invalidOption]); - } + addValidators() { + this.control?.addValidators([CustomValidators.invalidOption]); + } - trackByFn(i: number, option: MultiOption) { - return option.value ?? i; - } + trackByFn(i: number, option: MultiOption) { + return option.value ?? i; + } } diff --git a/src/app/forms/components/switchable-input/switchable-input.component.spec.ts b/src/app/forms/components/switchable-input/switchable-input.component.spec.ts index 87a38408b1..ee1328e759 100644 --- a/src/app/forms/components/switchable-input/switchable-input.component.spec.ts +++ b/src/app/forms/components/switchable-input/switchable-input.component.spec.ts @@ -14,38 +14,38 @@ import { TextInputComponent } from '../text-input/text-input.component'; import { SwitchableInputComponent } from './switchable-input.component'; describe('SwitchableInputComponent', () => { - let component: SwitchableInputComponent; - let fixture: ComponentFixture; + let component: SwitchableInputComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ - AutocompleteComponent, - DateComponent, - FieldErrorMessageComponent, - NumberInputComponent, - RadioGroupComponent, - ReadOnlyComponent, - SelectComponent, - SuffixDirective, - SwitchableInputComponent, - TextAreaComponent, - TextInputComponent, - ], - imports: [FormsModule, ReactiveFormsModule], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + AutocompleteComponent, + DateComponent, + FieldErrorMessageComponent, + NumberInputComponent, + RadioGroupComponent, + ReadOnlyComponent, + SelectComponent, + SuffixDirective, + SwitchableInputComponent, + TextAreaComponent, + TextInputComponent, + ], + imports: [FormsModule, ReactiveFormsModule], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(SwitchableInputComponent); - component = fixture.componentInstance; - component.type = FormNodeEditTypes.TEXT; - component.form = new FormGroup({ foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL }, '') }); - component.name = 'foo'; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(SwitchableInputComponent); + component = fixture.componentInstance; + component.type = FormNodeEditTypes.TEXT; + component.form = new FormGroup({ foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL }, '') }); + component.name = 'foo'; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/components/switchable-input/switchable-input.component.ts b/src/app/forms/components/switchable-input/switchable-input.component.ts index 64a7f09dc6..921060ab53 100644 --- a/src/app/forms/components/switchable-input/switchable-input.component.ts +++ b/src/app/forms/components/switchable-input/switchable-input.component.ts @@ -5,52 +5,52 @@ import { FormNodeEditTypes, FormNodeWidth } from '@forms/services/dynamic-form.t import { Observable, of } from 'rxjs'; @Component({ - selector: 'app-switchable-input[form][type][name][isEditing]', - templateUrl: './switchable-input.component.html', + selector: 'app-switchable-input[form][type][name][isEditing]', + templateUrl: './switchable-input.component.html', }) export class SwitchableInputComponent implements OnInit { - @Input() type!: FormNodeEditTypes; - @Input() form!: FormGroup; - @Input() name!: string; - - @Input() isEditing = true; - - @Input() customId?: string; - @Input() idExtension?: number; - @Input() label?: string; - @Input() prefix?: string; - @Input() suffix?: string; - @Input() width?: FormNodeWidth; - @Input() options?: MultiOptions = []; - @Input() propOptions$?: Observable; - @Input() hint?: string; - @Input() approvalType?: string; - @Input() approvalTypeChange?: boolean | undefined = false; - - @Input() readOnlyDate?: boolean; - @Input() vehicleType?: string | null; - delimiter = { regex: '\\. (? { - return this.propOptions$ ?? of(this.options ?? []); - } - - get types(): typeof FormNodeEditTypes { - return FormNodeEditTypes; - } + @Input() type!: FormNodeEditTypes; + @Input() form!: FormGroup; + @Input() name!: string; + + @Input() isEditing = true; + + @Input() customId?: string; + @Input() idExtension?: number; + @Input() label?: string; + @Input() prefix?: string; + @Input() suffix?: string; + @Input() width?: FormNodeWidth; + @Input() options?: MultiOptions = []; + @Input() propOptions$?: Observable; + @Input() hint?: string; + @Input() approvalType?: string; + @Input() approvalTypeChange?: boolean | undefined = false; + + @Input() readOnlyDate?: boolean; + @Input() vehicleType?: string | null; + delimiter = { regex: '\\. (? { + return this.propOptions$ ?? of(this.options ?? []); + } + + get types(): typeof FormNodeEditTypes { + return FormNodeEditTypes; + } } diff --git a/src/app/forms/components/text-area/text-area.component.spec.ts b/src/app/forms/components/text-area/text-area.component.spec.ts index af1f61e753..6bca85037f 100644 --- a/src/app/forms/components/text-area/text-area.component.spec.ts +++ b/src/app/forms/components/text-area/text-area.component.spec.ts @@ -5,35 +5,35 @@ import { CustomFormControl, FormNodeTypes } from '../../services/dynamic-form.ty import { TextAreaComponent } from './text-area.component'; @Component({ - selector: 'app-host-component', - template: `
+ selector: 'app-host-component', + template: `
`, - styles: [], + styles: [], }) class HostComponent { - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, ''), - }); + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, ''), + }); } describe('TextAreaComponent', () => { - let component: HostComponent; - let fixture: ComponentFixture; + let component: HostComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TextAreaComponent], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TextAreaComponent], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(HostComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(HostComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/components/text-area/text-area.component.ts b/src/app/forms/components/text-area/text-area.component.ts index 9cec4b2e01..cd6f5ab680 100644 --- a/src/app/forms/components/text-area/text-area.component.ts +++ b/src/app/forms/components/text-area/text-area.component.ts @@ -4,18 +4,18 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { BaseControlComponent } from '../base-control/base-control.component'; @Component({ - selector: 'app-text-area', - templateUrl: './text-area.component.html', - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: TextAreaComponent, - multi: true, - }, - ], + selector: 'app-text-area', + templateUrl: './text-area.component.html', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: TextAreaComponent, + multi: true, + }, + ], }) export class TextAreaComponent extends BaseControlComponent { - get maxLength(): number | undefined { - return this.control?.meta.validators?.find((v) => v.name === ValidatorNames.MaxLength)?.args as number | undefined; - } + get maxLength(): number | undefined { + return this.control?.meta.validators?.find((v) => v.name === ValidatorNames.MaxLength)?.args as number | undefined; + } } diff --git a/src/app/forms/components/text-input/text-input.component.spec.ts b/src/app/forms/components/text-input/text-input.component.spec.ts index d11c9a3754..8294e04e9f 100644 --- a/src/app/forms/components/text-input/text-input.component.spec.ts +++ b/src/app/forms/components/text-input/text-input.component.spec.ts @@ -5,35 +5,35 @@ import { CustomFormControl, FormNodeTypes } from '../../services/dynamic-form.ty import { TextInputComponent } from './text-input.component'; @Component({ - selector: 'app-host-component', - template: `
+ selector: 'app-host-component', + template: `
`, - styles: [], + styles: [], }) class HostComponent { - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, ''), - }); + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, ''), + }); } describe('TextInputComponent', () => { - let component: HostComponent; - let fixture: ComponentFixture; + let component: HostComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TextInputComponent], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TextInputComponent], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(HostComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(HostComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/components/text-input/text-input.component.ts b/src/app/forms/components/text-input/text-input.component.ts index 9d59668f8f..5684cf3d23 100644 --- a/src/app/forms/components/text-input/text-input.component.ts +++ b/src/app/forms/components/text-input/text-input.component.ts @@ -1,29 +1,24 @@ -import { - Component, - EventEmitter, - Input, - Output, -} from '@angular/core'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { BaseControlComponent } from '../base-control/base-control.component'; @Component({ - selector: 'app-text-input', - templateUrl: './text-input.component.html', - styleUrls: ['./text-input.component.scss'], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: TextInputComponent, - multi: true, - }, - ], + selector: 'app-text-input', + templateUrl: './text-input.component.html', + styleUrls: ['./text-input.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: TextInputComponent, + multi: true, + }, + ], }) export class TextInputComponent extends BaseControlComponent { - @Input() numeric = false; - @Output() blur = new EventEmitter(); + @Input() numeric = false; + @Output() blur = new EventEmitter(); - get style(): string { - return `govuk-input ${this.width ? `govuk-input--width-${this.width}` : ''}`; - } + get style(): string { + return `govuk-input ${this.width ? `govuk-input--width-${this.width}` : ''}`; + } } diff --git a/src/app/forms/components/view-combination/view-combination.component.spec.ts b/src/app/forms/components/view-combination/view-combination.component.spec.ts index ec6f078521..9c0238efad 100644 --- a/src/app/forms/components/view-combination/view-combination.component.spec.ts +++ b/src/app/forms/components/view-combination/view-combination.component.spec.ts @@ -6,55 +6,55 @@ import { CustomFormControl, FormNode, FormNodeTypes } from '../../services/dynam import { ViewCombinationComponent } from './view-combination.component'; describe('ViewCombinationComponent', () => { - let component: ViewCombinationComponent; - let fixture: ComponentFixture; - - const formNode: FormNode = { - name: 'combination', - label: 'label', - type: FormNodeTypes.COMBINATION, - options: { - leftComponentName: 'aName', - rightComponentName: 'aName2', - separator: ' ', - }, - children: [], - }; - - const formGroup = new FormGroup({ - aName: new CustomFormControl({ name: 'aName', type: FormNodeTypes.CONTROL, children: [] }, ''), - aName2: new CustomFormControl({ name: 'aName2', type: FormNodeTypes.CONTROL, children: [] }, ''), - }); - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ViewCombinationComponent], - imports: [SharedModule], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ViewCombinationComponent); - component = fixture.componentInstance; - component.formNode = formNode; - component.formGroup = formGroup; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should find the left and right components to make up the combination', () => { - expect(component.leftComponent?.meta.name).toBe('aName'); - expect(component.rightComponent?.meta.name).toBe('aName2'); - }); - - it('should render correct values', () => { - const ddText: HTMLSpanElement = fixture.debugElement.query(By.css('span')).nativeElement; - expect(ddText.innerHTML).toBe('- -'); - formGroup.patchValue({ aName: 'Hello', aName2: 'World' }); - fixture.detectChanges(); - expect(ddText.innerHTML).toBe('Hello World'); - }); + let component: ViewCombinationComponent; + let fixture: ComponentFixture; + + const formNode: FormNode = { + name: 'combination', + label: 'label', + type: FormNodeTypes.COMBINATION, + options: { + leftComponentName: 'aName', + rightComponentName: 'aName2', + separator: ' ', + }, + children: [], + }; + + const formGroup = new FormGroup({ + aName: new CustomFormControl({ name: 'aName', type: FormNodeTypes.CONTROL, children: [] }, ''), + aName2: new CustomFormControl({ name: 'aName2', type: FormNodeTypes.CONTROL, children: [] }, ''), + }); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ViewCombinationComponent], + imports: [SharedModule], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ViewCombinationComponent); + component = fixture.componentInstance; + component.formNode = formNode; + component.formGroup = formGroup; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should find the left and right components to make up the combination', () => { + expect(component.leftComponent?.meta.name).toBe('aName'); + expect(component.rightComponent?.meta.name).toBe('aName2'); + }); + + it('should render correct values', () => { + const ddText: HTMLSpanElement = fixture.debugElement.query(By.css('span')).nativeElement; + expect(ddText.innerHTML).toBe('- -'); + formGroup.patchValue({ aName: 'Hello', aName2: 'World' }); + fixture.detectChanges(); + expect(ddText.innerHTML).toBe('Hello World'); + }); }); diff --git a/src/app/forms/components/view-combination/view-combination.component.ts b/src/app/forms/components/view-combination/view-combination.component.ts index 51ec500382..b6cedb56e3 100644 --- a/src/app/forms/components/view-combination/view-combination.component.ts +++ b/src/app/forms/components/view-combination/view-combination.component.ts @@ -3,39 +3,39 @@ import { FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; import { CustomFormControl, FormNode, FormNodeCombinationOptions } from '../../services/dynamic-form.types'; @Component({ - selector: '[app-view-combination]', - templateUrl: './view-combination.component.html', - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: ViewCombinationComponent, - multi: true, - }, - ], + selector: '[app-view-combination]', + templateUrl: './view-combination.component.html', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: ViewCombinationComponent, + multi: true, + }, + ], }) export class ViewCombinationComponent implements OnInit { - @Input() formNode: FormNode; - @Input() formGroup: FormGroup; + @Input() formNode: FormNode; + @Input() formGroup: FormGroup; - leftComponent?: CustomFormControl; - rightComponent?: CustomFormControl; - separator = ' '; - label?: string; + leftComponent?: CustomFormControl; + rightComponent?: CustomFormControl; + separator = ' '; + label?: string; - constructor() { - this.formNode = {}; - this.formGroup = {}; - } + constructor() { + this.formNode = {}; + this.formGroup = {}; + } - ngOnInit(): void { - const options = this.formNode.options; - this.leftComponent = this.findComponentByName(options.leftComponentName, this.formGroup); - this.rightComponent = this.findComponentByName(options.rightComponentName, this.formGroup); - this.separator = options.separator; - this.label = this.formNode.label; - } + ngOnInit(): void { + const options = this.formNode.options; + this.leftComponent = this.findComponentByName(options.leftComponentName, this.formGroup); + this.rightComponent = this.findComponentByName(options.rightComponentName, this.formGroup); + this.separator = options.separator; + this.label = this.formNode.label; + } - private findComponentByName(nodeName: string, formGroup: FormGroup): CustomFormControl { - return formGroup.get(nodeName) as CustomFormControl; - } + private findComponentByName(nodeName: string, formGroup: FormGroup): CustomFormControl { + return formGroup.get(nodeName) as CustomFormControl; + } } diff --git a/src/app/forms/components/view-list-item/view-list-item.component.spec.ts b/src/app/forms/components/view-list-item/view-list-item.component.spec.ts index e631c2eefb..f60934808b 100644 --- a/src/app/forms/components/view-list-item/view-list-item.component.spec.ts +++ b/src/app/forms/components/view-list-item/view-list-item.component.spec.ts @@ -5,35 +5,35 @@ import { CustomFormControl, FormNodeTypes } from '../../services/dynamic-form.ty import { ViewListItemComponent } from './view-list-item.component'; @Component({ - selector: 'app-host-component', - template: `
+ selector: 'app-host-component', + template: `
`, - styles: [], + styles: [], }) class HostComponent { - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, ''), - }); + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, ''), + }); } describe('ListItemOutputComponent', () => { - let component: HostComponent; - let fixture: ComponentFixture; + let component: HostComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ViewListItemComponent], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ViewListItemComponent], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(HostComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(HostComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/components/view-list-item/view-list-item.component.ts b/src/app/forms/components/view-list-item/view-list-item.component.ts index 59306d15bf..bac47102d5 100644 --- a/src/app/forms/components/view-list-item/view-list-item.component.ts +++ b/src/app/forms/components/view-list-item/view-list-item.component.ts @@ -4,39 +4,37 @@ import { FormNodeViewTypes } from '../../services/dynamic-form.types'; import { BaseControlComponent } from '../base-control/base-control.component'; @Component({ - selector: '[app-view-list-item]', - templateUrl: './view-list-item.component.html', - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: ViewListItemComponent, - multi: true, - }, - ], - styleUrls: ['./view-list-item.component.scss'], + selector: '[app-view-list-item]', + templateUrl: './view-list-item.component.html', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: ViewListItemComponent, + multi: true, + }, + ], + styleUrls: ['./view-list-item.component.scss'], }) export class ViewListItemComponent extends BaseControlComponent { - customFormControlInjector?: Injector; + customFormControlInjector?: Injector; - get formNodeViewTypes(): typeof FormNodeViewTypes { - return FormNodeViewTypes; - } + get formNodeViewTypes(): typeof FormNodeViewTypes { + return FormNodeViewTypes; + } - get displayAsRow() { - return !(this.viewType === this.formNodeViewTypes.FULLWIDTH || this.viewType === this.formNodeViewTypes.CUSTOM); - } + get displayAsRow() { + return !(this.viewType === this.formNodeViewTypes.FULLWIDTH || this.viewType === this.formNodeViewTypes.CUSTOM); + } - override ngAfterContentInit(): void { - super.ngAfterContentInit(); - this.createCustomFormControlInjector(); - } + override ngAfterContentInit(): void { + super.ngAfterContentInit(); + this.createCustomFormControlInjector(); + } - createCustomFormControlInjector() { - this.customFormControlInjector = Injector.create({ - providers: [ - { provide: NgControl, useValue: { control: this.control } }, - ], - parent: this.injector, - }); - } + createCustomFormControlInjector() { + this.customFormControlInjector = Injector.create({ + providers: [{ provide: NgControl, useValue: { control: this.control } }], + parent: this.injector, + }); + } } diff --git a/src/app/forms/custom-sections/abandon-dialog/abandon-dialog.component.spec.ts b/src/app/forms/custom-sections/abandon-dialog/abandon-dialog.component.spec.ts index 81d7331e15..266da1ad8d 100644 --- a/src/app/forms/custom-sections/abandon-dialog/abandon-dialog.component.spec.ts +++ b/src/app/forms/custom-sections/abandon-dialog/abandon-dialog.component.spec.ts @@ -14,45 +14,45 @@ import { initialAppState } from '@store/index'; import { AbandonDialogComponent } from './abandon-dialog.component'; describe('AbandonDialogComponent', () => { - let component: AbandonDialogComponent; - let fixture: ComponentFixture; + let component: AbandonDialogComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AbandonDialogComponent], - imports: [DynamicFormsModule, SharedModule, RouterTestingModule, HttpClientTestingModule], - providers: [provideMockStore({ initialState: initialAppState }), DynamicFormService], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AbandonDialogComponent], + imports: [DynamicFormsModule, SharedModule, RouterTestingModule, HttpClientTestingModule], + providers: [provideMockStore({ initialState: initialAppState }), DynamicFormService], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(AbandonDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(AbandonDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - describe('template getter', () => { - it('should get the template with TIR reasons for abandoning if the testType is a TIR', () => { - const mockTestResult = { testTypes: [{ testTypeId: TEST_TYPES_GROUP5_13[0] }] } as TestResultModel; - component.testResult = mockTestResult; - const ReasonsForAbandoning = component.getTemplate().children?.[0].children?.[0].children?.[0].referenceData; - expect(ReasonsForAbandoning).toEqual(ReferenceDataResourceType.TirReasonsForAbandoning); - }); - it('should get the specialist reasons for abandoning', () => { - const mockTestResult = { testTypes: [{ testTypeId: SPECIALIST_TEST_TYPE_IDS[0] }] } as TestResultModel; - component.testResult = mockTestResult; - const ReasonsForAbandoning = component.getTemplate().children?.[0].children?.[0].children?.[0].referenceData; - expect(ReasonsForAbandoning).toEqual(ReferenceDataResourceType.SpecialistReasonsForAbandoning); - }); - it('should get the reasons for regular reasons for abandoning by default', () => { - const mockTestResult = { testTypes: [{ testTypeId: 'foobar' }] } as TestResultModel; - component.testResult = mockTestResult; - const ReasonsForAbandoning = component.getTemplate().children?.[0].children?.[0].children?.[0].referenceData; - expect(ReasonsForAbandoning).toEqual(SpecialRefData.ReasonsForAbandoning); - }); - }); + describe('template getter', () => { + it('should get the template with TIR reasons for abandoning if the testType is a TIR', () => { + const mockTestResult = { testTypes: [{ testTypeId: TEST_TYPES_GROUP5_13[0] }] } as TestResultModel; + component.testResult = mockTestResult; + const ReasonsForAbandoning = component.getTemplate().children?.[0].children?.[0].children?.[0].referenceData; + expect(ReasonsForAbandoning).toEqual(ReferenceDataResourceType.TirReasonsForAbandoning); + }); + it('should get the specialist reasons for abandoning', () => { + const mockTestResult = { testTypes: [{ testTypeId: SPECIALIST_TEST_TYPE_IDS[0] }] } as TestResultModel; + component.testResult = mockTestResult; + const ReasonsForAbandoning = component.getTemplate().children?.[0].children?.[0].children?.[0].referenceData; + expect(ReasonsForAbandoning).toEqual(ReferenceDataResourceType.SpecialistReasonsForAbandoning); + }); + it('should get the reasons for regular reasons for abandoning by default', () => { + const mockTestResult = { testTypes: [{ testTypeId: 'foobar' }] } as TestResultModel; + component.testResult = mockTestResult; + const ReasonsForAbandoning = component.getTemplate().children?.[0].children?.[0].children?.[0].referenceData; + expect(ReasonsForAbandoning).toEqual(SpecialRefData.ReasonsForAbandoning); + }); + }); }); diff --git a/src/app/forms/custom-sections/abandon-dialog/abandon-dialog.component.ts b/src/app/forms/custom-sections/abandon-dialog/abandon-dialog.component.ts index eb457dd7fe..a7d10cb5b4 100644 --- a/src/app/forms/custom-sections/abandon-dialog/abandon-dialog.component.ts +++ b/src/app/forms/custom-sections/abandon-dialog/abandon-dialog.component.ts @@ -1,6 +1,4 @@ -import { - Component, EventEmitter, Input, OnInit, Output, ViewChild, -} from '@angular/core'; +import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; import { TEST_TYPES_GROUP5_13 } from '@forms/models/testTypeId.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; import { FormNode, FormNodeEditTypes, FormNodeTypes } from '@forms/services/dynamic-form.types'; @@ -13,73 +11,74 @@ import merge from 'lodash.merge'; import { DynamicFormGroupComponent } from '../../components/dynamic-form-group/dynamic-form-group.component'; const ABANDON_FORM = (ReasonsForAbandoning: ReferenceDataResourceType | SpecialRefData): FormNode => ({ - name: 'abandonSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - label: 'Why was this test abandoned?', - hint: 'Select all that apply.', - editType: FormNodeEditTypes.CHECKBOXGROUP, - delimited: { regex: '\\. (?(); - template?: FormNode; - ngOnInit() { - this.template = this.getTemplate(); - } + @ViewChild(DynamicFormGroupComponent) dynamicFormGroup?: DynamicFormGroupComponent; + @Input() testResult?: TestResultModel; + @Output() newTestResult = new EventEmitter(); + template?: FormNode; + ngOnInit() { + this.template = this.getTemplate(); + } - getTemplate(): FormNode { - const testTypeId = this.testResult?.testTypes[0].testTypeId ?? ''; + getTemplate(): FormNode { + const testTypeId = this.testResult?.testTypes[0].testTypeId ?? ''; - if (TEST_TYPES_GROUP5_13.includes(testTypeId)) { - return ABANDON_FORM(ReferenceDataResourceType.TirReasonsForAbandoning); - } if (TestRecordsService.getTestTypeGroup(testTypeId)?.includes('Specialist')) { - return ABANDON_FORM(ReferenceDataResourceType.SpecialistReasonsForAbandoning); - } - return ABANDON_FORM(SpecialRefData.ReasonsForAbandoning); - } + if (TEST_TYPES_GROUP5_13.includes(testTypeId)) { + return ABANDON_FORM(ReferenceDataResourceType.TirReasonsForAbandoning); + } + if (TestRecordsService.getTestTypeGroup(testTypeId)?.includes('Specialist')) { + return ABANDON_FORM(ReferenceDataResourceType.SpecialistReasonsForAbandoning); + } + return ABANDON_FORM(SpecialRefData.ReasonsForAbandoning); + } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - handleFormChange(event: any) { - const latestTest = merge(this.testResult, event); - if (latestTest && Object.keys(latestTest).length > 0) { - this.newTestResult.emit(latestTest as TestResultModel); - } - } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + handleFormChange(event: any) { + const latestTest = merge(this.testResult, event); + if (latestTest && Object.keys(latestTest).length > 0) { + this.newTestResult.emit(latestTest as TestResultModel); + } + } } diff --git a/src/app/forms/custom-sections/adr-certificate-history/adr-certificate-history.component.spec.ts b/src/app/forms/custom-sections/adr-certificate-history/adr-certificate-history.component.spec.ts index 88f82c7134..58ad199b41 100644 --- a/src/app/forms/custom-sections/adr-certificate-history/adr-certificate-history.component.spec.ts +++ b/src/app/forms/custom-sections/adr-certificate-history/adr-certificate-history.component.spec.ts @@ -1,101 +1,99 @@ +import { ViewportScroller } from '@angular/common'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { createMockHgv } from '@mocks/hgv-record.mock'; -import { provideMockStore } from '@ngrx/store/testing'; -import { initialAppState } from '@store/index'; -import { ADRCertificateDetails } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/hgv/complete'; +import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; +import { ADRCertificateDetails } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/hgv/complete'; +import { createMockHgv } from '@mocks/hgv-record.mock'; +import { provideMockStore } from '@ngrx/store/testing'; import { AdrService } from '@services/adr/adr.service'; -import { Router } from '@angular/router'; -import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { ViewportScroller } from '@angular/common'; +import { initialAppState } from '@store/index'; import { AdrCertificateHistoryComponent } from './adr-certificate-history.component'; describe('TechRecordAdrCertificateHistoryComponent', () => { - let component: AdrCertificateHistoryComponent; - let fixture: ComponentFixture; - let globalErrorService: GlobalErrorService; - let adrService: AdrService; - let router: Router; - let viewportScroller: ViewportScroller; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AdrCertificateHistoryComponent], - providers: [ - provideMockStore({ initialState: initialAppState }), - ], - imports: [RouterTestingModule, HttpClientTestingModule], - schemas: [NO_ERRORS_SCHEMA], - }).compileComponents(); - }); - beforeEach(() => { - fixture = TestBed.createComponent(AdrCertificateHistoryComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - component.currentTechRecord = createMockHgv(0); - globalErrorService = TestBed.inject(GlobalErrorService); - adrService = TestBed.inject(AdrService); - router = TestBed.inject(Router); - viewportScroller = TestBed.inject(ViewportScroller); - }); - it('should create', () => { - expect(component).toBeTruthy(); - }); - describe('showTable', () => { - it('should return false if isEditing returns true', () => { - component.isEditing = true; - expect(component.showTable()).toBe(false); - }); - it('should return false if numberOfADRCertificates returns 0', () => { - component.currentTechRecord = createMockHgv(0); - component.isEditing = false; - component.currentTechRecord.techRecord_adrPassCertificateDetails = []; - expect(component.showTable()).toBe(false); - }); - it('should return true if numberOfADRCertificates returns > 0', () => { - component.currentTechRecord = createMockHgv(0); - component.isEditing = false; - component.currentTechRecord.techRecord_adrPassCertificateDetails = [ - { - createdByName: '', - certificateType: 'PASS', - generatedTimestamp: '', - certificateId: '', - } as unknown as ADRCertificateDetails, - ]; - expect(component.showTable()).toBe(true); - }); - }); + let component: AdrCertificateHistoryComponent; + let fixture: ComponentFixture; + let globalErrorService: GlobalErrorService; + let adrService: AdrService; + let router: Router; + let viewportScroller: ViewportScroller; + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AdrCertificateHistoryComponent], + providers: [provideMockStore({ initialState: initialAppState })], + imports: [RouterTestingModule, HttpClientTestingModule], + schemas: [NO_ERRORS_SCHEMA], + }).compileComponents(); + }); + beforeEach(() => { + fixture = TestBed.createComponent(AdrCertificateHistoryComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + component.currentTechRecord = createMockHgv(0); + globalErrorService = TestBed.inject(GlobalErrorService); + adrService = TestBed.inject(AdrService); + router = TestBed.inject(Router); + viewportScroller = TestBed.inject(ViewportScroller); + }); + it('should create', () => { + expect(component).toBeTruthy(); + }); + describe('showTable', () => { + it('should return false if isEditing returns true', () => { + component.isEditing = true; + expect(component.showTable()).toBe(false); + }); + it('should return false if numberOfADRCertificates returns 0', () => { + component.currentTechRecord = createMockHgv(0); + component.isEditing = false; + component.currentTechRecord.techRecord_adrPassCertificateDetails = []; + expect(component.showTable()).toBe(false); + }); + it('should return true if numberOfADRCertificates returns > 0', () => { + component.currentTechRecord = createMockHgv(0); + component.isEditing = false; + component.currentTechRecord.techRecord_adrPassCertificateDetails = [ + { + createdByName: '', + certificateType: 'PASS', + generatedTimestamp: '', + certificateId: '', + } as unknown as ADRCertificateDetails, + ]; + expect(component.showTable()).toBe(true); + }); + }); - describe('validateADRDetailsAndNavigate', () => { - it('should navigate when carriesDangerousGoodsSpy returns true', () => { - fixture.ngZone?.run(() => { - component.currentTechRecord = createMockHgv(0); - component.currentTechRecord.techRecord_adrDetails_dangerousGoods = true; - const clearErrorsSpy = jest.spyOn(globalErrorService, 'clearErrors'); - const carriesDangerousGoodsSpy = jest.spyOn(adrService, 'carriesDangerousGoods'); - const routerSpy = jest.spyOn(router, 'navigate'); - component.validateADRDetailsAndNavigate(); - expect(clearErrorsSpy).toHaveBeenCalled(); - expect(carriesDangerousGoodsSpy).toHaveBeenCalled(); - expect(routerSpy).toHaveBeenCalled(); - }); - }); - it('should not navigate when carriesDangerousGoods returns false', () => { - component.currentTechRecord = createMockHgv(0); - component.currentTechRecord.techRecord_adrDetails_dangerousGoods = false; - const clearErrorsSpy = jest.spyOn(globalErrorService, 'clearErrors'); - const addErrorSpy = jest.spyOn(globalErrorService, 'addError'); - const carriesDangerousGoodsSpy = jest.spyOn(adrService, 'carriesDangerousGoods'); - const routerSpy = jest.spyOn(router, 'navigate'); - const viewportScrollerSpy = jest.spyOn(viewportScroller, 'scrollToPosition').mockImplementation(() => {}); - component.validateADRDetailsAndNavigate(); - expect(clearErrorsSpy).toHaveBeenCalled(); - expect(carriesDangerousGoodsSpy).toHaveBeenCalled(); - expect(viewportScrollerSpy).toHaveBeenCalled(); - expect(addErrorSpy).toHaveBeenCalled(); - expect(routerSpy).not.toHaveBeenCalled(); - }); - }); + describe('validateADRDetailsAndNavigate', () => { + it('should navigate when carriesDangerousGoodsSpy returns true', () => { + fixture.ngZone?.run(() => { + component.currentTechRecord = createMockHgv(0); + component.currentTechRecord.techRecord_adrDetails_dangerousGoods = true; + const clearErrorsSpy = jest.spyOn(globalErrorService, 'clearErrors'); + const carriesDangerousGoodsSpy = jest.spyOn(adrService, 'carriesDangerousGoods'); + const routerSpy = jest.spyOn(router, 'navigate'); + component.validateADRDetailsAndNavigate(); + expect(clearErrorsSpy).toHaveBeenCalled(); + expect(carriesDangerousGoodsSpy).toHaveBeenCalled(); + expect(routerSpy).toHaveBeenCalled(); + }); + }); + it('should not navigate when carriesDangerousGoods returns false', () => { + component.currentTechRecord = createMockHgv(0); + component.currentTechRecord.techRecord_adrDetails_dangerousGoods = false; + const clearErrorsSpy = jest.spyOn(globalErrorService, 'clearErrors'); + const addErrorSpy = jest.spyOn(globalErrorService, 'addError'); + const carriesDangerousGoodsSpy = jest.spyOn(adrService, 'carriesDangerousGoods'); + const routerSpy = jest.spyOn(router, 'navigate'); + const viewportScrollerSpy = jest.spyOn(viewportScroller, 'scrollToPosition').mockImplementation(() => {}); + component.validateADRDetailsAndNavigate(); + expect(clearErrorsSpy).toHaveBeenCalled(); + expect(carriesDangerousGoodsSpy).toHaveBeenCalled(); + expect(viewportScrollerSpy).toHaveBeenCalled(); + expect(addErrorSpy).toHaveBeenCalled(); + expect(routerSpy).not.toHaveBeenCalled(); + }); + }); }); diff --git a/src/app/forms/custom-sections/adr-certificate-history/adr-certificate-history.component.ts b/src/app/forms/custom-sections/adr-certificate-history/adr-certificate-history.component.ts index 1970d0eb96..c422c8b1d3 100644 --- a/src/app/forms/custom-sections/adr-certificate-history/adr-certificate-history.component.ts +++ b/src/app/forms/custom-sections/adr-certificate-history/adr-certificate-history.component.ts @@ -1,116 +1,114 @@ -import { - Component, inject, Input, -} from '@angular/core'; -import { - TechRecordType, -} from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; -import { ADRCertificateDetails } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/hgv/complete'; -import { - map, Observable, Subject, takeUntil, -} from 'rxjs'; -import { RouterService } from '@services/router/router.service'; -import { FeatureToggleService } from '@services/feature-toggle-service/feature-toggle-service'; -import { GlobalErrorService } from '@core/components/global-error/global-error.service'; -import { AdrService } from '@services/adr/adr.service'; import { ViewportScroller } from '@angular/common'; +import { Component, Input, inject } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { Roles } from '@models/roles.enum'; +import { GlobalErrorService } from '@core/components/global-error/global-error.service'; +import { ADRCertificateDetails } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/hgv/complete'; +import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; import { CustomFormControlComponent } from '@forms/custom-sections/custom-form-control/custom-form-control.component'; +import { Roles } from '@models/roles.enum'; +import { AdrService } from '@services/adr/adr.service'; +import { FeatureToggleService } from '@services/feature-toggle-service/feature-toggle-service'; +import { RouterService } from '@services/router/router.service'; import { cloneDeep } from 'lodash'; +import { Observable, Subject, map, takeUntil } from 'rxjs'; @Component({ - selector: 'app-adr-certificate-history', - templateUrl: './adr-certificate-history.html', - styleUrls: ['./adr-certificate-history.scss'], + selector: 'app-adr-certificate-history', + templateUrl: './adr-certificate-history.html', + styleUrls: ['./adr-certificate-history.scss'], }) export class AdrCertificateHistoryComponent extends CustomFormControlComponent { - @Input() currentTechRecord?: TechRecordType<'hgv' | 'lgv' | 'trl'>; - isEditing = false; - private destroy$ = new Subject(); - routerService = inject(RouterService); - featureToggleService = inject(FeatureToggleService); - globalErrorService = inject(GlobalErrorService); - adrService = inject(AdrService); - viewportScroller = inject(ViewportScroller); - router = inject(Router); - route = inject(ActivatedRoute); - pageStart?: number; - pageEnd?: number; + @Input() currentTechRecord?: TechRecordType<'hgv' | 'lgv' | 'trl'>; + isEditing = false; + private destroy$ = new Subject(); + routerService = inject(RouterService); + featureToggleService = inject(FeatureToggleService); + globalErrorService = inject(GlobalErrorService); + adrService = inject(AdrService); + viewportScroller = inject(ViewportScroller); + router = inject(Router); + route = inject(ActivatedRoute); + pageStart?: number; + pageEnd?: number; - ngOnInit() { - this.isEditing$.pipe(takeUntil(this.destroy$)).subscribe((editing) => { - this.isEditing = editing; - }); - } + ngOnInit() { + this.isEditing$.pipe(takeUntil(this.destroy$)).subscribe((editing) => { + this.isEditing = editing; + }); + } - get roles(): typeof Roles { - return Roles; - } + get roles(): typeof Roles { + return Roles; + } - get isEditing$(): Observable { - return this.routerService.getRouteDataProperty$('isEditing').pipe(map((isEditing) => !!isEditing)); - } + get isEditing$(): Observable { + return this.routerService.getRouteDataProperty$('isEditing').pipe(map((isEditing) => !!isEditing)); + } - get sortedCertificates(): ADRCertificateDetails[] | undefined { - return cloneDeep(this.currentTechRecord?.techRecord_adrPassCertificateDetails)?.sort((a, b) => - a.generatedTimestamp && b.generatedTimestamp ? new Date(b.generatedTimestamp).getTime() - new Date(a.generatedTimestamp).getTime() : 0); - } + get sortedCertificates(): ADRCertificateDetails[] | undefined { + return cloneDeep(this.currentTechRecord?.techRecord_adrPassCertificateDetails)?.sort((a, b) => + a.generatedTimestamp && b.generatedTimestamp + ? new Date(b.generatedTimestamp).getTime() - new Date(a.generatedTimestamp).getTime() + : 0 + ); + } - get adrCertificateHistory(): ADRCertificateDetails[] { - return this.sortedCertificates?.slice(this.pageStart, this.pageEnd) || []; - } + get adrCertificateHistory(): ADRCertificateDetails[] { + return this.sortedCertificates?.slice(this.pageStart, this.pageEnd) || []; + } - trackByFn(i: number, tr: ADRCertificateDetails) { - return tr.generatedTimestamp; - } + trackByFn(i: number, tr: ADRCertificateDetails) { + return tr.generatedTimestamp; + } - get numberOfADRCertificates(): number { - return this.sortedCertificates?.length || 0; - } + get numberOfADRCertificates(): number { + return this.sortedCertificates?.length || 0; + } - getFileName(certificate: ADRCertificateDetails) { - return certificate.certificateId; - } - documentParams(certificate: ADRCertificateDetails): Map { - return new Map([['fileName', this.getFileName(certificate)]]); - } + getFileName(certificate: ADRCertificateDetails) { + return certificate.certificateId; + } + documentParams(certificate: ADRCertificateDetails): Map { + return new Map([['fileName', this.getFileName(certificate)]]); + } - get isArchived(): boolean { - return this.currentTechRecord?.techRecord_statusCode === 'archived'; - } + get isArchived(): boolean { + return this.currentTechRecord?.techRecord_statusCode === 'archived'; + } - showTable(): boolean { - return !this.isEditing && this.numberOfADRCertificates > 0; - } + showTable(): boolean { + return !this.isEditing && this.numberOfADRCertificates > 0; + } - get reasonForNoRecords(): string { - if (this.isEditing) { - return 'This section is not available when amending or creating a technical record.'; - } - if (this.numberOfADRCertificates === 0) { - return 'No ADR certificates found.'; - } - return ''; - } + get reasonForNoRecords(): string { + if (this.isEditing) { + return 'This section is not available when amending or creating a technical record.'; + } + if (this.numberOfADRCertificates === 0) { + return 'No ADR certificates found.'; + } + return ''; + } - validateADRDetailsAndNavigate(): void { - this.globalErrorService.clearErrors(); - if (this.currentTechRecord) { - if (!this.adrService.carriesDangerousGoods(this.currentTechRecord)) { - this.viewportScroller.scrollToPosition([0, 0]); - this.globalErrorService.addError( - { error: 'This vehicle is not able to carry dangerous goods, add ADR details to the technical record to generate a certificate.' }, - ); - return; - } - } + validateADRDetailsAndNavigate(): void { + this.globalErrorService.clearErrors(); + if (this.currentTechRecord) { + if (!this.adrService.carriesDangerousGoods(this.currentTechRecord)) { + this.viewportScroller.scrollToPosition([0, 0]); + this.globalErrorService.addError({ + error: + 'This vehicle is not able to carry dangerous goods, add ADR details to the technical record to generate a certificate.', + }); + return; + } + } - void this.router.navigate(['adr-certificate'], { relativeTo: this.route }); - } + void this.router.navigate(['adr-certificate'], { relativeTo: this.route }); + } - handlePaginationChange({ start, end }: { start: number; end: number }) { - this.pageStart = start; - this.pageEnd = end; - this.cdr.detectChanges(); - } + handlePaginationChange({ start, end }: { start: number; end: number }) { + this.pageStart = start; + this.pageEnd = end; + this.cdr.detectChanges(); + } } diff --git a/src/app/forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit.spec.ts b/src/app/forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit.spec.ts index 76ff27c32c..ae38f2bd99 100644 --- a/src/app/forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit.spec.ts +++ b/src/app/forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit.spec.ts @@ -1,110 +1,107 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { ActivatedRoute, Router } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; -import { - AdrExaminerNotesHistoryEditComponent, -} from '@forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit'; +import { AdrExaminerNotesHistoryEditComponent } from '@forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit'; import { DynamicFormsModule } from '@forms/dynamic-forms.module'; import { mockVehicleTechnicalRecord } from '@mocks/mock-vehicle-technical-record.mock'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; -import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { provideMockStore } from '@ngrx/store/testing'; +import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { initialAppState } from '@store/index'; -import { ActivatedRoute, Router } from '@angular/router'; import { of } from 'rxjs'; -import { RouterTestingModule } from '@angular/router/testing'; const mockTechRecordService = { - techRecord$: jest.fn(), + techRecord$: jest.fn(), }; describe('AdrExaminerNotesHistoryEditComponent', () => { - let component: AdrExaminerNotesHistoryEditComponent; - let fixture: ComponentFixture; - let router: Router; - - const MOCK_HGV = mockVehicleTechnicalRecord(VehicleTypes.HGV) as TechRecordType<'hgv'>; + let component: AdrExaminerNotesHistoryEditComponent; + let fixture: ComponentFixture; + let router: Router; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AdrExaminerNotesHistoryEditComponent], - imports: [DynamicFormsModule, FormsModule, ReactiveFormsModule, RouterTestingModule], - providers: [ - { provide: TechnicalRecordService, useValue: mockTechRecordService }, - provideMockStore({ initialState: initialAppState }), - { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, - ], - }).compileComponents(); - fixture = TestBed.createComponent(AdrExaminerNotesHistoryEditComponent); - component = fixture.componentInstance; - router = TestBed.inject(Router); - }); - describe('ngOnDestroy', () => { - it('should call destroy$.next and destroy$.complete', () => { - const nextSpy = jest.spyOn(component.destroy$, 'next'); - const completeSpy = jest.spyOn(component.destroy$, 'complete'); - component.ngOnDestroy(); - expect(nextSpy).toHaveBeenCalled(); - expect(completeSpy).toHaveBeenCalled(); - }); - }); + const MOCK_HGV = mockVehicleTechnicalRecord(VehicleTypes.HGV) as TechRecordType<'hgv'>; - describe('getAdditionalExaminerNotes', () => { - it('should return an empty array if additionalExaminerNotes is empty', () => { - component.currentTechRecord = mockVehicleTechnicalRecord(VehicleTypes.HGV) as TechRecordType<'hgv'>; - component.currentTechRecord.techRecord_adrDetails_additionalExaminerNotes = []; - const notes = component.getAdditionalExaminerNotes(); - expect(notes).toEqual([]); - }); - it('should return a populated array if additionalExaminerNotes is not empty', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AdrExaminerNotesHistoryEditComponent], + imports: [DynamicFormsModule, FormsModule, ReactiveFormsModule, RouterTestingModule], + providers: [ + { provide: TechnicalRecordService, useValue: mockTechRecordService }, + provideMockStore({ initialState: initialAppState }), + { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, + ], + }).compileComponents(); + fixture = TestBed.createComponent(AdrExaminerNotesHistoryEditComponent); + component = fixture.componentInstance; + router = TestBed.inject(Router); + }); + describe('ngOnDestroy', () => { + it('should call destroy$.next and destroy$.complete', () => { + const nextSpy = jest.spyOn(component.destroy$, 'next'); + const completeSpy = jest.spyOn(component.destroy$, 'complete'); + component.ngOnDestroy(); + expect(nextSpy).toHaveBeenCalled(); + expect(completeSpy).toHaveBeenCalled(); + }); + }); - component.currentTechRecord = mockVehicleTechnicalRecord(VehicleTypes.HGV) as TechRecordType<'hgv'>; - const testNote = { - note: 'testNote', - createdAtDate: new Date().toISOString(), - lastUpdatedBy: 'Someone Somewhere', - }; - component.currentTechRecord.techRecord_adrDetails_additionalExaminerNotes = [testNote]; - const notes = component.getAdditionalExaminerNotes(); - expect(notes).toEqual([testNote]); - }); - }); - describe('getEditAdditionalExaminerNotePage', () => { - it('should navigate you to the EditAdditionalExaminerNotePage', () => { - const routerSpy = jest.spyOn(router, 'navigate'); - component.getEditAdditionalExaminerNotePage(1); - expect(routerSpy).toHaveBeenCalled(); - }); - }); + describe('getAdditionalExaminerNotes', () => { + it('should return an empty array if additionalExaminerNotes is empty', () => { + component.currentTechRecord = mockVehicleTechnicalRecord(VehicleTypes.HGV) as TechRecordType<'hgv'>; + component.currentTechRecord.techRecord_adrDetails_additionalExaminerNotes = []; + const notes = component.getAdditionalExaminerNotes(); + expect(notes).toEqual([]); + }); + it('should return a populated array if additionalExaminerNotes is not empty', () => { + component.currentTechRecord = mockVehicleTechnicalRecord(VehicleTypes.HGV) as TechRecordType<'hgv'>; + const testNote = { + note: 'testNote', + createdAtDate: new Date().toISOString(), + lastUpdatedBy: 'Someone Somewhere', + }; + component.currentTechRecord.techRecord_adrDetails_additionalExaminerNotes = [testNote]; + const notes = component.getAdditionalExaminerNotes(); + expect(notes).toEqual([testNote]); + }); + }); + describe('getEditAdditionalExaminerNotePage', () => { + it('should navigate you to the EditAdditionalExaminerNotePage', () => { + const routerSpy = jest.spyOn(router, 'navigate'); + component.getEditAdditionalExaminerNotePage(1); + expect(routerSpy).toHaveBeenCalled(); + }); + }); - describe('handlePaginationChange', () => { - it('should set the start and end pages', () => { - component.handlePaginationChange({ start: 0, end: 3 }); + describe('handlePaginationChange', () => { + it('should set the start and end pages', () => { + component.handlePaginationChange({ start: 0, end: 3 }); - expect(component.pageStart).toBe(0); - expect(component.pageEnd).toBe(3); - }); - }); + expect(component.pageStart).toBe(0); + expect(component.pageEnd).toBe(3); + }); + }); - describe('currentAdrNotesPage', () => { - it('should return a sliced array of adr notes depending on the page the user is on', () => { - component.currentTechRecord = { ...MOCK_HGV }; - component.pageStart = 1; - component.pageEnd = 2; - component.currentTechRecord.techRecord_adrDetails_additionalExaminerNotes = [ - { createdAtDate: 'test1', lastUpdatedBy: 'test1', note: 'test note 1' }, - { createdAtDate: 'test2', lastUpdatedBy: 'test2', note: 'test note 2' }, - ]; - expect(component.currentAdrNotesPage).toEqual([ - { createdAtDate: 'test2', lastUpdatedBy: 'test2', note: 'test note 2' }, - ]); - }); + describe('currentAdrNotesPage', () => { + it('should return a sliced array of adr notes depending on the page the user is on', () => { + component.currentTechRecord = { ...MOCK_HGV }; + component.pageStart = 1; + component.pageEnd = 2; + component.currentTechRecord.techRecord_adrDetails_additionalExaminerNotes = [ + { createdAtDate: 'test1', lastUpdatedBy: 'test1', note: 'test note 1' }, + { createdAtDate: 'test2', lastUpdatedBy: 'test2', note: 'test note 2' }, + ]; + expect(component.currentAdrNotesPage).toEqual([ + { createdAtDate: 'test2', lastUpdatedBy: 'test2', note: 'test note 2' }, + ]); + }); - it('should return an empty array if the adr examiner notes is undefined', () => { - component.currentTechRecord = { ...MOCK_HGV }; - component.pageStart = 2; - component.pageEnd = 3; - component.currentTechRecord.techRecord_adrDetails_additionalExaminerNotes = undefined; - expect(component.currentAdrNotesPage).toEqual([]); - }); - }); + it('should return an empty array if the adr examiner notes is undefined', () => { + component.currentTechRecord = { ...MOCK_HGV }; + component.pageStart = 2; + component.pageEnd = 3; + component.currentTechRecord.techRecord_adrDetails_additionalExaminerNotes = undefined; + expect(component.currentAdrNotesPage).toEqual([]); + }); + }); }); diff --git a/src/app/forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit.ts b/src/app/forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit.ts index 088856dbfb..b65f753556 100644 --- a/src/app/forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit.ts +++ b/src/app/forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit.ts @@ -1,7 +1,5 @@ import { KeyValue, ViewportScroller } from '@angular/common'; -import { - AfterContentInit, Component, OnDestroy, OnInit, inject, -} from '@angular/core'; +import { AfterContentInit, Component, OnDestroy, OnInit, inject } from '@angular/core'; import { FormArray, NgControl } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { AdditionalExaminerNotes } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/hgv/complete'; @@ -16,70 +14,75 @@ import { TechnicalRecordServiceState } from '@store/technical-records/reducers/t import { ReplaySubject, takeUntil } from 'rxjs'; @Component({ - selector: 'app-adr-examiner-notes-history', - templateUrl: './adr-examiner-notes-history-edit.component.html', - styleUrls: ['adr-examiner-notes-history.component-edit.scss'], + selector: 'app-adr-examiner-notes-history', + templateUrl: './adr-examiner-notes-history-edit.component.html', + styleUrls: ['adr-examiner-notes-history.component-edit.scss'], }) -export class AdrExaminerNotesHistoryEditComponent extends BaseControlComponent implements OnInit, OnDestroy, AfterContentInit { - destroy$ = new ReplaySubject(1); - formArray = new FormArray([]); - currentTechRecord?: TechRecordType<'hgv' | 'lgv' | 'trl'> = undefined; - technicalRecordService = inject(TechnicalRecordService); - store = inject(Store); - viewportScroller = inject(ViewportScroller); - router = inject(Router); - route = inject(ActivatedRoute); - editingReason?: ReasonForEditing; - pageStart?: number; - pageEnd?: number; +export class AdrExaminerNotesHistoryEditComponent + extends BaseControlComponent + implements OnInit, OnDestroy, AfterContentInit +{ + destroy$ = new ReplaySubject(1); + formArray = new FormArray([]); + currentTechRecord?: TechRecordType<'hgv' | 'lgv' | 'trl'> = undefined; + technicalRecordService = inject(TechnicalRecordService); + store = inject(Store); + viewportScroller = inject(ViewportScroller); + router = inject(Router); + route = inject(ActivatedRoute); + editingReason?: ReasonForEditing; + pageStart?: number; + pageEnd?: number; - ngOnInit(): void { - this.formArray.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((changes) => { - this.control?.patchValue(changes, { emitModelToViewChange: true }); - }); - this.technicalRecordService.techRecord$.pipe(takeUntil(this.destroy$)).subscribe((currentTechRecord) => { - this.currentTechRecord = currentTechRecord as TechRecordType<'hgv' | 'lgv' | 'trl'>; - }); - this.editingReason = this.route.snapshot.data['reason']; - } + ngOnInit(): void { + this.formArray.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((changes) => { + this.control?.patchValue(changes, { emitModelToViewChange: true }); + }); + this.technicalRecordService.techRecord$.pipe(takeUntil(this.destroy$)).subscribe((currentTechRecord) => { + this.currentTechRecord = currentTechRecord as TechRecordType<'hgv' | 'lgv' | 'trl'>; + }); + this.editingReason = this.route.snapshot.data['reason']; + } - override ngAfterContentInit(): void { - const injectedControl = this.injector.get(NgControl, null); - if (injectedControl) { - const ngControl = injectedControl.control as unknown as KeyValue; - if (ngControl.value) { - this.name = ngControl.key; - this.control = ngControl.value; - } - } - } + override ngAfterContentInit(): void { + const injectedControl = this.injector.get(NgControl, null); + if (injectedControl) { + const ngControl = injectedControl.control as unknown as KeyValue; + if (ngControl.value) { + this.name = ngControl.key; + this.control = ngControl.value; + } + } + } - handlePaginationChange({ start, end }: { start: number; end: number }): void { - this.pageStart = start; - this.pageEnd = end; - this.cdr.detectChanges(); - } + handlePaginationChange({ start, end }: { start: number; end: number }): void { + this.pageStart = start; + this.pageEnd = end; + this.cdr.detectChanges(); + } - getAdditionalExaminerNotes(): AdditionalExaminerNotes[] { - return (this.currentTechRecord?.techRecord_adrDetails_additionalExaminerNotes ?? []).sort( - (a, b) => +new Date(b.createdAtDate ?? '') - +new Date(a.createdAtDate ?? ''), - ); - } + getAdditionalExaminerNotes(): AdditionalExaminerNotes[] { + return (this.currentTechRecord?.techRecord_adrDetails_additionalExaminerNotes ?? []).sort( + (a, b) => +new Date(b.createdAtDate ?? '') - +new Date(a.createdAtDate ?? '') + ); + } - get currentAdrNotesPage(): AdditionalExaminerNotes[] { - return this.currentTechRecord?.techRecord_adrDetails_additionalExaminerNotes?.slice(this.pageStart, this.pageEnd) ?? []; - } + get currentAdrNotesPage(): AdditionalExaminerNotes[] { + return ( + this.currentTechRecord?.techRecord_adrDetails_additionalExaminerNotes?.slice(this.pageStart, this.pageEnd) ?? [] + ); + } - getEditAdditionalExaminerNotePage(examinerNoteIndex: number) { - const route = `../${this.editingReason}/edit-additional-examiner-note/${examinerNoteIndex}`; + getEditAdditionalExaminerNotePage(examinerNoteIndex: number) { + const route = `../${this.editingReason}/edit-additional-examiner-note/${examinerNoteIndex}`; - this.store.dispatch(updateScrollPosition({ position: this.viewportScroller.getScrollPosition() })); + this.store.dispatch(updateScrollPosition({ position: this.viewportScroller.getScrollPosition() })); - void this.router.navigate([route], { relativeTo: this.route, state: this.currentTechRecord }); - } + void this.router.navigate([route], { relativeTo: this.route, state: this.currentTechRecord }); + } - ngOnDestroy(): void { - this.destroy$.next(true); - this.destroy$.complete(); - } + ngOnDestroy(): void { + this.destroy$.next(true); + this.destroy$.complete(); + } } diff --git a/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.spec.ts b/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.spec.ts index d613b53cfa..fb57508ff5 100644 --- a/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.spec.ts +++ b/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.spec.ts @@ -12,104 +12,105 @@ import { of } from 'rxjs'; import { AdrExaminerNotesHistoryViewComponent } from './adr-examiner-notes-history-view.component'; describe('AdrExaminerNotesHistoryViewComponent', () => { - let component: AdrExaminerNotesHistoryViewComponent; - let fixture: ComponentFixture; + let component: AdrExaminerNotesHistoryViewComponent; + let fixture: ComponentFixture; - const MOCK_HGV = mockVehicleTechnicalRecord(VehicleTypes.HGV) as TechRecordType<'hgv'>; - const mockTechRecordService = { - techRecord$: of({ ...MOCK_HGV }), - }; - const mockRouterService = {}; + const MOCK_HGV = mockVehicleTechnicalRecord(VehicleTypes.HGV) as TechRecordType<'hgv'>; + const mockTechRecordService = { + techRecord$: of({ ...MOCK_HGV }), + }; + const mockRouterService = {}; - const control = new CustomFormControl({ - name: 'techRecord_adrDetails_additionalExaminerNotes', - type: FormNodeTypes.CONTROL, - label: 'Additional Examiner Notes History', - }); + const control = new CustomFormControl({ + name: 'techRecord_adrDetails_additionalExaminerNotes', + type: FormNodeTypes.CONTROL, + label: 'Additional Examiner Notes History', + }); - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AdrExaminerNotesHistoryViewComponent], - providers: [ - provideMockStore({ initialState: initialAppState }), - { provide: TechnicalRecordService, useValue: mockTechRecordService }, - { provide: RouterService, useValue: mockRouterService }, - { provide: NG_VALUE_ACCESSOR, useExisting: AdrExaminerNotesHistoryViewComponent, multi: true }, - { - provide: NgControl, - useValue: { - control: { key: control.meta.name, value: control }, - }, - }, - ], - }) - .compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AdrExaminerNotesHistoryViewComponent], + providers: [ + provideMockStore({ initialState: initialAppState }), + { provide: TechnicalRecordService, useValue: mockTechRecordService }, + { provide: RouterService, useValue: mockRouterService }, + { provide: NG_VALUE_ACCESSOR, useExisting: AdrExaminerNotesHistoryViewComponent, multi: true }, + { + provide: NgControl, + useValue: { + control: { key: control.meta.name, value: control }, + }, + }, + ], + }).compileComponents(); - fixture = TestBed.createComponent(AdrExaminerNotesHistoryViewComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(AdrExaminerNotesHistoryViewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - describe('ngOnInit', () => { - it('should set the currentTechRecord when ngOnInit is fired', () => { - component.currentTechRecord = undefined; + describe('ngOnInit', () => { + it('should set the currentTechRecord when ngOnInit is fired', () => { + component.currentTechRecord = undefined; - component.ngOnInit(); - expect(component.currentTechRecord).toEqual(MOCK_HGV); - }); - }); + component.ngOnInit(); + expect(component.currentTechRecord).toEqual(MOCK_HGV); + }); + }); - describe('adrNotes', () => { - it('should return an array of the technical records adr examiner notes', () => { - component.currentTechRecord = { ...MOCK_HGV }; - component.currentTechRecord.techRecord_adrDetails_additionalExaminerNotes = [ - { createdAtDate: 'test', lastUpdatedBy: 'test', note: 'test note' }, - ]; - expect(component.getAdditionalExaminerNotes()).toEqual([{ createdAtDate: 'test', lastUpdatedBy: 'test', note: 'test note' }]); - }); + describe('adrNotes', () => { + it('should return an array of the technical records adr examiner notes', () => { + component.currentTechRecord = { ...MOCK_HGV }; + component.currentTechRecord.techRecord_adrDetails_additionalExaminerNotes = [ + { createdAtDate: 'test', lastUpdatedBy: 'test', note: 'test note' }, + ]; + expect(component.getAdditionalExaminerNotes()).toEqual([ + { createdAtDate: 'test', lastUpdatedBy: 'test', note: 'test note' }, + ]); + }); - it('should return an empty array if the adr examiner notes is undefined', () => { - component.currentTechRecord = { ...MOCK_HGV }; - component.currentTechRecord.techRecord_adrDetails_additionalExaminerNotes = undefined; - expect(component.getAdditionalExaminerNotes()).toEqual([]); - }); - }); + it('should return an empty array if the adr examiner notes is undefined', () => { + component.currentTechRecord = { ...MOCK_HGV }; + component.currentTechRecord.techRecord_adrDetails_additionalExaminerNotes = undefined; + expect(component.getAdditionalExaminerNotes()).toEqual([]); + }); + }); - describe('currentAdrNotesPage', () => { - it('should return a sliced array of adr notes depending on the page the user is on', () => { - component.currentTechRecord = { ...MOCK_HGV }; - component.pageStart = 2; - component.pageEnd = 3; - component.currentTechRecord.techRecord_adrDetails_additionalExaminerNotes = [ - { createdAtDate: 'test1', lastUpdatedBy: 'test1', note: 'test note 1' }, - { createdAtDate: 'test2', lastUpdatedBy: 'test2', note: 'test note 2' }, - { createdAtDate: 'test3', lastUpdatedBy: 'test3', note: 'test note 3' }, - { createdAtDate: 'test4', lastUpdatedBy: 'test4', note: 'test note 4' }, - ]; - expect(component.currentAdrNotesPage).toEqual([ - { createdAtDate: 'test3', lastUpdatedBy: 'test3', note: 'test note 3' }, - ]); - }); + describe('currentAdrNotesPage', () => { + it('should return a sliced array of adr notes depending on the page the user is on', () => { + component.currentTechRecord = { ...MOCK_HGV }; + component.pageStart = 2; + component.pageEnd = 3; + component.currentTechRecord.techRecord_adrDetails_additionalExaminerNotes = [ + { createdAtDate: 'test1', lastUpdatedBy: 'test1', note: 'test note 1' }, + { createdAtDate: 'test2', lastUpdatedBy: 'test2', note: 'test note 2' }, + { createdAtDate: 'test3', lastUpdatedBy: 'test3', note: 'test note 3' }, + { createdAtDate: 'test4', lastUpdatedBy: 'test4', note: 'test note 4' }, + ]; + expect(component.currentAdrNotesPage).toEqual([ + { createdAtDate: 'test3', lastUpdatedBy: 'test3', note: 'test note 3' }, + ]); + }); - it('should return an empty array if the adr examiner notes is undefined', () => { - component.currentTechRecord = { ...MOCK_HGV }; - component.pageStart = 1; - component.pageEnd = 2; - component.currentTechRecord.techRecord_adrDetails_additionalExaminerNotes = undefined; - expect(component.currentAdrNotesPage).toEqual([]); - }); - }); + it('should return an empty array if the adr examiner notes is undefined', () => { + component.currentTechRecord = { ...MOCK_HGV }; + component.pageStart = 1; + component.pageEnd = 2; + component.currentTechRecord.techRecord_adrDetails_additionalExaminerNotes = undefined; + expect(component.currentAdrNotesPage).toEqual([]); + }); + }); - describe('handlePaginationChange', () => { - it('should set the start and end pages', () => { - component.handlePaginationChange({ start: 0, end: 3 }); + describe('handlePaginationChange', () => { + it('should set the start and end pages', () => { + component.handlePaginationChange({ start: 0, end: 3 }); - expect(component.pageStart).toBe(0); - expect(component.pageEnd).toBe(3); - }); - }); + expect(component.pageStart).toBe(0); + expect(component.pageEnd).toBe(3); + }); + }); }); diff --git a/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.ts b/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.ts index 8e0b8244a7..709703773d 100644 --- a/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.ts +++ b/src/app/forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component.ts @@ -1,64 +1,62 @@ -import { - Component, inject, OnDestroy, OnInit, -} from '@angular/core'; +import { Component, OnDestroy, OnInit, inject } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { AdditionalExaminerNotes } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/hgv/complete'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; import { BaseControlComponent } from '@forms/components/base-control/base-control.component'; import { RouterService } from '@services/router/router.service'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; -import { - map, Observable, Subject, takeUntil, -} from 'rxjs'; +import { Observable, Subject, map, takeUntil } from 'rxjs'; @Component({ - selector: 'app-adr-examiner-notes-history-view', - templateUrl: './adr-examiner-notes-history-view.component.html', - styleUrls: ['./adr-examiner-notes-history-view.component.scss'], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: AdrExaminerNotesHistoryViewComponent, - multi: true, - }, - ], + selector: 'app-adr-examiner-notes-history-view', + templateUrl: './adr-examiner-notes-history-view.component.html', + styleUrls: ['./adr-examiner-notes-history-view.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: AdrExaminerNotesHistoryViewComponent, + multi: true, + }, + ], }) export class AdrExaminerNotesHistoryViewComponent extends BaseControlComponent implements OnInit, OnDestroy { - technicalRecordService = inject(TechnicalRecordService); - routerService = inject(RouterService); - currentTechRecord?: TechRecordType<'hgv' | 'lgv' | 'trl'> | undefined; - pageStart?: number; - pageEnd?: number; - private destroy$: Subject = new Subject(); + technicalRecordService = inject(TechnicalRecordService); + routerService = inject(RouterService); + currentTechRecord?: TechRecordType<'hgv' | 'lgv' | 'trl'> | undefined; + pageStart?: number; + pageEnd?: number; + private destroy$: Subject = new Subject(); - ngOnInit(): void { - this.technicalRecordService.techRecord$.pipe(takeUntil(this.destroy$)).subscribe((currentTechRecord) => { - this.currentTechRecord = currentTechRecord as TechRecordType<'hgv' | 'lgv' | 'trl'>; - }); - } + ngOnInit(): void { + this.technicalRecordService.techRecord$.pipe(takeUntil(this.destroy$)).subscribe((currentTechRecord) => { + this.currentTechRecord = currentTechRecord as TechRecordType<'hgv' | 'lgv' | 'trl'>; + }); + } - get isEditing$(): Observable { - return this.routerService.getRouteDataProperty$('isEditing').pipe(map((isEditing) => !!isEditing)); - } + get isEditing$(): Observable { + return this.routerService.getRouteDataProperty$('isEditing').pipe(map((isEditing) => !!isEditing)); + } - handlePaginationChange({ start, end }: { start: number; end: number }): void { - this.pageStart = start; - this.pageEnd = end; - this.cdr.detectChanges(); - } + handlePaginationChange({ start, end }: { start: number; end: number }): void { + this.pageStart = start; + this.pageEnd = end; + this.cdr.detectChanges(); + } - getAdditionalExaminerNotes(): AdditionalExaminerNotes[] { - return (this.currentTechRecord?.techRecord_adrDetails_additionalExaminerNotes ?? []).sort( - (a, b) => +new Date(b.createdAtDate ?? '') - +new Date(a.createdAtDate ?? ''), - ); - } + getAdditionalExaminerNotes(): AdditionalExaminerNotes[] { + return (this.currentTechRecord?.techRecord_adrDetails_additionalExaminerNotes ?? []).sort( + (a, b) => +new Date(b.createdAtDate ?? '') - +new Date(a.createdAtDate ?? '') + ); + } - get currentAdrNotesPage(): AdditionalExaminerNotes[] { - return this.currentTechRecord?.techRecord_adrDetails_additionalExaminerNotes?.slice(this.pageStart, this.pageEnd) ?? []; - } + get currentAdrNotesPage(): AdditionalExaminerNotes[] { + return ( + this.currentTechRecord?.techRecord_adrDetails_additionalExaminerNotes?.slice(this.pageStart, this.pageEnd) ?? [] + ); + } - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } } diff --git a/src/app/forms/custom-sections/adr-new-certificate-required-view/adr-new-certificate-required-view.component.spec.ts b/src/app/forms/custom-sections/adr-new-certificate-required-view/adr-new-certificate-required-view.component.spec.ts index d36ddc7698..1b81207b10 100644 --- a/src/app/forms/custom-sections/adr-new-certificate-required-view/adr-new-certificate-required-view.component.spec.ts +++ b/src/app/forms/custom-sections/adr-new-certificate-required-view/adr-new-certificate-required-view.component.spec.ts @@ -3,39 +3,38 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NG_VALUE_ACCESSOR, NgControl } from '@angular/forms'; import { CustomFormControl, FormNodeTypes } from '@forms/services/dynamic-form.types'; import { provideMockStore } from '@ngrx/store/testing'; -import { State, initialAppState } from '@store/index'; import { SharedModule } from '@shared/shared.module'; +import { State, initialAppState } from '@store/index'; import { AdrTankDetailsM145ViewComponent } from '../adr-tank-details-m145-view/adr-tank-details-m145-view.component'; import { AdrNewCertificateRequiredViewComponent } from './adr-new-certificate-required-view.component'; describe('AdrNewCertificateRequiredViewComponent', () => { - let component: AdrNewCertificateRequiredViewComponent; - let fixture: ComponentFixture; + let component: AdrNewCertificateRequiredViewComponent; + let fixture: ComponentFixture; - const control = new CustomFormControl({ - name: 'techRecord_adrDetails_m145Statement', - type: FormNodeTypes.CONTROL, - value: [], - }); + const control = new CustomFormControl({ + name: 'techRecord_adrDetails_m145Statement', + type: FormNodeTypes.CONTROL, + value: [], + }); - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AdrNewCertificateRequiredViewComponent], - imports: [SharedModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - { provide: NG_VALUE_ACCESSOR, useExisting: AdrTankDetailsM145ViewComponent, multi: true }, - { provide: NgControl, useValue: { control } }, - ], - }) - .compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AdrNewCertificateRequiredViewComponent], + imports: [SharedModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + { provide: NG_VALUE_ACCESSOR, useExisting: AdrTankDetailsM145ViewComponent, multi: true }, + { provide: NgControl, useValue: { control } }, + ], + }).compileComponents(); - fixture = TestBed.createComponent(AdrNewCertificateRequiredViewComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(AdrNewCertificateRequiredViewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/custom-sections/adr-new-certificate-required-view/adr-new-certificate-required-view.component.ts b/src/app/forms/custom-sections/adr-new-certificate-required-view/adr-new-certificate-required-view.component.ts index 132dcd90de..d9d211587d 100644 --- a/src/app/forms/custom-sections/adr-new-certificate-required-view/adr-new-certificate-required-view.component.ts +++ b/src/app/forms/custom-sections/adr-new-certificate-required-view/adr-new-certificate-required-view.component.ts @@ -3,15 +3,15 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { BaseControlComponent } from '@forms/components/base-control/base-control.component'; @Component({ - selector: 'app-adr-new-certificate-required-view', - templateUrl: './adr-new-certificate-required-view.component.html', - styleUrl: './adr-new-certificate-required-view.component.scss', - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: AdrNewCertificateRequiredViewComponent, - multi: true, - }, - ], + selector: 'app-adr-new-certificate-required-view', + templateUrl: './adr-new-certificate-required-view.component.html', + styleUrl: './adr-new-certificate-required-view.component.scss', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: AdrNewCertificateRequiredViewComponent, + multi: true, + }, + ], }) export class AdrNewCertificateRequiredViewComponent extends BaseControlComponent {} diff --git a/src/app/forms/custom-sections/adr-tank-details-initial-inspection-view/adr-tank-details-initial-inspection-view.component.spec.ts b/src/app/forms/custom-sections/adr-tank-details-initial-inspection-view/adr-tank-details-initial-inspection-view.component.spec.ts index 7f746c1056..095c294d97 100644 --- a/src/app/forms/custom-sections/adr-tank-details-initial-inspection-view/adr-tank-details-initial-inspection-view.component.spec.ts +++ b/src/app/forms/custom-sections/adr-tank-details-initial-inspection-view/adr-tank-details-initial-inspection-view.component.spec.ts @@ -6,36 +6,35 @@ import { State, initialAppState } from '@store/index'; import { AdrTankDetailsInitialInspectionViewComponent } from './adr-tank-details-initial-inspection-view.component'; describe('AdrTankDetailsInitialInspectionViewComponent', () => { - let component: AdrTankDetailsInitialInspectionViewComponent; - let fixture: ComponentFixture; + let component: AdrTankDetailsInitialInspectionViewComponent; + let fixture: ComponentFixture; - const control = new CustomFormControl({ - name: 'tankInspectionsInitialView', - type: FormNodeTypes.CONTROL, - }); + const control = new CustomFormControl({ + name: 'tankInspectionsInitialView', + type: FormNodeTypes.CONTROL, + }); - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AdrTankDetailsInitialInspectionViewComponent], - providers: [ - provideMockStore({ initialState: initialAppState }), - { provide: NG_VALUE_ACCESSOR, useExisting: AdrTankDetailsInitialInspectionViewComponent, multi: true }, - { - provide: NgControl, - useValue: { - control: { key: control.meta.name, value: control }, - }, - }, - ], - }) - .compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AdrTankDetailsInitialInspectionViewComponent], + providers: [ + provideMockStore({ initialState: initialAppState }), + { provide: NG_VALUE_ACCESSOR, useExisting: AdrTankDetailsInitialInspectionViewComponent, multi: true }, + { + provide: NgControl, + useValue: { + control: { key: control.meta.name, value: control }, + }, + }, + ], + }).compileComponents(); - fixture = TestBed.createComponent(AdrTankDetailsInitialInspectionViewComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(AdrTankDetailsInitialInspectionViewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/custom-sections/adr-tank-details-initial-inspection-view/adr-tank-details-initial-inspection-view.component.ts b/src/app/forms/custom-sections/adr-tank-details-initial-inspection-view/adr-tank-details-initial-inspection-view.component.ts index 9379dc1b64..68cf585b19 100644 --- a/src/app/forms/custom-sections/adr-tank-details-initial-inspection-view/adr-tank-details-initial-inspection-view.component.ts +++ b/src/app/forms/custom-sections/adr-tank-details-initial-inspection-view/adr-tank-details-initial-inspection-view.component.ts @@ -2,8 +2,8 @@ import { Component } from '@angular/core'; import { BaseControlComponent } from '@forms/components/base-control/base-control.component'; @Component({ - selector: 'app-adr-tank-details-initial-inspection-view', - templateUrl: './adr-tank-details-initial-inspection-view.component.html', - styleUrls: ['./adr-tank-details-initial-inspection-view.component.scss'], + selector: 'app-adr-tank-details-initial-inspection-view', + templateUrl: './adr-tank-details-initial-inspection-view.component.html', + styleUrls: ['./adr-tank-details-initial-inspection-view.component.scss'], }) export class AdrTankDetailsInitialInspectionViewComponent extends BaseControlComponent {} diff --git a/src/app/forms/custom-sections/adr-tank-details-m145-view/adr-tank-details-m145-view.component.spec.ts b/src/app/forms/custom-sections/adr-tank-details-m145-view/adr-tank-details-m145-view.component.spec.ts index a01d96c1fd..d57f554834 100644 --- a/src/app/forms/custom-sections/adr-tank-details-m145-view/adr-tank-details-m145-view.component.spec.ts +++ b/src/app/forms/custom-sections/adr-tank-details-m145-view/adr-tank-details-m145-view.component.spec.ts @@ -1,7 +1,5 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - FormsModule, NG_VALUE_ACCESSOR, NgControl, ReactiveFormsModule, -} from '@angular/forms'; +import { FormsModule, NG_VALUE_ACCESSOR, NgControl, ReactiveFormsModule } from '@angular/forms'; import { DynamicFormsModule } from '@forms/dynamic-forms.module'; import { CustomFormControl, FormNodeTypes } from '@forms/services/dynamic-form.types'; import { provideMockStore } from '@ngrx/store/testing'; @@ -9,33 +7,32 @@ import { State, initialAppState } from '@store/index'; import { AdrTankDetailsM145ViewComponent } from './adr-tank-details-m145-view.component'; describe('AdrTankDetailsM145ViewComponent', () => { - let component: AdrTankDetailsM145ViewComponent; - let fixture: ComponentFixture; + let component: AdrTankDetailsM145ViewComponent; + let fixture: ComponentFixture; - const control = new CustomFormControl({ - name: 'techRecord_adrDetails_m145Statement', - type: FormNodeTypes.CONTROL, - value: [], - }); + const control = new CustomFormControl({ + name: 'techRecord_adrDetails_m145Statement', + type: FormNodeTypes.CONTROL, + value: [], + }); - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AdrTankDetailsM145ViewComponent], - imports: [DynamicFormsModule, FormsModule, ReactiveFormsModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - { provide: NG_VALUE_ACCESSOR, useExisting: AdrTankDetailsM145ViewComponent, multi: true }, - { provide: NgControl, useValue: { control } }, - ], - }) - .compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AdrTankDetailsM145ViewComponent], + imports: [DynamicFormsModule, FormsModule, ReactiveFormsModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + { provide: NG_VALUE_ACCESSOR, useExisting: AdrTankDetailsM145ViewComponent, multi: true }, + { provide: NgControl, useValue: { control } }, + ], + }).compileComponents(); - fixture = TestBed.createComponent(AdrTankDetailsM145ViewComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(AdrTankDetailsM145ViewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/custom-sections/adr-tank-details-m145-view/adr-tank-details-m145-view.component.ts b/src/app/forms/custom-sections/adr-tank-details-m145-view/adr-tank-details-m145-view.component.ts index b94c9c0b5d..5efce00d67 100644 --- a/src/app/forms/custom-sections/adr-tank-details-m145-view/adr-tank-details-m145-view.component.ts +++ b/src/app/forms/custom-sections/adr-tank-details-m145-view/adr-tank-details-m145-view.component.ts @@ -3,17 +3,15 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { BaseControlComponent } from '@forms/components/base-control/base-control.component'; @Component({ - selector: 'app-adr-tank-details-m145-view', - templateUrl: './adr-tank-details-m145-view.component.html', - styleUrls: ['./adr-tank-details-m145-view.component.scss'], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: AdrTankDetailsM145ViewComponent, - multi: true, - }, - ], + selector: 'app-adr-tank-details-m145-view', + templateUrl: './adr-tank-details-m145-view.component.html', + styleUrls: ['./adr-tank-details-m145-view.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: AdrTankDetailsM145ViewComponent, + multi: true, + }, + ], }) -export class AdrTankDetailsM145ViewComponent extends BaseControlComponent { - -} +export class AdrTankDetailsM145ViewComponent extends BaseControlComponent {} diff --git a/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component.spec.ts b/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component.spec.ts index 50f8f35277..b5788ad7d0 100644 --- a/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component.spec.ts +++ b/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component.spec.ts @@ -1,8 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - FormsModule, NG_VALUE_ACCESSOR, NgControl, ReactiveFormsModule, -} from '@angular/forms'; +import { FormsModule, NG_VALUE_ACCESSOR, NgControl, ReactiveFormsModule } from '@angular/forms'; import { DateComponent } from '@forms/components/date/date.component'; import { FORM_INJECTION_TOKEN } from '@forms/components/dynamic-form-field/dynamic-form-field.component'; import { FieldErrorMessageComponent } from '@forms/components/field-error-message/field-error-message.component'; @@ -10,164 +8,164 @@ import { SelectComponent } from '@forms/components/select/select.component'; import { TextInputComponent } from '@forms/components/text-input/text-input.component'; import { DynamicFormsModule } from '@forms/dynamic-forms.module'; import { - CustomFormControl, - CustomFormGroup, - FormNodeTypes, - FormNodeViewTypes, + CustomFormControl, + CustomFormGroup, + FormNodeTypes, + FormNodeViewTypes, } from '@forms/services/dynamic-form.types'; import { provideMockStore } from '@ngrx/store/testing'; import { State, initialAppState } from '@store/index'; import { AdrTankDetailsSubsequentInspectionsEditComponent } from './adr-tank-details-subsequent-inspections-edit.component'; describe('AdrTankDetailsSubsequentInspectionsEditComponent', () => { - let component: AdrTankDetailsSubsequentInspectionsEditComponent; - let fixture: ComponentFixture; - - const control = new CustomFormControl({ - name: 'techRecord_adrDetails_tank_tankDetails_tc3Details', - type: FormNodeTypes.CONTROL, - }); - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ - AdrTankDetailsSubsequentInspectionsEditComponent, - SelectComponent, - FieldErrorMessageComponent, - DateComponent, - TextInputComponent, - ], - imports: [DynamicFormsModule, FormsModule, ReactiveFormsModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - { provide: NG_VALUE_ACCESSOR, useExisting: AdrTankDetailsSubsequentInspectionsEditComponent, multi: true }, - { - provide: NgControl, - useValue: { - control: { key: control.meta.name, value: control }, - }, - }, - { - provide: FORM_INJECTION_TOKEN, - useValue: new CustomFormGroup({ - name: '1', - label: 'Subsequent', - type: FormNodeTypes.GROUP, - customId: `subsequent[${1}]`, - children: [ - { - name: 'tc3Type', - type: FormNodeTypes.CONTROL, - label: 'TC3: Inspection Type', - customId: `tc3Type[${1}]`, - }, - { - name: 'tc3PeriodicNumber', - label: 'TC3: Certificate Number', - type: FormNodeTypes.CONTROL, + let component: AdrTankDetailsSubsequentInspectionsEditComponent; + let fixture: ComponentFixture; - }, - { - name: 'tc3PeriodicExpiryDate', - label: 'TC3: Expiry Date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - }, - ], - }, { - tc3Type: new CustomFormControl({ - name: 'tc3Type', - type: FormNodeTypes.CONTROL, - }), - tc3PeriodicNumber: new CustomFormControl({ - name: 'tc3PeriodicNumber', - type: FormNodeTypes.CONTROL, - }), - tc3PeriodicExpiryDate: new CustomFormControl({ - name: 'tc3PeriodicExpiryDate', - type: FormNodeTypes.CONTROL, - }), - }), + const control = new CustomFormControl({ + name: 'techRecord_adrDetails_tank_tankDetails_tc3Details', + type: FormNodeTypes.CONTROL, + }); - }, - ], - }) - .compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + AdrTankDetailsSubsequentInspectionsEditComponent, + SelectComponent, + FieldErrorMessageComponent, + DateComponent, + TextInputComponent, + ], + imports: [DynamicFormsModule, FormsModule, ReactiveFormsModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + { provide: NG_VALUE_ACCESSOR, useExisting: AdrTankDetailsSubsequentInspectionsEditComponent, multi: true }, + { + provide: NgControl, + useValue: { + control: { key: control.meta.name, value: control }, + }, + }, + { + provide: FORM_INJECTION_TOKEN, + useValue: new CustomFormGroup( + { + name: '1', + label: 'Subsequent', + type: FormNodeTypes.GROUP, + customId: `subsequent[${1}]`, + children: [ + { + name: 'tc3Type', + type: FormNodeTypes.CONTROL, + label: 'TC3: Inspection Type', + customId: `tc3Type[${1}]`, + }, + { + name: 'tc3PeriodicNumber', + label: 'TC3: Certificate Number', + type: FormNodeTypes.CONTROL, + }, + { + name: 'tc3PeriodicExpiryDate', + label: 'TC3: Expiry Date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + }, + ], + }, + { + tc3Type: new CustomFormControl({ + name: 'tc3Type', + type: FormNodeTypes.CONTROL, + }), + tc3PeriodicNumber: new CustomFormControl({ + name: 'tc3PeriodicNumber', + type: FormNodeTypes.CONTROL, + }), + tc3PeriodicExpiryDate: new CustomFormControl({ + name: 'tc3PeriodicExpiryDate', + type: FormNodeTypes.CONTROL, + }), + } + ), + }, + ], + }).compileComponents(); - fixture = TestBed.createComponent(AdrTankDetailsSubsequentInspectionsEditComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(AdrTankDetailsSubsequentInspectionsEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - beforeEach(() => { - component.formArray.patchValue([]); - }); + beforeEach(() => { + component.formArray.patchValue([]); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it('should, upon instantiation, add a form control to the form array', () => { - expect(component.formArray).toHaveLength(0); - }); + it('should, upon instantiation, add a form control to the form array', () => { + expect(component.formArray).toHaveLength(0); + }); - describe('ngOnInit', () => { - it('should set a subscription to listen to form array changes, and patch the control value', () => { - const ngOnInitSpy = jest.spyOn(component, 'ngOnInit'); - component.ngOnInit(); - expect(ngOnInitSpy).toHaveBeenCalled(); - }); - }); + describe('ngOnInit', () => { + it('should set a subscription to listen to form array changes, and patch the control value', () => { + const ngOnInitSpy = jest.spyOn(component, 'ngOnInit'); + component.ngOnInit(); + expect(ngOnInitSpy).toHaveBeenCalled(); + }); + }); - describe('ngOnDestroy', () => { - it('should next true and complete the destroy subject, triggering all subscriptions linked to it to complete also', () => { - const ngOnDestroySpy = jest.spyOn(component, 'ngOnDestroy'); - const destroySubjectNextSpy = jest.spyOn(component.destroy$, 'next'); - const destroySubjectCompletedSpy = jest.spyOn(component.destroy$, 'complete'); - component.ngOnDestroy(); - expect(ngOnDestroySpy).toHaveBeenCalled(); - expect(destroySubjectNextSpy).toHaveBeenCalledWith(true); - expect(destroySubjectCompletedSpy).toHaveBeenCalled(); - }); - }); + describe('ngOnDestroy', () => { + it('should next true and complete the destroy subject, triggering all subscriptions linked to it to complete also', () => { + const ngOnDestroySpy = jest.spyOn(component, 'ngOnDestroy'); + const destroySubjectNextSpy = jest.spyOn(component.destroy$, 'next'); + const destroySubjectCompletedSpy = jest.spyOn(component.destroy$, 'complete'); + component.ngOnDestroy(); + expect(ngOnDestroySpy).toHaveBeenCalled(); + expect(destroySubjectNextSpy).toHaveBeenCalledWith(true); + expect(destroySubjectCompletedSpy).toHaveBeenCalled(); + }); + }); - describe('createSubsequentInspection', () => { - it('should return a new form group representing a subsequent inspection (for ADR Tank Details)', () => { - const index = 1; - const methodSpy = jest.spyOn(component, 'createSubsequentInspection'); - const result = component.createSubsequentInspection(1); - expect(methodSpy).toHaveBeenCalled(); - expect(result).toBeDefined(); - expect(result.meta).toBeDefined(); - expect(result.meta.customId).toBe(`subsequent[${index}]`); - expect(Object.values(result.controls)).toHaveLength(3); - expect(result.get('techRecord_adrDetails_tank_tankDetails_tc3Details_tc3Type')).toBeDefined(); - expect(result.get('techRecord_adrDetails_tank_tankDetails_tc3Type_tc3PeriodicNumber')).toBeDefined(); - expect(result.get('techRecord_adrDetails_tank_tankDetails_tc3Type_tc3PeriodicExpiryDate')).toBeDefined(); - }); - }); + describe('createSubsequentInspection', () => { + it('should return a new form group representing a subsequent inspection (for ADR Tank Details)', () => { + const index = 1; + const methodSpy = jest.spyOn(component, 'createSubsequentInspection'); + const result = component.createSubsequentInspection(1); + expect(methodSpy).toHaveBeenCalled(); + expect(result).toBeDefined(); + expect(result.meta).toBeDefined(); + expect(result.meta.customId).toBe(`subsequent[${index}]`); + expect(Object.values(result.controls)).toHaveLength(3); + expect(result.get('techRecord_adrDetails_tank_tankDetails_tc3Details_tc3Type')).toBeDefined(); + expect(result.get('techRecord_adrDetails_tank_tankDetails_tc3Type_tc3PeriodicNumber')).toBeDefined(); + expect(result.get('techRecord_adrDetails_tank_tankDetails_tc3Type_tc3PeriodicExpiryDate')).toBeDefined(); + }); + }); - describe('addSubsequentInspection', () => { - it('should add an extra form group to the end of the form array', () => { - const methodSpy = jest.spyOn(component, 'addSubsequentInspection'); - component.addSubsequentInspection(); - expect(methodSpy).toHaveBeenCalled(); - expect(component.formArray).toHaveLength(1); - }); - }); + describe('addSubsequentInspection', () => { + it('should add an extra form group to the end of the form array', () => { + const methodSpy = jest.spyOn(component, 'addSubsequentInspection'); + component.addSubsequentInspection(); + expect(methodSpy).toHaveBeenCalled(); + expect(component.formArray).toHaveLength(1); + }); + }); - describe('removeSubsequentInspection', () => { - it('should remove the form group, from the form array at the correct index', () => { - component.addSubsequentInspection(); - component.addSubsequentInspection(); - component.addSubsequentInspection(); - const methodSpy = jest.spyOn(component, 'removeSubsequentInspection'); - component.removeSubsequentInspection(3); - component.removeSubsequentInspection(2); - component.removeSubsequentInspection(1); - component.removeSubsequentInspection(0); - expect(methodSpy).toHaveBeenCalledTimes(4); - expect(component.formArray).toHaveLength(0); - }); - }); + describe('removeSubsequentInspection', () => { + it('should remove the form group, from the form array at the correct index', () => { + component.addSubsequentInspection(); + component.addSubsequentInspection(); + component.addSubsequentInspection(); + const methodSpy = jest.spyOn(component, 'removeSubsequentInspection'); + component.removeSubsequentInspection(3); + component.removeSubsequentInspection(2); + component.removeSubsequentInspection(1); + component.removeSubsequentInspection(0); + expect(methodSpy).toHaveBeenCalledTimes(4); + expect(component.formArray).toHaveLength(0); + }); + }); }); diff --git a/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component.ts b/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component.ts index f31bd9d781..afed416351 100644 --- a/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component.ts +++ b/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component.ts @@ -1,134 +1,134 @@ -import { - AfterContentInit, - Component, - OnDestroy, - OnInit, -} from '@angular/core'; +import { AfterContentInit, Component, OnDestroy, OnInit } from '@angular/core'; import { FormArray, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { TC3Types } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/tc3Types.enum.js'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - CustomFormControl, - CustomFormGroup, - FormNodeEditTypes, - FormNodeTypes, - FormNodeViewTypes, + CustomFormControl, + CustomFormGroup, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, } from '@forms/services/dynamic-form.types'; import { getOptionsFromEnum } from '@forms/utils/enum-map'; import { CustomValidators } from '@forms/validators/custom-validators'; -import { - ReplaySubject, - takeUntil, -} from 'rxjs'; +import { ReplaySubject, takeUntil } from 'rxjs'; import { CustomFormControlComponent } from '../custom-form-control/custom-form-control.component'; @Component({ - selector: 'app-adr-tank-details-subsequent-inspections', - templateUrl: './adr-tank-details-subsequent-inspections-edit.component.html', - styleUrls: ['./adr-tank-details-subsequent-inspections-edit.component.scss'], - providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: AdrTankDetailsSubsequentInspectionsEditComponent, multi: true }], + selector: 'app-adr-tank-details-subsequent-inspections', + templateUrl: './adr-tank-details-subsequent-inspections-edit.component.html', + styleUrls: ['./adr-tank-details-subsequent-inspections-edit.component.scss'], + providers: [ + { provide: NG_VALUE_ACCESSOR, useExisting: AdrTankDetailsSubsequentInspectionsEditComponent, multi: true }, + ], }) -export class AdrTankDetailsSubsequentInspectionsEditComponent extends CustomFormControlComponent implements OnInit, OnDestroy, AfterContentInit { - destroy$ = new ReplaySubject(1); +export class AdrTankDetailsSubsequentInspectionsEditComponent + extends CustomFormControlComponent + implements OnInit, OnDestroy, AfterContentInit +{ + destroy$ = new ReplaySubject(1); - formArray = new FormArray([]); + formArray = new FormArray([]); - ngOnInit() { - this.formArray.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((changes) => { - this.control?.patchValue(changes, { emitModelToViewChange: true }); - }); - } + ngOnInit() { + this.formArray.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((changes) => { + this.control?.patchValue(changes, { emitModelToViewChange: true }); + }); + } - ngOnDestroy(): void { - this.destroy$.next(true); - this.destroy$.complete(); - } + ngOnDestroy(): void { + this.destroy$.next(true); + this.destroy$.complete(); + } - override ngAfterContentInit() { - super.ngAfterContentInit(); - if (this.form) { - const value = this.form?.get(this.name)?.value; - const values = Array.isArray(value) && value.length ? value : []; + override ngAfterContentInit() { + super.ngAfterContentInit(); + if (this.form) { + const value = this.form?.get(this.name)?.value; + const values = Array.isArray(value) && value.length ? value : []; - values.forEach((formValue: { tc3Type: string, tc3PeriodicNumber: string, tc3PeriodicExpiryDate: string }, index: number) => { - const control = this.createSubsequentInspection(index); - control.patchValue(formValue); - this.formArray.push(control); - }); - } - } + values.forEach( + (formValue: { tc3Type: string; tc3PeriodicNumber: string; tc3PeriodicExpiryDate: string }, index: number) => { + const control = this.createSubsequentInspection(index); + control.patchValue(formValue); + this.formArray.push(control); + } + ); + } + } - createSubsequentInspection(index: number) { - const newFormGroup = new CustomFormGroup({ - name: index.toString(), - label: 'Subsequent', - type: FormNodeTypes.GROUP, - customId: `subsequent[${index}]`, - validators: [{ name: ValidatorNames.Tc3TestValidator }], - children: [ - { - name: 'tc3Type', - type: FormNodeTypes.CONTROL, - label: 'TC3: Inspection Type', - options: getOptionsFromEnum(TC3Types), - customId: `tc3Type[${index}]`, - }, - { - name: 'tc3PeriodicNumber', - label: 'TC3: Certificate Number', - type: FormNodeTypes.CONTROL, - customId: `tc3PeriodicNumber[${index}]`, - }, - { - name: 'tc3PeriodicExpiryDate', - label: 'TC3: Expiry Date', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.DATE, - viewType: FormNodeViewTypes.DATE, - customId: `tc3PeriodicExpiryDate[${index}]`, - }, - ], - }, { - tc3Type: new CustomFormControl({ - name: 'tc3Type', - type: FormNodeTypes.CONTROL, - }), - tc3PeriodicNumber: new CustomFormControl({ - name: 'tc3PeriodicNumber', - type: FormNodeTypes.CONTROL, - }), - tc3PeriodicExpiryDate: new CustomFormControl({ - name: 'tc3PeriodicExpiryDate', - type: FormNodeTypes.CONTROL, - }), - }); + createSubsequentInspection(index: number) { + const newFormGroup = new CustomFormGroup( + { + name: index.toString(), + label: 'Subsequent', + type: FormNodeTypes.GROUP, + customId: `subsequent[${index}]`, + validators: [{ name: ValidatorNames.Tc3TestValidator }], + children: [ + { + name: 'tc3Type', + type: FormNodeTypes.CONTROL, + label: 'TC3: Inspection Type', + options: getOptionsFromEnum(TC3Types), + customId: `tc3Type[${index}]`, + }, + { + name: 'tc3PeriodicNumber', + label: 'TC3: Certificate Number', + type: FormNodeTypes.CONTROL, + customId: `tc3PeriodicNumber[${index}]`, + }, + { + name: 'tc3PeriodicExpiryDate', + label: 'TC3: Expiry Date', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.DATE, + viewType: FormNodeViewTypes.DATE, + customId: `tc3PeriodicExpiryDate[${index}]`, + }, + ], + }, + { + tc3Type: new CustomFormControl({ + name: 'tc3Type', + type: FormNodeTypes.CONTROL, + }), + tc3PeriodicNumber: new CustomFormControl({ + name: 'tc3PeriodicNumber', + type: FormNodeTypes.CONTROL, + }), + tc3PeriodicExpiryDate: new CustomFormControl({ + name: 'tc3PeriodicExpiryDate', + type: FormNodeTypes.CONTROL, + }), + } + ); - newFormGroup.get('tc3PeriodicNumber')?.addValidators(Validators.maxLength(75)); - newFormGroup.get('tc3PeriodicExpiryDate')?.addValidators( - CustomValidators.tc3TestValidator({ inspectionNumber: index + 1 }), - ); - newFormGroup.get('tc3PeriodicNumber')?.addValidators( - CustomValidators.tc3TestValidator({ inspectionNumber: index + 1 }), - ); - newFormGroup.get('tc3Type')?.addValidators( - CustomValidators.tc3TestValidator({ inspectionNumber: index + 1 }), - ); + newFormGroup.get('tc3PeriodicNumber')?.addValidators(Validators.maxLength(75)); + newFormGroup + .get('tc3PeriodicExpiryDate') + ?.addValidators(CustomValidators.tc3TestValidator({ inspectionNumber: index + 1 })); + newFormGroup + .get('tc3PeriodicNumber') + ?.addValidators(CustomValidators.tc3TestValidator({ inspectionNumber: index + 1 })); + newFormGroup.get('tc3Type')?.addValidators(CustomValidators.tc3TestValidator({ inspectionNumber: index + 1 })); - return newFormGroup; - } + return newFormGroup; + } - addSubsequentInspection() { - this.formArray.push(this.createSubsequentInspection(this.formArray.length)); - } + addSubsequentInspection() { + this.formArray.push(this.createSubsequentInspection(this.formArray.length)); + } - removeSubsequentInspection(index: number) { - this.formArray.removeAt(index); - } + removeSubsequentInspection(index: number) { + this.formArray.removeAt(index); + } - handleChanges(index: number): void { - this.formArray.controls[`${index}`].markAllAsTouched(); - this.formArray.controls[`${index}`].get('tc3Type')?.updateValueAndValidity(); - this.formArray.controls[`${index}`].get('tc3PeriodicNumber')?.updateValueAndValidity(); - this.formArray.controls[`${index}`].get('tc3PeriodicExpiryDate')?.updateValueAndValidity(); - } + handleChanges(index: number): void { + this.formArray.controls[`${index}`].markAllAsTouched(); + this.formArray.controls[`${index}`].get('tc3Type')?.updateValueAndValidity(); + this.formArray.controls[`${index}`].get('tc3PeriodicNumber')?.updateValueAndValidity(); + this.formArray.controls[`${index}`].get('tc3PeriodicExpiryDate')?.updateValueAndValidity(); + } } diff --git a/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-view/adr-tank-details-subsequent-inspections-view.component.spec.ts b/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-view/adr-tank-details-subsequent-inspections-view.component.spec.ts index adcab2b9b3..69f7ebd74e 100644 --- a/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-view/adr-tank-details-subsequent-inspections-view.component.spec.ts +++ b/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-view/adr-tank-details-subsequent-inspections-view.component.spec.ts @@ -1,7 +1,5 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - FormsModule, NG_VALUE_ACCESSOR, NgControl, ReactiveFormsModule, -} from '@angular/forms'; +import { FormsModule, NG_VALUE_ACCESSOR, NgControl, ReactiveFormsModule } from '@angular/forms'; import { DynamicFormsModule } from '@forms/dynamic-forms.module'; import { CustomFormControl, FormNodeTypes } from '@forms/services/dynamic-form.types'; import { provideMockStore } from '@ngrx/store/testing'; @@ -9,33 +7,32 @@ import { State, initialAppState } from '@store/index'; import { AdrTankDetailsSubsequentInspectionsViewComponent } from './adr-tank-details-subsequent-inspections-view.component'; describe('AdrTankDetailsSubsequentInspectionsViewComponent', () => { - let component: AdrTankDetailsSubsequentInspectionsViewComponent; - let fixture: ComponentFixture; + let component: AdrTankDetailsSubsequentInspectionsViewComponent; + let fixture: ComponentFixture; - const control = new CustomFormControl({ - name: 'techRecord_adrDetails_tank_tankDetails_tc3Details', - type: FormNodeTypes.CONTROL, - value: [], - }); + const control = new CustomFormControl({ + name: 'techRecord_adrDetails_tank_tankDetails_tc3Details', + type: FormNodeTypes.CONTROL, + value: [], + }); - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AdrTankDetailsSubsequentInspectionsViewComponent], - imports: [DynamicFormsModule, FormsModule, ReactiveFormsModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - { provide: NG_VALUE_ACCESSOR, useExisting: AdrTankDetailsSubsequentInspectionsViewComponent, multi: true }, - { provide: NgControl, useValue: { control } }, - ], - }) - .compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AdrTankDetailsSubsequentInspectionsViewComponent], + imports: [DynamicFormsModule, FormsModule, ReactiveFormsModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + { provide: NG_VALUE_ACCESSOR, useExisting: AdrTankDetailsSubsequentInspectionsViewComponent, multi: true }, + { provide: NgControl, useValue: { control } }, + ], + }).compileComponents(); - fixture = TestBed.createComponent(AdrTankDetailsSubsequentInspectionsViewComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(AdrTankDetailsSubsequentInspectionsViewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-view/adr-tank-details-subsequent-inspections-view.component.ts b/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-view/adr-tank-details-subsequent-inspections-view.component.ts index c931f32c54..efbb59c4a0 100644 --- a/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-view/adr-tank-details-subsequent-inspections-view.component.ts +++ b/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-view/adr-tank-details-subsequent-inspections-view.component.ts @@ -3,17 +3,15 @@ import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { BaseControlComponent } from '@forms/components/base-control/base-control.component'; @Component({ - selector: 'app-adr-tank-details-subsequent-inspections-view', - templateUrl: './adr-tank-details-subsequent-inspections-view.component.html', - styleUrls: ['./adr-tank-details-subsequent-inspections-view.component.scss'], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: AdrTankDetailsSubsequentInspectionsViewComponent, - multi: true, - }, - ], + selector: 'app-adr-tank-details-subsequent-inspections-view', + templateUrl: './adr-tank-details-subsequent-inspections-view.component.html', + styleUrls: ['./adr-tank-details-subsequent-inspections-view.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: AdrTankDetailsSubsequentInspectionsViewComponent, + multi: true, + }, + ], }) -export class AdrTankDetailsSubsequentInspectionsViewComponent extends BaseControlComponent { - -} +export class AdrTankDetailsSubsequentInspectionsViewComponent extends BaseControlComponent {} diff --git a/src/app/forms/custom-sections/adr-tank-statement-un-number-edit/adr-tank-statement-un-number-edit.component.spec.ts b/src/app/forms/custom-sections/adr-tank-statement-un-number-edit/adr-tank-statement-un-number-edit.component.spec.ts index a4e417396c..8c92817282 100644 --- a/src/app/forms/custom-sections/adr-tank-statement-un-number-edit/adr-tank-statement-un-number-edit.component.spec.ts +++ b/src/app/forms/custom-sections/adr-tank-statement-un-number-edit/adr-tank-statement-un-number-edit.component.spec.ts @@ -1,9 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - FormBuilder, - FormControl, FormGroup, NG_VALUE_ACCESSOR, NgControl, -} from '@angular/forms'; +import { FormBuilder, FormControl, FormGroup, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms'; import { GlobalWarningService } from '@core/components/global-warning/global-warning.service'; import { FORM_INJECTION_TOKEN } from '@forms/components/dynamic-form-field/dynamic-form-field.component'; import { DynamicFormsModule } from '@forms/dynamic-forms.module'; @@ -14,100 +11,99 @@ import { initialAppState } from '@store/index'; import { AdrTankStatementUnNumberEditComponent } from './adr-tank-statement-un-number-edit.component'; describe('AdrTankStatementUnNumberEditComponent', () => { - let fb: FormBuilder; - let component: AdrTankStatementUnNumberEditComponent; - let fixture: ComponentFixture; + let fb: FormBuilder; + let component: AdrTankStatementUnNumberEditComponent; + let fixture: ComponentFixture; - const control = new CustomFormControl({ - name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo', - label: 'UN Number', - type: FormNodeTypes.CONTROL, - }); + const control = new CustomFormControl({ + name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo', + label: 'UN Number', + type: FormNodeTypes.CONTROL, + }); - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [DynamicFormsModule, SharedModule], - declarations: [AdrTankStatementUnNumberEditComponent], - providers: [ - FormBuilder, - provideMockStore({ initialState: initialAppState }), - { provide: GlobalWarningService, useValue: { error$: jest.fn() } }, - { provide: NG_VALUE_ACCESSOR, useExisting: AdrTankStatementUnNumberEditComponent, multi: true }, - { - provide: NgControl, - useValue: { - control: { key: control.meta.name, value: control }, - }, - }, - { - provide: FORM_INJECTION_TOKEN, - useValue: new FormGroup({ - techRecord_adrDetails_additionalNotes_guidanceNotes: new FormControl(null), - }), - }, - ], - }) - .compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [DynamicFormsModule, SharedModule], + declarations: [AdrTankStatementUnNumberEditComponent], + providers: [ + FormBuilder, + provideMockStore({ initialState: initialAppState }), + { provide: GlobalWarningService, useValue: { error$: jest.fn() } }, + { provide: NG_VALUE_ACCESSOR, useExisting: AdrTankStatementUnNumberEditComponent, multi: true }, + { + provide: NgControl, + useValue: { + control: { key: control.meta.name, value: control }, + }, + }, + { + provide: FORM_INJECTION_TOKEN, + useValue: new FormGroup({ + techRecord_adrDetails_additionalNotes_guidanceNotes: new FormControl(null), + }), + }, + ], + }).compileComponents(); - fb = TestBed.inject(FormBuilder); - fixture = TestBed.createComponent(AdrTankStatementUnNumberEditComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fb = TestBed.inject(FormBuilder); + fixture = TestBed.createComponent(AdrTankStatementUnNumberEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - describe('ngAfterContentInit', () => { - it('should add an initial control to the form array once the form is injected into the component', () => { - const spy = jest.spyOn(component, 'addControl'); - component.ngAfterContentInit(); - expect(spy).toHaveBeenCalled(); - expect(component.formArray.value).toHaveLength(1); - }); - }); + describe('ngAfterContentInit', () => { + it('should add an initial control to the form array once the form is injected into the component', () => { + const spy = jest.spyOn(component, 'addControl'); + component.ngAfterContentInit(); + expect(spy).toHaveBeenCalled(); + expect(component.formArray.value).toHaveLength(1); + }); + }); - describe('addControl', () => { - it('should add a copy of the control to the end of the form array', () => { - const spy = jest.spyOn(component, 'addControl'); - component.formArray = fb.array([]); - component.addControl('valid'); - component.addControl('valid'); - component.addControl('valid'); - component.addControl('valid'); - component.addControl('valid'); - expect(spy).toHaveBeenCalled(); - expect(component.formArray.value).toHaveLength(5); - }); + describe('addControl', () => { + it('should add a copy of the control to the end of the form array', () => { + const spy = jest.spyOn(component, 'addControl'); + component.formArray = fb.array([]); + component.addControl('valid'); + component.addControl('valid'); + component.addControl('valid'); + component.addControl('valid'); + component.addControl('valid'); + expect(spy).toHaveBeenCalled(); + expect(component.formArray.value).toHaveLength(5); + }); - it('should prevent the adding of additional controls, when the previous one is empty', () => { - component.formArray = fb.array([]); - component.addControl('valid'); - component.addControl(); - component.addControl(); - expect(component.formArray.value).toHaveLength(2); - }); - }); + it('should prevent the adding of additional controls, when the previous one is empty', () => { + component.formArray = fb.array([]); + component.addControl('valid'); + component.addControl(); + component.addControl(); + expect(component.formArray.value).toHaveLength(2); + }); + }); - describe('removeControl', () => { - it('should remove the UN number control from the form array at the index specified', () => { - const methodSpy = jest.spyOn(component, 'removeControl'); + describe('removeControl', () => { + it('should remove the UN number control from the form array at the index specified', () => { + const methodSpy = jest.spyOn(component, 'removeControl'); - component.formArray.patchValue(['valid']); // ensure initial is valid to allow adding subsequent controls - component.addControl('valid'); - component.addControl('valid'); - component.addControl('valid'); - component.addControl('valid'); + component.formArray.patchValue(['valid']); // ensure initial is valid to allow adding subsequent controls + component.addControl('valid'); + component.addControl('valid'); + component.addControl('valid'); + component.addControl('valid'); - component.removeControl(3); - component.removeControl(2); + component.removeControl(3); + component.removeControl(2); - expect(methodSpy).toHaveBeenCalledTimes(2); - expect(component.formArray.controls.at(4)).toBeUndefined(); - expect(component.formArray.controls.at(3)).toBeUndefined(); - expect(component.formArray.controls.at(2)).toBeDefined(); - expect(component.formArray.controls).toHaveLength(3); - }); - }); + expect(methodSpy).toHaveBeenCalledTimes(2); + expect(component.formArray.controls.at(4)).toBeUndefined(); + expect(component.formArray.controls.at(3)).toBeUndefined(); + expect(component.formArray.controls.at(2)).toBeDefined(); + expect(component.formArray.controls).toHaveLength(3); + }); + }); }); diff --git a/src/app/forms/custom-sections/adr-tank-statement-un-number-edit/adr-tank-statement-un-number-edit.component.ts b/src/app/forms/custom-sections/adr-tank-statement-un-number-edit/adr-tank-statement-un-number-edit.component.ts index d9a3294edb..fc1572a6f5 100644 --- a/src/app/forms/custom-sections/adr-tank-statement-un-number-edit/adr-tank-statement-un-number-edit.component.ts +++ b/src/app/forms/custom-sections/adr-tank-statement-un-number-edit/adr-tank-statement-un-number-edit.component.ts @@ -1,66 +1,63 @@ -import { - Component, OnDestroy, inject, -} from '@angular/core'; +import { Component, OnDestroy, inject } from '@angular/core'; import { FormBuilder, Validators } from '@angular/forms'; import { CustomFormControl, FormNodeTypes } from '@forms/services/dynamic-form.types'; import { Subject, takeUntil } from 'rxjs'; import { CustomFormControlComponent } from '../custom-form-control/custom-form-control.component'; @Component({ - selector: 'app-adr-tank-statement-un-number', - templateUrl: './adr-tank-statement-un-number-edit.component.html', - styleUrls: ['./adr-tank-statement-un-number-edit.component.scss'], + selector: 'app-adr-tank-statement-un-number', + templateUrl: './adr-tank-statement-un-number-edit.component.html', + styleUrls: ['./adr-tank-statement-un-number-edit.component.scss'], }) export class AdrTankStatementUnNumberEditComponent extends CustomFormControlComponent implements OnDestroy { - fb = inject(FormBuilder); - - destroy$ = new Subject(); - formArray = this.fb.array([]); - - onFormArrayChange = this.formArray.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((changes) => { - this.control?.patchValue(changes, { emitModelToViewChange: true }); - }); - - ngOnDestroy(): void { - this.destroy$.next(true); - this.destroy$.complete(); - } - - override ngAfterContentInit(): void { - super.ngAfterContentInit(); - this.buildFormArray(); - } - - buildFormArray() { - const values: string[] = this.control?.value ?? ['']; - values.forEach((value) => this.addControl(value)); - } - - addControl(value = '') { - const lastUnNumber = this.formArray.at(-1); - - if (this.formArray.length > 0 && (lastUnNumber.invalid || !lastUnNumber.value)) { - // If the parent control or lastUnNumber control isn't already invalid set additional errors - if (!this.control?.invalid && !lastUnNumber.invalid) { - lastUnNumber.setErrors({ required: true }); - } - - // Mark as touched to show errors - this.formArray.markAllAsTouched(); - - return; - } - - this.formArray.push( - new CustomFormControl( - { type: FormNodeTypes.CONTROL, name: 'UN number' }, - value, - [Validators.minLength(1), Validators.maxLength(1500)], - ), - ); - } - - removeControl(index: number) { - this.formArray.removeAt(index); - } + fb = inject(FormBuilder); + + destroy$ = new Subject(); + formArray = this.fb.array([]); + + onFormArrayChange = this.formArray.valueChanges.pipe(takeUntil(this.destroy$)).subscribe((changes) => { + this.control?.patchValue(changes, { emitModelToViewChange: true }); + }); + + ngOnDestroy(): void { + this.destroy$.next(true); + this.destroy$.complete(); + } + + override ngAfterContentInit(): void { + super.ngAfterContentInit(); + this.buildFormArray(); + } + + buildFormArray() { + const values: string[] = this.control?.value ?? ['']; + values.forEach((value) => this.addControl(value)); + } + + addControl(value = '') { + const lastUnNumber = this.formArray.at(-1); + + if (this.formArray.length > 0 && (lastUnNumber.invalid || !lastUnNumber.value)) { + // If the parent control or lastUnNumber control isn't already invalid set additional errors + if (!this.control?.invalid && !lastUnNumber.invalid) { + lastUnNumber.setErrors({ required: true }); + } + + // Mark as touched to show errors + this.formArray.markAllAsTouched(); + + return; + } + + this.formArray.push( + new CustomFormControl({ type: FormNodeTypes.CONTROL, name: 'UN number' }, value, [ + Validators.minLength(1), + Validators.maxLength(1500), + ]) + ); + } + + removeControl(index: number) { + this.formArray.removeAt(index); + } } diff --git a/src/app/forms/custom-sections/adr-tank-statement-un-number-view/adr-tank-statement-un-number-view.component.spec.ts b/src/app/forms/custom-sections/adr-tank-statement-un-number-view/adr-tank-statement-un-number-view.component.spec.ts index 345ab0107f..98d6419531 100644 --- a/src/app/forms/custom-sections/adr-tank-statement-un-number-view/adr-tank-statement-un-number-view.component.spec.ts +++ b/src/app/forms/custom-sections/adr-tank-statement-un-number-view/adr-tank-statement-un-number-view.component.spec.ts @@ -9,34 +9,33 @@ import { State, initialAppState } from '@store/index'; import { AdrTankStatementUnNumberViewComponent } from './adr-tank-statement-un-number-view.component'; describe('AdrTankStatementUnNumberViewComponent', () => { - let component: AdrTankStatementUnNumberViewComponent; - let fixture: ComponentFixture; + let component: AdrTankStatementUnNumberViewComponent; + let fixture: ComponentFixture; - const control = new CustomFormControl({ - name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo', - label: 'UN Number', - type: FormNodeTypes.CONTROL, - value: ['UN number 1'], - }); + const control = new CustomFormControl({ + name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo', + label: 'UN Number', + type: FormNodeTypes.CONTROL, + value: ['UN number 1'], + }); - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [DynamicFormsModule, SharedModule, FormsModule], - declarations: [AdrTankStatementUnNumberViewComponent], - providers: [ - provideMockStore({ initialState: initialAppState }), - { provide: NG_VALUE_ACCESSOR, useExisting: AdrTankStatementUnNumberViewComponent, multi: true }, - { provide: NgControl, useValue: { control } }, - ], - }) - .compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [DynamicFormsModule, SharedModule, FormsModule], + declarations: [AdrTankStatementUnNumberViewComponent], + providers: [ + provideMockStore({ initialState: initialAppState }), + { provide: NG_VALUE_ACCESSOR, useExisting: AdrTankStatementUnNumberViewComponent, multi: true }, + { provide: NgControl, useValue: { control } }, + ], + }).compileComponents(); - fixture = TestBed.createComponent(AdrTankStatementUnNumberViewComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(AdrTankStatementUnNumberViewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/custom-sections/adr-tank-statement-un-number-view/adr-tank-statement-un-number-view.component.ts b/src/app/forms/custom-sections/adr-tank-statement-un-number-view/adr-tank-statement-un-number-view.component.ts index 4d0e72691f..33b58ba9fe 100644 --- a/src/app/forms/custom-sections/adr-tank-statement-un-number-view/adr-tank-statement-un-number-view.component.ts +++ b/src/app/forms/custom-sections/adr-tank-statement-un-number-view/adr-tank-statement-un-number-view.component.ts @@ -2,8 +2,8 @@ import { Component } from '@angular/core'; import { BaseControlComponent } from '@forms/components/base-control/base-control.component'; @Component({ - selector: 'app-adr-tank-statement-un-number-view', - templateUrl: './adr-tank-statement-un-number-view.component.html', - styleUrls: ['./adr-tank-statement-un-number-view.component.scss'], + selector: 'app-adr-tank-statement-un-number-view', + templateUrl: './adr-tank-statement-un-number-view.component.html', + styleUrls: ['./adr-tank-statement-un-number-view.component.scss'], }) export class AdrTankStatementUnNumberViewComponent extends BaseControlComponent {} diff --git a/src/app/forms/custom-sections/adr/adr.component.spec.ts b/src/app/forms/custom-sections/adr/adr.component.spec.ts index 691eaab492..88ece1f511 100644 --- a/src/app/forms/custom-sections/adr/adr.component.spec.ts +++ b/src/app/forms/custom-sections/adr/adr.component.spec.ts @@ -11,90 +11,97 @@ import { initialAppState } from '@store/index'; import { AdrComponent } from './adr.component'; describe('AdrComponent', () => { - let component: AdrComponent; - let fixture: ComponentFixture; + let component: AdrComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AdrComponent], - imports: [DynamicFormsModule, FormsModule, ReactiveFormsModule, HttpClientTestingModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - { provide: TechnicalRecordService, useValue: { updateEditingTechRecord: jest.fn() } }, - { provide: AdrService, useValue: { carriesDangerousGoods: jest.fn(), determineTankStatementSelect: jest.fn() } }, - ], - }).compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AdrComponent], + imports: [DynamicFormsModule, FormsModule, ReactiveFormsModule, HttpClientTestingModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + { provide: TechnicalRecordService, useValue: { updateEditingTechRecord: jest.fn() } }, + { + provide: AdrService, + useValue: { carriesDangerousGoods: jest.fn(), determineTankStatementSelect: jest.fn() }, + }, + ], + }).compileComponents(); - fixture = TestBed.createComponent(AdrComponent); - component = fixture.componentInstance; - component.techRecord = createMockHgv(1234); - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(AdrComponent); + component = fixture.componentInstance; + component.techRecord = createMockHgv(1234); + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - describe('ngOnInit', () => { - it('should populate the dangerous goods property', () => { - const spy = jest.spyOn(component.adrService, 'carriesDangerousGoods'); - component.ngOnInit(); - expect(spy).toHaveBeenCalled(); - }); - }); + describe('ngOnInit', () => { + it('should populate the dangerous goods property', () => { + const spy = jest.spyOn(component.adrService, 'carriesDangerousGoods'); + component.ngOnInit(); + expect(spy).toHaveBeenCalled(); + }); + }); - describe('handleFormChange', () => { - it('the form should be updated', () => { - const testData = { test: 11 }; - const spy = jest.spyOn(component.form, 'patchValue'); - component.handleFormChange(testData); - expect(spy).toHaveBeenCalled(); - }); + describe('handleFormChange', () => { + it('the form should be updated', () => { + const testData = { test: 11 }; + const spy = jest.spyOn(component.form, 'patchValue'); + component.handleFormChange(testData); + expect(spy).toHaveBeenCalled(); + }); - it('should not update the form if the event is null', () => { - const testData = null as unknown as Record; - const spy = jest.spyOn(component.form, 'patchValue'); - component.handleFormChange(testData); - expect(spy).not.toHaveBeenCalled(); - }); + it('should not update the form if the event is null', () => { + const testData = null as unknown as Record; + const spy = jest.spyOn(component.form, 'patchValue'); + component.handleFormChange(testData); + expect(spy).not.toHaveBeenCalled(); + }); - it('should not update the form if the techRecord is null', () => { - component.techRecord = null as unknown as TechRecordType<'hgv' | 'lgv' | 'trl'>; - const testData = { test: 11 }; - const spy = jest.spyOn(component.form, 'patchValue'); - component.handleFormChange(testData); - expect(spy).not.toHaveBeenCalled(); - }); - }); + it('should not update the form if the techRecord is null', () => { + component.techRecord = null as unknown as TechRecordType<'hgv' | 'lgv' | 'trl'>; + const testData = { test: 11 }; + const spy = jest.spyOn(component.form, 'patchValue'); + component.handleFormChange(testData); + expect(spy).not.toHaveBeenCalled(); + }); + }); - describe('adr documentation methods', () => { - it('should return false if I do not have a document id', () => { - component.techRecord = { } as unknown as TechRecordType<'hgv' | 'lgv' | 'trl'>; - const res = component.hasAdrDocumentation(); - expect(res).toBeFalsy(); - }); + describe('adr documentation methods', () => { + it('should return false if I do not have a document id', () => { + component.techRecord = {} as unknown as TechRecordType<'hgv' | 'lgv' | 'trl'>; + const res = component.hasAdrDocumentation(); + expect(res).toBeFalsy(); + }); - it('should return true if I do have a document id', () => { - component.techRecord = { techRecord_adrDetails_documentId: '1234' } as unknown as TechRecordType<'hgv' | 'lgv' | 'trl'>; - const res = component.hasAdrDocumentation(); - expect(res).toBeTruthy(); - }); + it('should return true if I do have a document id', () => { + component.techRecord = { techRecord_adrDetails_documentId: '1234' } as unknown as TechRecordType< + 'hgv' | 'lgv' | 'trl' + >; + const res = component.hasAdrDocumentation(); + expect(res).toBeTruthy(); + }); - it('should return a map with filename in', () => { - const map = new Map([['adrDocumentId', 'filename']]); - component.techRecord.techRecord_adrDetails_documentId = 'filename'; - expect(component.documentParams).toStrictEqual(map); - }); + it('should return a map with filename in', () => { + const map = new Map([['adrDocumentId', 'filename']]); + component.techRecord.techRecord_adrDetails_documentId = 'filename'; + expect(component.documentParams).toStrictEqual(map); + }); - it('should return the filename', () => { - component.techRecord.techRecord_adrDetails_documentId = 'filename'; - expect(component.fileName).toBe('filename'); - }); + it('should return the filename', () => { + component.techRecord.techRecord_adrDetails_documentId = 'filename'; + expect(component.fileName).toBe('filename'); + }); - it('should error if no filename', () => { - component.techRecord.techRecord_adrDetails_documentId = undefined; - // eslint-disable-next-line no-unused-expressions, @typescript-eslint/no-unused-expressions - expect(() => { component.fileName; }).toThrow('Could not find ADR Documentation'); - }); - }); + it('should error if no filename', () => { + component.techRecord.techRecord_adrDetails_documentId = undefined; + // eslint-disable-next-line no-unused-expressions, @typescript-eslint/no-unused-expressions + expect(() => { + component.fileName; + }).toThrow('Could not find ADR Documentation'); + }); + }); }); diff --git a/src/app/forms/custom-sections/adr/adr.component.ts b/src/app/forms/custom-sections/adr/adr.component.ts index cc6868db46..18c1101dce 100644 --- a/src/app/forms/custom-sections/adr/adr.component.ts +++ b/src/app/forms/custom-sections/adr/adr.component.ts @@ -1,9 +1,4 @@ -import { - Component, - Input, - OnDestroy, - OnInit, -} from '@angular/core'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; import { TechRecordType as TechRecordTypeVerb } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; @@ -17,67 +12,71 @@ import { AdrService } from '@services/adr/adr.service'; import { ReplaySubject, skipWhile, takeUntil } from 'rxjs'; @Component({ - selector: 'app-adr', - templateUrl: './adr.component.html', - styleUrls: ['./adr.component.scss'], + selector: 'app-adr', + templateUrl: './adr.component.html', + styleUrls: ['./adr.component.scss'], }) export class AdrComponent implements OnInit, OnDestroy { - @Input() techRecord!: TechRecordType<'hgv' | 'lgv' | 'trl'>; - @Input() isEditing = false; - @Input() isReviewScreen = false; + @Input() techRecord!: TechRecordType<'hgv' | 'lgv' | 'trl'>; + @Input() isEditing = false; + @Input() isReviewScreen = false; - template!: FormNode; - form!: CustomFormGroup; - destroy$ = new ReplaySubject(1); + template!: FormNode; + form!: CustomFormGroup; + destroy$ = new ReplaySubject(1); - constructor( - private dfs: DynamicFormService, - private technicalRecordService: TechnicalRecordService, - private globalErrorService: GlobalErrorService, - public adrService: AdrService, - ) { } + constructor( + private dfs: DynamicFormService, + private technicalRecordService: TechnicalRecordService, + private globalErrorService: GlobalErrorService, + public adrService: AdrService + ) {} - ngOnInit(): void { - this.template = this.isReviewScreen ? AdrSummaryTemplate : AdrTemplate; - this.form = this.dfs.createForm(this.template, this.techRecord) as CustomFormGroup; - this.techRecord.techRecord_adrDetails_dangerousGoods = this.adrService.carriesDangerousGoods(this.techRecord); - if (this.techRecord.techRecord_adrDetails_dangerousGoods && !this.isReviewScreen) { - this.techRecord.techRecord_adrDetails_tank_tankDetails_tankStatement_select = this.adrService.determineTankStatementSelect(this.techRecord); - } - this.handleSubmit(); - } + ngOnInit(): void { + this.template = this.isReviewScreen ? AdrSummaryTemplate : AdrTemplate; + this.form = this.dfs.createForm(this.template, this.techRecord) as CustomFormGroup; + this.techRecord.techRecord_adrDetails_dangerousGoods = this.adrService.carriesDangerousGoods(this.techRecord); + if (this.techRecord.techRecord_adrDetails_dangerousGoods && !this.isReviewScreen) { + this.techRecord.techRecord_adrDetails_tank_tankDetails_tankStatement_select = + this.adrService.determineTankStatementSelect(this.techRecord); + } + this.handleSubmit(); + } - ngOnDestroy(): void { - this.destroy$.next(true); - this.destroy$.complete(); - } + ngOnDestroy(): void { + this.destroy$.next(true); + this.destroy$.complete(); + } - handleFormChange(event: Record) { - if (event == null) return; - if (this.techRecord == null) return; + handleFormChange(event: Record) { + if (event == null) return; + if (this.techRecord == null) return; - this.form.patchValue(event); - this.technicalRecordService.updateEditingTechRecord({ ...this.techRecord, ...event } as TechRecordTypeVerb<'put'>); - } + this.form.patchValue(event); + this.technicalRecordService.updateEditingTechRecord({ ...this.techRecord, ...event } as TechRecordTypeVerb<'put'>); + } - get documentParams(): Map { - return new Map([['adrDocumentId', this.fileName]]); - } + get documentParams(): Map { + return new Map([['adrDocumentId', this.fileName]]); + } - get fileName(): string { - if (this.hasAdrDocumentation()) { - return this.techRecord.techRecord_adrDetails_documentId ?? ''; - } - throw new Error('Could not find ADR Documentation.'); - } + get fileName(): string { + if (this.hasAdrDocumentation()) { + return this.techRecord.techRecord_adrDetails_documentId ?? ''; + } + throw new Error('Could not find ADR Documentation.'); + } - hasAdrDocumentation(): boolean { - return !!this.techRecord.techRecord_adrDetails_documentId && !this.isEditing; - } + hasAdrDocumentation(): boolean { + return !!this.techRecord.techRecord_adrDetails_documentId && !this.isEditing; + } - handleSubmit() { - this.globalErrorService.errors$ - .pipe(takeUntil(this.destroy$), skipWhile((errors) => errors.length === 0)) - .subscribe(() => this.globalErrorService.focusAllControls()); - } + handleSubmit() { + this.globalErrorService.errors$ + .pipe( + takeUntil(this.destroy$), + skipWhile((errors) => errors.length === 0) + ) + .subscribe(() => this.globalErrorService.focusAllControls()); + } } diff --git a/src/app/forms/custom-sections/approval-type/approval-type.component.ts b/src/app/forms/custom-sections/approval-type/approval-type.component.ts index aaf62b990b..1a00f49920 100644 --- a/src/app/forms/custom-sections/approval-type/approval-type.component.ts +++ b/src/app/forms/custom-sections/approval-type/approval-type.component.ts @@ -1,6 +1,4 @@ -import { - Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, -} from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core'; import { FormControl } from '@angular/forms'; import { TechRecord } from '@api/vehicle'; import { ApprovalType as approvalType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/approvalType.enum.js'; @@ -8,7 +6,11 @@ import { ApprovalType as approvalTypeHgvOrPsv } from '@dvsa/cvs-type-definitions import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; import { - CustomFormGroup, FormNode, FormNodeEditTypes, FormNodeViewTypes, FormNodeWidth, + CustomFormGroup, + FormNode, + FormNodeEditTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; import { HgvAndTrlTypeApprovalTemplate } from '@forms/templates/general/approval-type.template'; import { PsvTypeApprovalTemplate } from '@forms/templates/psv/psv-approval-type.template'; @@ -17,84 +19,88 @@ import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { Subject, debounceTime, takeUntil } from 'rxjs'; @Component({ - selector: 'app-approval-type[techRecord]', - templateUrl: './approval-type.component.html', - styleUrls: ['./approval-type.component.scss'], + selector: 'app-approval-type[techRecord]', + templateUrl: './approval-type.component.html', + styleUrls: ['./approval-type.component.scss'], }) export class ApprovalTypeComponent implements OnInit, OnChanges, OnDestroy { - @Input() techRecord!: TechRecordType<'hgv' | 'psv' | 'trl'>; - @Input() isEditing = false; - @Output() formChange = new EventEmitter(); - @Output() approvalTypeNumberChange = new EventEmitter(); + @Input() techRecord!: TechRecordType<'hgv' | 'psv' | 'trl'>; + @Input() isEditing = false; + @Output() formChange = new EventEmitter(); + @Output() approvalTypeNumberChange = new EventEmitter(); - public form!: CustomFormGroup; - private destroy$ = new Subject(); - protected chosenApprovalType: string | undefined; - protected approvalTypeChange = false; - protected approvalType: typeof approvalTypeHgvOrPsv | typeof approvalType = approvalType; - formControls: { [key: string]: FormControl } = {}; + public form!: CustomFormGroup; + private destroy$ = new Subject(); + protected chosenApprovalType: string | undefined; + protected approvalTypeChange = false; + protected approvalType: typeof approvalTypeHgvOrPsv | typeof approvalType = approvalType; + formControls: { [key: string]: FormControl } = {}; - constructor(private dfs: DynamicFormService) {} + constructor(private dfs: DynamicFormService) {} - ngOnInit() { - this.approvalType = this.techRecord.techRecord_vehicleType === 'psv' - || this.techRecord.techRecord_vehicleType === 'hgv' ? approvalTypeHgvOrPsv : approvalType; - this.form = this.dfs.createForm( - this.techRecord.techRecord_vehicleType === 'psv' ? PsvTypeApprovalTemplate : HgvAndTrlTypeApprovalTemplate, - this.techRecord, - ) as CustomFormGroup; - this.form.cleanValueChanges.pipe(debounceTime(400), takeUntil(this.destroy$)).subscribe((e) => this.formChange.emit(e)); - Object.keys(this.form.controls).forEach((key) => { - this.formControls[`${key}`] = this.form.get(key) as FormControl; - }); - } + ngOnInit() { + this.approvalType = + this.techRecord.techRecord_vehicleType === 'psv' || this.techRecord.techRecord_vehicleType === 'hgv' + ? approvalTypeHgvOrPsv + : approvalType; + this.form = this.dfs.createForm( + this.techRecord.techRecord_vehicleType === 'psv' ? PsvTypeApprovalTemplate : HgvAndTrlTypeApprovalTemplate, + this.techRecord + ) as CustomFormGroup; + this.form.cleanValueChanges + .pipe(debounceTime(400), takeUntil(this.destroy$)) + .subscribe((e) => this.formChange.emit(e)); + Object.keys(this.form.controls).forEach((key) => { + this.formControls[`${key}`] = this.form.get(key) as FormControl; + }); + } - ngOnChanges(changes: SimpleChanges): void { - const { techRecord } = changes; - if (this.form && techRecord?.currentValue && techRecord.currentValue !== techRecord.previousValue) { - const { currentValue } = techRecord; + ngOnChanges(changes: SimpleChanges): void { + const { techRecord } = changes; + if (this.form && techRecord?.currentValue && techRecord.currentValue !== techRecord.previousValue) { + const { currentValue } = techRecord; - this.form.patchValue(currentValue, { emitEvent: false }); - this.chosenApprovalType = currentValue.techRecord_approvalType ? currentValue.techRecord_approvalType : ''; - techRecord.currentValue.techRecord_coifDate = currentValue.techRecord_coifDate - ? currentValue.techRecord_coifDate.split('T')[0] - : ''; - } - } + this.form.patchValue(currentValue, { emitEvent: false }); + this.chosenApprovalType = currentValue.techRecord_approvalType ? currentValue.techRecord_approvalType : ''; + techRecord.currentValue.techRecord_coifDate = currentValue.techRecord_coifDate + ? currentValue.techRecord_coifDate.split('T')[0] + : ''; + } + } - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } - get template(): FormNode { - switch (this.techRecord.techRecord_vehicleType) { - case VehicleTypes.PSV: - return PsvTypeApprovalTemplate; - case VehicleTypes.HGV: - return HgvAndTrlTypeApprovalTemplate; - case VehicleTypes.TRL: - return HgvAndTrlTypeApprovalTemplate; - default: - throw Error('Incorrect vehicle type!'); - } - } + get template(): FormNode { + switch (this.techRecord.techRecord_vehicleType) { + case VehicleTypes.PSV: + return PsvTypeApprovalTemplate; + case VehicleTypes.HGV: + return HgvAndTrlTypeApprovalTemplate; + case VehicleTypes.TRL: + return HgvAndTrlTypeApprovalTemplate; + default: + throw Error('Incorrect vehicle type!'); + } + } - get editTypes(): typeof FormNodeEditTypes { - return FormNodeEditTypes; - } + get editTypes(): typeof FormNodeEditTypes { + return FormNodeEditTypes; + } - get widths(): typeof FormNodeWidth { - return FormNodeWidth; - } + get widths(): typeof FormNodeWidth { + return FormNodeWidth; + } - get isPsv(): boolean { - return this.techRecord.techRecord_vehicleType === VehicleTypes.PSV; - } + get isPsv(): boolean { + return this.techRecord.techRecord_vehicleType === VehicleTypes.PSV; + } - get formNodeViewTypes(): typeof FormNodeViewTypes { - return FormNodeViewTypes; - } - protected readonly TechRecord = TechRecord; - protected readonly getOptionsFromEnum = getOptionsFromEnum; + get formNodeViewTypes(): typeof FormNodeViewTypes { + return FormNodeViewTypes; + } + protected readonly TechRecord = TechRecord; + protected readonly getOptionsFromEnum = getOptionsFromEnum; } diff --git a/src/app/forms/custom-sections/approval-type/approval-type.directive.ts b/src/app/forms/custom-sections/approval-type/approval-type.directive.ts index 52d62cea8f..18de794880 100644 --- a/src/app/forms/custom-sections/approval-type/approval-type.directive.ts +++ b/src/app/forms/custom-sections/approval-type/approval-type.directive.ts @@ -1,20 +1,18 @@ -import { - Directive, ElementRef, HostListener, Input, -} from '@angular/core'; +import { Directive, ElementRef, HostListener, Input } from '@angular/core'; @Directive({ - selector: '[appFocusOnCharacterLimit]', + selector: '[appFocusOnCharacterLimit]', }) export class FocusOnCharacterLimitDirective { - @Input() nextElement: ElementRef | undefined; - @Input() characterLimit = 0; + @Input() nextElement: ElementRef | undefined; + @Input() characterLimit = 0; - constructor(private el: ElementRef) {} + constructor(private el: ElementRef) {} - @HostListener('input', ['$event.target.value']) - onInput(value: string): void { - if (value.length >= this.characterLimit && this.nextElement) { - this.nextElement.nativeElement.focus(); - } - } + @HostListener('input', ['$event.target.value']) + onInput(value: string): void { + if (value.length >= this.characterLimit && this.nextElement) { + this.nextElement.nativeElement.focus(); + } + } } diff --git a/src/app/forms/custom-sections/body/body.component.spec.ts b/src/app/forms/custom-sections/body/body.component.spec.ts index 56912ce914..ebd9fcd41f 100644 --- a/src/app/forms/custom-sections/body/body.component.spec.ts +++ b/src/app/forms/custom-sections/body/body.component.spec.ts @@ -24,241 +24,246 @@ import { lastValueFrom, of } from 'rxjs'; import { BodyComponent } from './body.component'; describe('BodyComponent', () => { - let component: BodyComponent; - let fixture: ComponentFixture; - let store: MockStore; - let multiOptionsService: MultiOptionsService; - let dynamicFormService: DynamicFormService; - let referenceDataService: ReferenceDataService; + let component: BodyComponent; + let fixture: ComponentFixture; + let store: MockStore; + let multiOptionsService: MultiOptionsService; + let dynamicFormService: DynamicFormService; + let referenceDataService: ReferenceDataService; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [BodyComponent], - imports: [DynamicFormsModule, FormsModule, HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - ReferenceDataService, - { provide: UserService, useValue: {} }, - { provide: MultiOptionsService, useValue: { getOptions: jest.fn(), loadOptions: jest.fn() } }, - ], - }).compileComponents(); - store = TestBed.inject(MockStore); - multiOptionsService = TestBed.inject(MultiOptionsService); - dynamicFormService = TestBed.inject(DynamicFormService); - referenceDataService = TestBed.inject(ReferenceDataService); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BodyComponent], + imports: [DynamicFormsModule, FormsModule, HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + ReferenceDataService, + { provide: UserService, useValue: {} }, + { provide: MultiOptionsService, useValue: { getOptions: jest.fn(), loadOptions: jest.fn() } }, + ], + }).compileComponents(); + store = TestBed.inject(MockStore); + multiOptionsService = TestBed.inject(MultiOptionsService); + dynamicFormService = TestBed.inject(DynamicFormService); + referenceDataService = TestBed.inject(ReferenceDataService); + }); - beforeEach(() => { - fixture = TestBed.createComponent(BodyComponent); - component = fixture.componentInstance; - component.techRecord = { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_vehicleType: VehicleTypes.PSV, - techRecord_brakes_dtpNumber: '000000', - techRecord_bodyModel: 'model', - techRecord_bodyType_description: 'type', - techRecord_chassisMake: 'chassisType', - } as unknown as TechRecordType<'psv'>; - fixture.detectChanges(); - }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(BodyComponent); + component = fixture.componentInstance; + component.techRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_vehicleType: VehicleTypes.PSV, + techRecord_brakes_dtpNumber: '000000', + techRecord_bodyModel: 'model', + techRecord_bodyType_description: 'type', + techRecord_chassisMake: 'chassisType', + } as unknown as TechRecordType<'psv'>; + fixture.detectChanges(); + }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - describe('The DTpNumber value on this.form', () => { - it('should match the corresponding values on vehicleTechRecord', () => { - expect((component.techRecord as TechRecordType<'psv'>).techRecord_brakes_dtpNumber).toStrictEqual( - component.form.value.techRecord_brakes_dtpNumber, - ); - }); - }); - describe('The bodyModel value on this.form', () => { - it('should match the corresponding values on vehicleTechRecord', () => { - expect((component.techRecord as TechRecordType<'psv'>).techRecord_bodyModel).toStrictEqual(component.form.value.techRecord_bodyModel); - }); - }); - describe('The bodyType value on this.form', () => { - it('should match the corresponding values on vehicleTechRecord', () => { - expect((component.techRecord as TechRecordType<'psv'>).techRecord_bodyType_description).toStrictEqual( - component.form.controls['techRecord_bodyType_description']?.value, - ); - }); - }); - describe('The chassisMake value on this.form', () => { - it('should match the corresponding values on vehicleTechRecord', () => { - expect((component.techRecord as TechRecordType<'psv'>).techRecord_chassisMake).toStrictEqual( - component.form.controls['techRecord_chassisMake']?.value, - ); - }); - }); - describe('updateArticulatedHgvVehicleBodyType', () => { - it('should dispatch updateEditingTechRecord if vehicle is hgv and articulated', () => { - const mockRecord = { - techRecord_vehicleType: 'hgv', - techRecord_vehicleConfiguration: 'articulated', - techRecord_bodyType_description: '', - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_brakes_dtpNumber: '000000', - techRecord_bodyModel: 'model', - techRecord_chassisMake: 'chassisType', - } as unknown as V3TechRecordModel; - component.techRecord = mockRecord; + describe('The DTpNumber value on this.form', () => { + it('should match the corresponding values on vehicleTechRecord', () => { + expect((component.techRecord as TechRecordType<'psv'>).techRecord_brakes_dtpNumber).toStrictEqual( + component.form.value.techRecord_brakes_dtpNumber + ); + }); + }); + describe('The bodyModel value on this.form', () => { + it('should match the corresponding values on vehicleTechRecord', () => { + expect((component.techRecord as TechRecordType<'psv'>).techRecord_bodyModel).toStrictEqual( + component.form.value.techRecord_bodyModel + ); + }); + }); + describe('The bodyType value on this.form', () => { + it('should match the corresponding values on vehicleTechRecord', () => { + expect((component.techRecord as TechRecordType<'psv'>).techRecord_bodyType_description).toStrictEqual( + component.form.controls['techRecord_bodyType_description']?.value + ); + }); + }); + describe('The chassisMake value on this.form', () => { + it('should match the corresponding values on vehicleTechRecord', () => { + expect((component.techRecord as TechRecordType<'psv'>).techRecord_chassisMake).toStrictEqual( + component.form.controls['techRecord_chassisMake']?.value + ); + }); + }); + describe('updateArticulatedHgvVehicleBodyType', () => { + it('should dispatch updateEditingTechRecord if vehicle is hgv and articulated', () => { + const mockRecord = { + techRecord_vehicleType: 'hgv', + techRecord_vehicleConfiguration: 'articulated', + techRecord_bodyType_description: '', + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_brakes_dtpNumber: '000000', + techRecord_bodyModel: 'model', + techRecord_chassisMake: 'chassisType', + } as unknown as V3TechRecordModel; + component.techRecord = mockRecord; - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.updateHgvVehicleBodyType(mockRecord as TechRecordType<'hgv'>); - expect(dispatchSpy).toHaveBeenCalled(); - expect(dispatchSpy).toHaveBeenCalledWith(expect.objectContaining({ - vehicleTechRecord: { - createdTimestamp: 'bar', - systemNumber: 'foo', - techRecord_bodyModel: 'model', - techRecord_bodyType_description: 'articulated', - techRecord_brakes_dtpNumber: '000000', - techRecord_chassisMake: 'chassisType', - techRecord_vehicleConfiguration: 'articulated', - techRecord_vehicleType: 'hgv', - techRecord_bodyType_code: 'a', - vin: 'testVin', - }, - })); - }); - it('should not dispatch updateEditingTechRecord if vehicle is hgv and rigid', () => { - const mockRecord = { - techRecord_vehicleType: 'hgv', - techRecord_vehicleConfiguration: 'rigid', - techRecord_bodyType_description: '', - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_brakes_dtpNumber: '000000', - techRecord_bodyModel: 'model', - techRecord_chassisMake: 'chassisType', - } as unknown as V3TechRecordModel; + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.updateHgvVehicleBodyType(mockRecord as TechRecordType<'hgv'>); + expect(dispatchSpy).toHaveBeenCalled(); + expect(dispatchSpy).toHaveBeenCalledWith( + expect.objectContaining({ + vehicleTechRecord: { + createdTimestamp: 'bar', + systemNumber: 'foo', + techRecord_bodyModel: 'model', + techRecord_bodyType_description: 'articulated', + techRecord_brakes_dtpNumber: '000000', + techRecord_chassisMake: 'chassisType', + techRecord_vehicleConfiguration: 'articulated', + techRecord_vehicleType: 'hgv', + techRecord_bodyType_code: 'a', + vin: 'testVin', + }, + }) + ); + }); + it('should not dispatch updateEditingTechRecord if vehicle is hgv and rigid', () => { + const mockRecord = { + techRecord_vehicleType: 'hgv', + techRecord_vehicleConfiguration: 'rigid', + techRecord_bodyType_description: '', + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_brakes_dtpNumber: '000000', + techRecord_bodyModel: 'model', + techRecord_chassisMake: 'chassisType', + } as unknown as V3TechRecordModel; - component.techRecord = mockRecord; + component.techRecord = mockRecord; - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.updateHgvVehicleBodyType(mockRecord as TechRecordType<'hgv'>); - expect(dispatchSpy).not.toHaveBeenCalled(); - }); - }); + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.updateHgvVehicleBodyType(mockRecord as TechRecordType<'hgv'>); + expect(dispatchSpy).not.toHaveBeenCalled(); + }); + }); - describe('loadOptions', () => { + describe('loadOptions', () => { + it('should trigger the loading of HGV make ref data when viewing a HGV', () => { + const spy = jest.spyOn(multiOptionsService, 'loadOptions'); + component.disableLoadOptions = false; + component.techRecord = createMockHgv(123); + component.loadOptions(); + expect(spy).toHaveBeenCalledWith(ReferenceDataResourceType.HgvMake); + }); - it('should trigger the loading of HGV make ref data when viewing a HGV', () => { - const spy = jest.spyOn(multiOptionsService, 'loadOptions'); - component.disableLoadOptions = false; - component.techRecord = createMockHgv(123); - component.loadOptions(); - expect(spy).toHaveBeenCalledWith(ReferenceDataResourceType.HgvMake); - }); + it('should trigger the loading of PSV make ref data when viewing a PSV', () => { + const spy = jest.spyOn(multiOptionsService, 'loadOptions'); + component.disableLoadOptions = false; + component.techRecord = createMockPsv(123); + component.loadOptions(); + expect(spy).toHaveBeenCalledWith(ReferenceDataResourceType.PsvMake); + }); - it('should trigger the loading of PSV make ref data when viewing a PSV', () => { - const spy = jest.spyOn(multiOptionsService, 'loadOptions'); - component.disableLoadOptions = false; - component.techRecord = createMockPsv(123); - component.loadOptions(); - expect(spy).toHaveBeenCalledWith(ReferenceDataResourceType.PsvMake); - }); + it('should trigger the loading of TRL make ref data when viewing a TRL', () => { + const spy = jest.spyOn(multiOptionsService, 'loadOptions'); + component.disableLoadOptions = false; + component.techRecord = createMockTrl(123); + component.loadOptions(); + expect(spy).toHaveBeenCalledWith(ReferenceDataResourceType.TrlMake); + }); + }); - it('should trigger the loading of TRL make ref data when viewing a TRL', () => { - const spy = jest.spyOn(multiOptionsService, 'loadOptions'); - component.disableLoadOptions = false; - component.techRecord = createMockTrl(123); - component.loadOptions(); - expect(spy).toHaveBeenCalledWith(ReferenceDataResourceType.TrlMake); - }); - }); + describe('ngOnInit', () => { + it('should use the PSV body type template to create the form when the vehicle type of the provided tech record is PSV', () => { + const techRecord = createMockPsv(123); + const dfsSpy = jest.spyOn(dynamicFormService, 'createForm'); + component.techRecord = techRecord; + component.ngOnInit(); + expect(dfsSpy).toHaveBeenCalledWith(PsvBodyTemplate, techRecord); + }); - describe('ngOnInit', () => { - it('should use the PSV body type template to create the form when the vehicle type of the provided tech record is PSV', () => { - const techRecord = createMockPsv(123); - const dfsSpy = jest.spyOn(dynamicFormService, 'createForm'); - component.techRecord = techRecord; - component.ngOnInit(); - expect(dfsSpy).toHaveBeenCalledWith(PsvBodyTemplate, techRecord); - }); + it('should use the HGV body type template to create the form when the vehicle type of the provided tech record is HGV', () => { + const techRecord = createMockHgv(123); + const dfsSpy = jest.spyOn(dynamicFormService, 'createForm'); + component.techRecord = techRecord; + component.ngOnInit(); + expect(dfsSpy).toHaveBeenCalledWith(HgvAndTrlBodyTemplate, techRecord); + }); - it('should use the HGV body type template to create the form when the vehicle type of the provided tech record is HGV', () => { - const techRecord = createMockHgv(123); - const dfsSpy = jest.spyOn(dynamicFormService, 'createForm'); - component.techRecord = techRecord; - component.ngOnInit(); - expect(dfsSpy).toHaveBeenCalledWith(HgvAndTrlBodyTemplate, techRecord); - }); + it('should call load options to fetch the ref data required for displaying the vehicle type', () => { + const loadOptionsSpy = jest.spyOn(component, 'loadOptions'); + component.ngOnInit(); + expect(loadOptionsSpy).toHaveBeenCalled(); + }); + }); - it('should call load options to fetch the ref data required for displaying the vehicle type', () => { - const loadOptionsSpy = jest.spyOn(component, 'loadOptions'); - component.ngOnInit(); - expect(loadOptionsSpy).toHaveBeenCalled(); - }); - }); + describe('ngOnChanges', () => { + it('should do nothing if the tech record input has not changed', () => { + const formSpy = jest.spyOn(component.form, 'patchValue'); + component.ngOnChanges({} as SimpleChanges); + expect(formSpy).not.toHaveBeenCalled(); + }); - describe('ngOnChanges', () => { - it('should do nothing if the tech record input has not changed', () => { - const formSpy = jest.spyOn(component.form, 'patchValue'); - component.ngOnChanges({} as SimpleChanges); - expect(formSpy).not.toHaveBeenCalled(); - }); + it('should patch the form with the current tech record when this changes', () => { + const formSpy = jest.spyOn(component.form, 'patchValue'); + component.ngOnChanges({ techRecord: { currentValue: {}, previousValue: null } } as unknown as SimpleChanges); + expect(formSpy).toHaveBeenCalled(); + }); + }); - it('should patch the form with the current tech record when this changes', () => { - const formSpy = jest.spyOn(component.form, 'patchValue'); - component.ngOnChanges({ techRecord: { currentValue: {}, previousValue: null } } as unknown as SimpleChanges); - expect(formSpy).toHaveBeenCalled(); - }); - }); + describe('editTypes', () => { + it('should return the form node edit types enum', () => { + expect(component.editTypes).toBe(FormNodeEditTypes); + }); + }); - describe('editTypes', () => { - it('should return the form node edit types enum', () => { - expect(component.editTypes).toBe(FormNodeEditTypes); - }); - }); + describe('widths', () => { + it('should return the form node width enum', () => { + expect(component.widths).toBe(FormNodeWidth); + }); + }); - describe('widths', () => { - it('should return the form node width enum', () => { - expect(component.widths).toBe(FormNodeWidth); - }); - }); + describe('bodyMakes', () => { + it('should return an observable which emits PSV body make ref data when the tech record is a PSV', async () => { + const mockData = [{ label: 'PSV', value: 'psv' }]; + const spy = jest.spyOn(multiOptionsService, 'getOptions').mockReturnValue(of(mockData)); + component.techRecord = createMockPsv(123); + await expect(lastValueFrom(component.bodyMakes$)).resolves.toEqual(mockData); + expect(spy).toHaveBeenCalledWith(ReferenceDataResourceType.PsvMake); + }); - describe('bodyMakes', () => { - it('should return an observable which emits PSV body make ref data when the tech record is a PSV', async () => { - const mockData = [{ label: 'PSV', value: 'psv' }]; - const spy = jest.spyOn(multiOptionsService, 'getOptions').mockReturnValue(of(mockData)); - component.techRecord = createMockPsv(123); - await expect(lastValueFrom(component.bodyMakes$)).resolves.toEqual(mockData); - expect(spy).toHaveBeenCalledWith(ReferenceDataResourceType.PsvMake); - }); + it('should return an observable which emits HGV body make ref data when the tech record is a HGV', async () => { + const mockData = [{ label: 'HGV', value: 'HGV' }]; + const spy = jest.spyOn(multiOptionsService, 'getOptions').mockReturnValue(of(mockData)); + component.techRecord = createMockHgv(123); + await expect(lastValueFrom(component.bodyMakes$)).resolves.toEqual(mockData); + expect(spy).toHaveBeenCalledWith(ReferenceDataResourceType.HgvMake); + }); - it('should return an observable which emits HGV body make ref data when the tech record is a HGV', async () => { - const mockData = [{ label: 'HGV', value: 'HGV' }]; - const spy = jest.spyOn(multiOptionsService, 'getOptions').mockReturnValue(of(mockData)); - component.techRecord = createMockHgv(123); - await expect(lastValueFrom(component.bodyMakes$)).resolves.toEqual(mockData); - expect(spy).toHaveBeenCalledWith(ReferenceDataResourceType.HgvMake); - }); + it('should return an observable which emits TRL body make ref data when the tech record is a TRL', async () => { + const mockData = [{ label: 'TRL', value: 'TRL' }]; + const spy = jest.spyOn(multiOptionsService, 'getOptions').mockReturnValue(of(mockData)); + component.techRecord = createMockTrl(123); + await expect(lastValueFrom(component.bodyMakes$)).resolves.toEqual(mockData); + expect(spy).toHaveBeenCalledWith(ReferenceDataResourceType.TrlMake); + }); + }); - it('should return an observable which emits TRL body make ref data when the tech record is a TRL', async () => { - const mockData = [{ label: 'TRL', value: 'TRL' }]; - const spy = jest.spyOn(multiOptionsService, 'getOptions').mockReturnValue(of(mockData)); - component.techRecord = createMockTrl(123); - await expect(lastValueFrom(component.bodyMakes$)).resolves.toEqual(mockData); - expect(spy).toHaveBeenCalledWith(ReferenceDataResourceType.TrlMake); - }); - }); - - describe('dtpNumbers', () => { - it('should return an observable which emits an array of multi options derrived from reference data', async () => { - const allMockData = [{ resourceKey: 'psv', resourceType: ReferenceDataResourceType.PsvMake }]; - const getAllSpy = jest.spyOn(referenceDataService, 'getAll$').mockReturnValue(of(allMockData)); - const getPsvMakeDataLoadingSpy = jest.spyOn(referenceDataService, 'getReferencePsvMakeDataLoading$').mockReturnValue(of(false)); - component.techRecord = createMockPsv(123); - await expect(lastValueFrom(component.dtpNumbers$)).resolves.toEqual([{ value: 'psv', label: 'psv' }]); - expect(getAllSpy).toHaveBeenCalledWith(ReferenceDataResourceType.PsvMake); - expect(getPsvMakeDataLoadingSpy).toHaveBeenCalled(); - }); - }); + describe('dtpNumbers', () => { + it('should return an observable which emits an array of multi options derrived from reference data', async () => { + const allMockData = [{ resourceKey: 'psv', resourceType: ReferenceDataResourceType.PsvMake }]; + const getAllSpy = jest.spyOn(referenceDataService, 'getAll$').mockReturnValue(of(allMockData)); + const getPsvMakeDataLoadingSpy = jest + .spyOn(referenceDataService, 'getReferencePsvMakeDataLoading$') + .mockReturnValue(of(false)); + component.techRecord = createMockPsv(123); + await expect(lastValueFrom(component.dtpNumbers$)).resolves.toEqual([{ value: 'psv', label: 'psv' }]); + expect(getAllSpy).toHaveBeenCalledWith(ReferenceDataResourceType.PsvMake); + expect(getPsvMakeDataLoadingSpy).toHaveBeenCalled(); + }); + }); }); diff --git a/src/app/forms/custom-sections/body/body.component.ts b/src/app/forms/custom-sections/body/body.component.ts index 86e4a75f6b..4f847f17cf 100644 --- a/src/app/forms/custom-sections/body/body.component.ts +++ b/src/app/forms/custom-sections/body/body.component.ts @@ -1,19 +1,18 @@ -import { - Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, -} from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core'; import { TechRecordType as TechRecordVehicleType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; import { MultiOptions } from '@forms/models/options.model'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; -import { - CustomFormGroup, FormNode, FormNodeEditTypes, FormNodeWidth, -} from '@forms/services/dynamic-form.types'; +import { CustomFormGroup, FormNode, FormNodeEditTypes, FormNodeWidth } from '@forms/services/dynamic-form.types'; import { MultiOptionsService } from '@forms/services/multi-options.service'; import { HgvAndTrlBodyTemplate } from '@forms/templates/general/hgv-trl-body.template'; import { PsvBodyTemplate } from '@forms/templates/psv/psv-body.template'; import { getOptionsFromEnum } from '@forms/utils/enum-map'; import { - BodyTypeCode, BodyTypeDescription, vehicleBodyTypeCodeMap, vehicleBodyTypeDescriptionMap, + BodyTypeCode, + BodyTypeDescription, + vehicleBodyTypeCodeMap, + vehicleBodyTypeDescriptionMap, } from '@models/body-type-enum'; import { PsvMake, ReferenceDataResourceType } from '@models/reference-data.model'; import { V3TechRecordModel, VehicleTypes } from '@models/vehicle-tech-record.model'; @@ -22,152 +21,159 @@ import { ReferenceDataService } from '@services/reference-data/reference-data.se import { State } from '@store/index'; import { selectReferenceDataByResourceKey } from '@store/reference-data'; import { updateBody, updateEditingTechRecord } from '@store/technical-records'; -import { - Observable, Subject, combineLatest, debounceTime, map, mergeMap, skipWhile, take, takeUntil, -} from 'rxjs'; +import { Observable, Subject, combineLatest, debounceTime, map, mergeMap, skipWhile, take, takeUntil } from 'rxjs'; @Component({ - selector: 'app-body', - templateUrl: './body.component.html', - styleUrls: ['./body.component.scss'], + selector: 'app-body', + templateUrl: './body.component.html', + styleUrls: ['./body.component.scss'], }) export class BodyComponent implements OnInit, OnChanges, OnDestroy { - @Input() techRecord!: V3TechRecordModel; - @Input() isEditing = false; - @Input() disableLoadOptions = false; - - @Output() formChange = new EventEmitter(); - - public form!: CustomFormGroup; - private template!: FormNode; - private destroy$ = new Subject(); - - constructor( - private dfs: DynamicFormService, - private optionsService: MultiOptionsService, - private referenceDataService: ReferenceDataService, - private store: Store, - ) { } - - ngOnInit(): void { - this.template = this.techRecord.techRecord_vehicleType === VehicleTypes.PSV ? PsvBodyTemplate : HgvAndTrlBodyTemplate; - this.form = this.dfs.createForm(this.template, this.techRecord) as CustomFormGroup; - this.form.cleanValueChanges - .pipe( - debounceTime(400), - takeUntil(this.destroy$), - // eslint-disable-next-line @typescript-eslint/no-explicit-any - mergeMap((event: any) => - this.store.pipe( - select(selectReferenceDataByResourceKey(ReferenceDataResourceType.PsvMake, event.techRecord_brakes_dtpNumber)), - take(1), - map((referenceData) => [event, referenceData as PsvMake]), - )), - ) - .subscribe(([event, psvMake]) => { - // Set the body type code automatically based selection - if (event?.techRecord_bodyType_description) { - // body type codes are specific to the vehicle type - const vehicleType = this.techRecord.techRecord_vehicleType === 'hgv' - ? `${this.techRecord.techRecord_vehicleConfiguration}Hgv` - : this.techRecord.techRecord_vehicleType; - const bodyTypes = vehicleBodyTypeDescriptionMap.get(vehicleType as VehicleTypes) as Map; - event.techRecord_bodyType_code = bodyTypes.get(event?.techRecord_bodyType_description); - } - - this.formChange.emit(event); - - if ( - this.techRecord.techRecord_vehicleType === VehicleTypes.PSV - && event?.techRecord_brakes_dtpNumber - && event.techRecord_brakes_dtpNumber.length >= 4 - && psvMake - ) { - this.store.dispatch(updateBody({ psvMake })); - } - }); - - this.loadOptions(); - } - - ngOnChanges(changes: SimpleChanges): void { - const { techRecord } = changes; - - if (this.form && techRecord?.currentValue && techRecord.currentValue !== techRecord.previousValue) { - this.form.patchValue(techRecord.currentValue, { emitEvent: false }); - } - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - get editTypes(): typeof FormNodeEditTypes { - return FormNodeEditTypes; - } - - get widths(): typeof FormNodeWidth { - return FormNodeWidth; - } - - get bodyTypes(): MultiOptions { - let vehicleType: string = this.techRecord.techRecord_vehicleType; - - if (this.techRecord.techRecord_vehicleType === 'hgv') { - vehicleType = `${this.techRecord.techRecord_vehicleConfiguration}Hgv`; - this.updateHgvVehicleBodyType(this.techRecord); - } - const optionsMap = vehicleBodyTypeCodeMap.get(vehicleType) ?? []; - const values = [...optionsMap.values()]; - return getOptionsFromEnum(values.sort()); - - } - - get bodyMakes$(): Observable { - if (this.techRecord.techRecord_vehicleType === VehicleTypes.HGV) { - return this.optionsService.getOptions(ReferenceDataResourceType.HgvMake); - } - if (this.techRecord.techRecord_vehicleType === VehicleTypes.PSV) { - return this.optionsService.getOptions(ReferenceDataResourceType.PsvMake); - } - return this.optionsService.getOptions(ReferenceDataResourceType.TrlMake); - } - - get dtpNumbers$(): Observable { - return combineLatest([ - this.referenceDataService.getAll$(ReferenceDataResourceType.PsvMake), - this.referenceDataService.getReferencePsvMakeDataLoading$(), - ]).pipe( - skipWhile(([, loading]) => loading), - take(1), - map(([data]) => { - return data?.map((option) => ({ value: option.resourceKey, label: option.resourceKey })) as MultiOptions; - }), - ); - } - - loadOptions(): void { - if (this.disableLoadOptions) return; - - if (this.techRecord.techRecord_vehicleType === VehicleTypes.HGV) { - this.optionsService.loadOptions(ReferenceDataResourceType.HgvMake); - } else if (this.techRecord.techRecord_vehicleType === VehicleTypes.PSV) { - this.optionsService.loadOptions(ReferenceDataResourceType.PsvMake); - } else { - this.optionsService.loadOptions(ReferenceDataResourceType.TrlMake); - } - } - - updateHgvVehicleBodyType(record: TechRecordVehicleType<'hgv'>) { - if (record.techRecord_vehicleConfiguration === 'articulated') { - this.store.dispatch(updateEditingTechRecord({ - vehicleTechRecord: { - ...this.techRecord, - techRecord_bodyType_description: 'articulated', - techRecord_bodyType_code: 'a', - } as TechRecordType<'put'>, - })); - } - } + @Input() techRecord!: V3TechRecordModel; + @Input() isEditing = false; + @Input() disableLoadOptions = false; + + @Output() formChange = new EventEmitter(); + + public form!: CustomFormGroup; + private template!: FormNode; + private destroy$ = new Subject(); + + constructor( + private dfs: DynamicFormService, + private optionsService: MultiOptionsService, + private referenceDataService: ReferenceDataService, + private store: Store + ) {} + + ngOnInit(): void { + this.template = + this.techRecord.techRecord_vehicleType === VehicleTypes.PSV ? PsvBodyTemplate : HgvAndTrlBodyTemplate; + this.form = this.dfs.createForm(this.template, this.techRecord) as CustomFormGroup; + this.form.cleanValueChanges + .pipe( + debounceTime(400), + takeUntil(this.destroy$), + // eslint-disable-next-line @typescript-eslint/no-explicit-any + mergeMap((event: any) => + this.store.pipe( + select( + selectReferenceDataByResourceKey(ReferenceDataResourceType.PsvMake, event.techRecord_brakes_dtpNumber) + ), + take(1), + map((referenceData) => [event, referenceData as PsvMake]) + ) + ) + ) + .subscribe(([event, psvMake]) => { + // Set the body type code automatically based selection + if (event?.techRecord_bodyType_description) { + // body type codes are specific to the vehicle type + const vehicleType = + this.techRecord.techRecord_vehicleType === 'hgv' + ? `${this.techRecord.techRecord_vehicleConfiguration}Hgv` + : this.techRecord.techRecord_vehicleType; + const bodyTypes = vehicleBodyTypeDescriptionMap.get(vehicleType as VehicleTypes) as Map< + BodyTypeDescription, + BodyTypeCode + >; + event.techRecord_bodyType_code = bodyTypes.get(event?.techRecord_bodyType_description); + } + + this.formChange.emit(event); + + if ( + this.techRecord.techRecord_vehicleType === VehicleTypes.PSV && + event?.techRecord_brakes_dtpNumber && + event.techRecord_brakes_dtpNumber.length >= 4 && + psvMake + ) { + this.store.dispatch(updateBody({ psvMake })); + } + }); + + this.loadOptions(); + } + + ngOnChanges(changes: SimpleChanges): void { + const { techRecord } = changes; + + if (this.form && techRecord?.currentValue && techRecord.currentValue !== techRecord.previousValue) { + this.form.patchValue(techRecord.currentValue, { emitEvent: false }); + } + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + get editTypes(): typeof FormNodeEditTypes { + return FormNodeEditTypes; + } + + get widths(): typeof FormNodeWidth { + return FormNodeWidth; + } + + get bodyTypes(): MultiOptions { + let vehicleType: string = this.techRecord.techRecord_vehicleType; + + if (this.techRecord.techRecord_vehicleType === 'hgv') { + vehicleType = `${this.techRecord.techRecord_vehicleConfiguration}Hgv`; + this.updateHgvVehicleBodyType(this.techRecord); + } + const optionsMap = vehicleBodyTypeCodeMap.get(vehicleType) ?? []; + const values = [...optionsMap.values()]; + return getOptionsFromEnum(values.sort()); + } + + get bodyMakes$(): Observable { + if (this.techRecord.techRecord_vehicleType === VehicleTypes.HGV) { + return this.optionsService.getOptions(ReferenceDataResourceType.HgvMake); + } + if (this.techRecord.techRecord_vehicleType === VehicleTypes.PSV) { + return this.optionsService.getOptions(ReferenceDataResourceType.PsvMake); + } + return this.optionsService.getOptions(ReferenceDataResourceType.TrlMake); + } + + get dtpNumbers$(): Observable { + return combineLatest([ + this.referenceDataService.getAll$(ReferenceDataResourceType.PsvMake), + this.referenceDataService.getReferencePsvMakeDataLoading$(), + ]).pipe( + skipWhile(([, loading]) => loading), + take(1), + map(([data]) => { + return data?.map((option) => ({ value: option.resourceKey, label: option.resourceKey })) as MultiOptions; + }) + ); + } + + loadOptions(): void { + if (this.disableLoadOptions) return; + + if (this.techRecord.techRecord_vehicleType === VehicleTypes.HGV) { + this.optionsService.loadOptions(ReferenceDataResourceType.HgvMake); + } else if (this.techRecord.techRecord_vehicleType === VehicleTypes.PSV) { + this.optionsService.loadOptions(ReferenceDataResourceType.PsvMake); + } else { + this.optionsService.loadOptions(ReferenceDataResourceType.TrlMake); + } + } + + updateHgvVehicleBodyType(record: TechRecordVehicleType<'hgv'>) { + if (record.techRecord_vehicleConfiguration === 'articulated') { + this.store.dispatch( + updateEditingTechRecord({ + vehicleTechRecord: { + ...this.techRecord, + techRecord_bodyType_description: 'articulated', + techRecord_bodyType_code: 'a', + } as TechRecordType<'put'>, + }) + ); + } + } } diff --git a/src/app/forms/custom-sections/custom-defect/custom-defect.component.spec.ts b/src/app/forms/custom-sections/custom-defect/custom-defect.component.spec.ts index 3fe253da22..919dbbe633 100644 --- a/src/app/forms/custom-sections/custom-defect/custom-defect.component.spec.ts +++ b/src/app/forms/custom-sections/custom-defect/custom-defect.component.spec.ts @@ -5,22 +5,22 @@ import { SharedModule } from '@shared/shared.module'; import { CustomDefectComponent } from './custom-defect.component'; describe('CustomDefectComponent', () => { - let component: CustomDefectComponent; - let fixture: ComponentFixture; + let component: CustomDefectComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [], - imports: [SharedModule, DynamicFormsModule], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [], + imports: [SharedModule, DynamicFormsModule], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(CustomDefectComponent); - component = fixture.componentInstance; - }); + beforeEach(() => { + fixture = TestBed.createComponent(CustomDefectComponent); + component = fixture.componentInstance; + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/custom-sections/custom-defect/custom-defect.component.ts b/src/app/forms/custom-sections/custom-defect/custom-defect.component.ts index 548783da63..255faab4b3 100644 --- a/src/app/forms/custom-sections/custom-defect/custom-defect.component.ts +++ b/src/app/forms/custom-sections/custom-defect/custom-defect.component.ts @@ -1,17 +1,15 @@ -import { - Component, EventEmitter, Input, Output, -} from '@angular/core'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; import { CustomFormGroup } from '@forms/services/dynamic-form.types'; @Component({ - selector: 'app-custom-defect[index][form]', - templateUrl: './custom-defect.component.html', - styleUrls: ['./custom-defect.component.scss'], + selector: 'app-custom-defect[index][form]', + templateUrl: './custom-defect.component.html', + styleUrls: ['./custom-defect.component.scss'], }) export class CustomDefectComponent { - @Input() form!: CustomFormGroup; - @Input() index!: number; - @Input() isEditing = false; - @Input() templateName?: string; - @Output() removeCustomDefect = new EventEmitter(); + @Input() form!: CustomFormGroup; + @Input() index!: number; + @Input() isEditing = false; + @Input() templateName?: string; + @Output() removeCustomDefect = new EventEmitter(); } diff --git a/src/app/forms/custom-sections/custom-defects/custom-defects.component.spec.ts b/src/app/forms/custom-sections/custom-defects/custom-defects.component.spec.ts index 60dd8d1d64..9c8e35ab47 100644 --- a/src/app/forms/custom-sections/custom-defects/custom-defects.component.spec.ts +++ b/src/app/forms/custom-sections/custom-defects/custom-defects.component.spec.ts @@ -1,6 +1,6 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { DebugElement } from '@angular/core'; -import { ComponentFixture, inject, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed, inject } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { RouterTestingModule } from '@angular/router/testing'; @@ -11,104 +11,104 @@ import { CustomDefectComponent } from '../custom-defect/custom-defect.component' import { CustomDefectsComponent } from './custom-defects.component'; describe('CustomDefectsComponent', () => { - let component: CustomDefectsComponent; - let fixture: ComponentFixture; - let el: DebugElement; + let component: CustomDefectsComponent; + let fixture: ComponentFixture; + let el: DebugElement; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [FormsModule, ReactiveFormsModule, HttpClientTestingModule, RouterTestingModule], - declarations: [CustomDefectsComponent, CustomDefectComponent], - providers: [DynamicFormService, provideMockStore({})], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [FormsModule, ReactiveFormsModule, HttpClientTestingModule, RouterTestingModule], + declarations: [CustomDefectsComponent, CustomDefectComponent], + providers: [DynamicFormService, provideMockStore({})], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(CustomDefectsComponent); - component = fixture.componentInstance; - el = fixture.debugElement; - component.template = { name: 'test component', type: FormNodeTypes.GROUP }; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(CustomDefectsComponent); + component = fixture.componentInstance; + el = fixture.debugElement; + component.template = { name: 'test component', type: FormNodeTypes.GROUP }; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it('should render correct header', () => { - expect(el.query(By.css('h2')).nativeElement.innerHTML).toBe('Custom Defects'); - }); + it('should render correct header', () => { + expect(el.query(By.css('h2')).nativeElement.innerHTML).toBe('Custom Defects'); + }); - describe('add and remove custom defects', () => { - const template = { - name: 'customDefectsSection', - label: 'Custom Defects', - type: 'group', - children: [ - { - name: 'testTypes', - label: 'Test Types', - type: 'array', - children: [ - { - name: '0', - type: 'group', - children: [ - { - name: 'customDefects', - type: 'array', - children: [ - { - name: '0', - type: 'group', - children: [ - { - name: 'referenceNumber', - label: 'Reference Number', - type: 'control', - }, - { - name: 'defectName', - label: 'Defect Name', - type: 'control', - }, - { - name: 'defectNotes', - label: 'Defect Notes', - type: 'control', - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], - }; + describe('add and remove custom defects', () => { + const template = { + name: 'customDefectsSection', + label: 'Custom Defects', + type: 'group', + children: [ + { + name: 'testTypes', + label: 'Test Types', + type: 'array', + children: [ + { + name: '0', + type: 'group', + children: [ + { + name: 'customDefects', + type: 'array', + children: [ + { + name: '0', + type: 'group', + children: [ + { + name: 'referenceNumber', + label: 'Reference Number', + type: 'control', + }, + { + name: 'defectName', + label: 'Defect Name', + type: 'control', + }, + { + name: 'defectNotes', + label: 'Defect Notes', + type: 'control', + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }; - const data = { - testTypes: [ - { - customDefects: [], - }, - ], - }; + const data = { + testTypes: [ + { + customDefects: [], + }, + ], + }; - it('should add new custom defect', inject([DynamicFormService], (dfs: DynamicFormService) => { - component.form = dfs.createForm(template, data) as CustomFormGroup; - expect(component.defectCount).toBe(0); - component.handleAddCustomDefect(); - expect(component.defectCount).toBe(1); - })); + it('should add new custom defect', inject([DynamicFormService], (dfs: DynamicFormService) => { + component.form = dfs.createForm(template, data) as CustomFormGroup; + expect(component.defectCount).toBe(0); + component.handleAddCustomDefect(); + expect(component.defectCount).toBe(1); + })); - it('should remove custom defect', inject([DynamicFormService], (dfs: DynamicFormService) => { - component.form = dfs.createForm(template, data) as CustomFormGroup; - component.handleAddCustomDefect(); - expect(component.defectCount).toBe(1); - component.handleRemoveDefect(0); - expect(component.defectCount).toBe(0); - })); - }); + it('should remove custom defect', inject([DynamicFormService], (dfs: DynamicFormService) => { + component.form = dfs.createForm(template, data) as CustomFormGroup; + component.handleAddCustomDefect(); + expect(component.defectCount).toBe(1); + component.handleRemoveDefect(0); + expect(component.defectCount).toBe(0); + })); + }); }); diff --git a/src/app/forms/custom-sections/custom-defects/custom-defects.component.ts b/src/app/forms/custom-sections/custom-defects/custom-defects.component.ts index c3dfd355ce..f8a254efbb 100644 --- a/src/app/forms/custom-sections/custom-defects/custom-defects.component.ts +++ b/src/app/forms/custom-sections/custom-defects/custom-defects.component.ts @@ -1,67 +1,67 @@ -import { - Component, EventEmitter, Input, OnDestroy, OnInit, Output, -} from '@angular/core'; +import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { CustomDefect, CustomDefects } from '@api/test-results'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; import { CustomFormArray, CustomFormGroup, FormNode } from '@forms/services/dynamic-form.types'; import { Subscription } from 'rxjs'; @Component({ - selector: 'app-custom-defects[template]', - templateUrl: './custom-defects.component.html', - styleUrls: [], + selector: 'app-custom-defects[template]', + templateUrl: './custom-defects.component.html', + styleUrls: [], }) export class CustomDefectsComponent implements OnInit, OnDestroy { - @Input() isEditing = false; - @Input() template!: FormNode; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - @Input() data: any = {}; + @Input() isEditing = false; + @Input() template!: FormNode; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + @Input() data: any = {}; - @Output() formChange = new EventEmitter(); - form!: CustomFormGroup; + @Output() formChange = new EventEmitter(); + form!: CustomFormGroup; - private formSubscription = new Subscription(); - defectNameType?: string; + private formSubscription = new Subscription(); + defectNameType?: string; - constructor(private dfs: DynamicFormService) {} + constructor(private dfs: DynamicFormService) {} - ngOnInit(): void { - this.form = this.dfs.createForm(this.template, this.data) as CustomFormGroup; - this.formSubscription = this.form.cleanValueChanges.subscribe((event) => { - this.formChange.emit(event); - }); - this.defectNameType = this.template.name === 'additionalDefectsSection' ? 'Additional Defect' : 'Custom Defect'; - } + ngOnInit(): void { + this.form = this.dfs.createForm(this.template, this.data) as CustomFormGroup; + this.formSubscription = this.form.cleanValueChanges.subscribe((event) => { + this.formChange.emit(event); + }); + this.defectNameType = this.template.name === 'additionalDefectsSection' ? 'Additional Defect' : 'Custom Defect'; + } - ngOnDestroy(): void { - this.formSubscription.unsubscribe(); - } + ngOnDestroy(): void { + this.formSubscription.unsubscribe(); + } - get customDefectsForm() { - return this.form?.get(['testTypes', '0', 'customDefects']) as CustomFormArray; - } + get customDefectsForm() { + return this.form?.get(['testTypes', '0', 'customDefects']) as CustomFormArray; + } - getCustomDefectForm(i: number) { - return this.customDefectsForm?.controls[`${i}`] as CustomFormGroup; - } + getCustomDefectForm(i: number) { + return this.customDefectsForm?.controls[`${i}`] as CustomFormGroup; + } - trackByFn(index: number): number { - return index; - } + trackByFn(index: number): number { + return index; + } - get defectCount() { - return this.customDefectsForm?.controls.length; - } + get defectCount() { + return this.customDefectsForm?.controls.length; + } - get customDefects(): CustomDefects { - return this.customDefectsForm.controls.map((control) => (control as CustomFormGroup).getCleanValue(control as CustomFormGroup) as CustomDefect); - } + get customDefects(): CustomDefects { + return this.customDefectsForm.controls.map( + (control) => (control as CustomFormGroup).getCleanValue(control as CustomFormGroup) as CustomDefect + ); + } - handleRemoveDefect(index: number): void { - this.customDefectsForm.removeAt(index); - } + handleRemoveDefect(index: number): void { + this.customDefectsForm.removeAt(index); + } - handleAddCustomDefect() { - this.customDefectsForm.addControl(); - } + handleAddCustomDefect() { + this.customDefectsForm.addControl(); + } } diff --git a/src/app/forms/custom-sections/custom-form-control/custom-form-control.component.spec.ts b/src/app/forms/custom-sections/custom-form-control/custom-form-control.component.spec.ts index b113e722e9..41c767c278 100644 --- a/src/app/forms/custom-sections/custom-form-control/custom-form-control.component.spec.ts +++ b/src/app/forms/custom-sections/custom-form-control/custom-form-control.component.spec.ts @@ -3,21 +3,20 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { CustomFormControlComponent } from './custom-form-control.component'; describe('CustomFormControlComponent', () => { - let component: CustomFormControlComponent; - let fixture: ComponentFixture; + let component: CustomFormControlComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [CustomFormControlComponent], - }) - .compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [CustomFormControlComponent], + }).compileComponents(); - fixture = TestBed.createComponent(CustomFormControlComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + fixture = TestBed.createComponent(CustomFormControlComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/custom-sections/custom-form-control/custom-form-control.component.ts b/src/app/forms/custom-sections/custom-form-control/custom-form-control.component.ts index 5602eb74b2..284fb8c158 100644 --- a/src/app/forms/custom-sections/custom-form-control/custom-form-control.component.ts +++ b/src/app/forms/custom-sections/custom-form-control/custom-form-control.component.ts @@ -6,28 +6,28 @@ import { FORM_INJECTION_TOKEN } from '@forms/components/dynamic-form-field/dynam import { CustomControl } from '@forms/services/dynamic-form.types'; @Component({ - selector: 'app-custom-form-control', - templateUrl: './custom-form-control.component.html', - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: CustomFormControlComponent, - multi: true, - }, - ], + selector: 'app-custom-form-control', + templateUrl: './custom-form-control.component.html', + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: CustomFormControlComponent, + multi: true, + }, + ], }) export class CustomFormControlComponent extends BaseControlComponent { - protected form?: FormGroup; + protected form?: FormGroup; - override ngAfterContentInit(): void { - const injectedControl = this.injector.get(NgControl, null); - if (injectedControl) { - const ngControl = injectedControl.control as unknown as KeyValue; - if (ngControl.value) { - this.name = ngControl.key; - this.control = ngControl.value; - this.form = this.injector.get(FORM_INJECTION_TOKEN) as FormGroup; - } - } - } + override ngAfterContentInit(): void { + const injectedControl = this.injector.get(NgControl, null); + if (injectedControl) { + const ngControl = injectedControl.control as unknown as KeyValue; + if (ngControl.value) { + this.name = ngControl.key; + this.control = ngControl.value; + this.form = this.injector.get(FORM_INJECTION_TOKEN) as FormGroup; + } + } + } } diff --git a/src/app/forms/custom-sections/defect/defect.component.spec.ts b/src/app/forms/custom-sections/defect/defect.component.spec.ts index 9a0c7e10ba..7278bddcae 100644 --- a/src/app/forms/custom-sections/defect/defect.component.spec.ts +++ b/src/app/forms/custom-sections/defect/defect.component.spec.ts @@ -1,7 +1,5 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { - ComponentFixture, fakeAsync, TestBed, tick, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { ActivatedRoute, Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { DynamicFormsModule } from '@forms/dynamic-forms.module'; @@ -15,237 +13,247 @@ import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { SharedModule } from '@shared/shared.module'; import { defects, selectByImNumber } from '@store/defects'; -import { initialAppState, State } from '@store/index'; +import { State, initialAppState } from '@store/index'; import { selectRouteParams } from '@store/router/selectors/router.selectors'; -import { - createDefect, removeDefect, toEditOrNotToEdit, updateDefect, -} from '@store/test-records'; +import { createDefect, removeDefect, toEditOrNotToEdit, updateDefect } from '@store/test-records'; import { DefectComponent } from './defect.component'; describe('DefectComponent', () => { - let component: DefectComponent; - let fixture: ComponentFixture; - let router: Router; - let store: MockStore; - - const deficiency: Deficiency = { - deficiencyCategory: deficiencyCategory.Major, - deficiencyId: 'a', - deficiencySubId: '', - deficiencyText: 'missing.', - forVehicleType: [VehicleTypes.PSV], - ref: '1.1.a', - stdForProhibition: false, - }; - - const item: Item = { - deficiencies: [deficiency], - forVehicleType: [VehicleTypes.PSV], - itemDescription: 'A registration plate:', - itemNumber: 1, - }; - - const defect: Defect = { - additionalInfo: { - [VehicleTypes.PSV]: { - location: { - longitudinal: ['front', 'rear'], - }, - notes: true, - }, - }, - forVehicleType: [VehicleTypes.PSV], - imDescription: 'Registration Plate', - imNumber: 1, - items: [item], - }; - - const fakeActivatedRoute = { - snapshot: { data: { key: 'value' } }, - }; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [], - imports: [SharedModule, DynamicFormsModule, RouterTestingModule, HttpClientTestingModule], - providers: [{ provide: ActivatedRoute, useValue: fakeActivatedRoute }, provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - - router = TestBed.inject(Router); - store = TestBed.inject(MockStore); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(DefectComponent); - component = fixture.componentInstance; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should navigate back to test record', () => { - const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); - component.navigateBack(); - expect(navigateSpy).toHaveBeenCalled(); - }); - - describe('should initialize info Dictionary', () => { - it('should initialize notes to true', fakeAsync(() => { - store.overrideSelector(selectRouteParams, { defectIndex: '0' }); - store.overrideSelector(toEditOrNotToEdit, { - vehicleType: VehicleTypes.PSV, - testTypes: [{ defects: [{ imNumber: 1, deficiencyCategory: deficiencyCategory.Major }] }], - } as TestResultModel); - store.overrideSelector(selectByImNumber(1, VehicleTypes.PSV), { imNumber: 1 } as Defect); - tick(); - fixture.detectChanges(); - - component.initializeInfoDictionary(defect); - expect(component.includeNotes).toBe(true); - })); - - it('should initialize info dictionary to the longitude', fakeAsync(() => { - store.overrideSelector(selectRouteParams, { defectIndex: '0' }); - store.overrideSelector(toEditOrNotToEdit, { - vehicleType: VehicleTypes.PSV, - testTypes: [{ defects: [{ imNumber: 1, deficiencyCategory: deficiencyCategory.Major }] }], - } as TestResultModel); - store.overrideSelector(selectByImNumber(1, VehicleTypes.PSV), { imNumber: 1 } as Defect); - tick(); - fixture.detectChanges(); - - component.initializeInfoDictionary(defect); - expect(component.infoDictionary).toEqual({ - longitudinal: [ - { - label: 'Front', - value: 'front', - }, - { - label: 'Rear', - value: 'rear', - }, - ], - }); - })); - }); - - describe('should initialize defect', () => { - it('should initialize defect using index', fakeAsync(() => { - store.overrideSelector(selectRouteParams, { defectIndex: '0' }); - store.overrideSelector(toEditOrNotToEdit, { - vehicleType: VehicleTypes.PSV, - testTypes: [{ defects: [{ imNumber: 1, deficiencyCategory: deficiencyCategory.Major }] }], - } as TestResultModel); - store.overrideSelector(selectByImNumber(1, VehicleTypes.PSV), { imNumber: 1 } as Defect); - tick(); - fixture.detectChanges(); - - expect(component.defect).toBeDefined(); - })); - - it('should initialize defect using ref', fakeAsync(() => { - store.overrideSelector(selectRouteParams, { ref: '1.1.a' }); - store.overrideSelector(toEditOrNotToEdit, { - vehicleType: VehicleTypes.PSV, - testTypes: [{ defects: [{ imNumber: 1, imDescription: 'desc', deficiencyCategory: deficiencyCategory.Major }] }], - } as TestResultModel); - store.overrideSelector(defects, [defect]); - tick(); - fixture.detectChanges(); - - expect(component.defect).toBeDefined(); - })); - }); - - describe('should get isDangerous', () => { - it('should return true when defect is dangerous', () => { - component.defect = { deficiencyCategory: deficiencyCategory.Dangerous }; - expect(component.isDangerous).toBe(true); - }); - it('should return false when defect is advisory', () => { - component.defect = { deficiencyCategory: deficiencyCategory.Advisory }; - expect(component.isDangerous).toBe(false); - }); - it('should return false when defect is major', () => { - component.defect = { deficiencyCategory: deficiencyCategory.Major }; - expect(component.isDangerous).toBe(false); - }); - it('should return false when defect is minor', () => { - component.defect = { deficiencyCategory: deficiencyCategory.Minor }; - expect(component.isDangerous).toBe(false); - }); - }); - - describe('should get isAdvisory', () => { - it('should return true when defect is advisory', () => { - component.defect = { deficiencyCategory: deficiencyCategory.Advisory }; - expect(component.isAdvisory).toBe(true); - }); - it('should return false when defect is dangerous', () => { - component.defect = { deficiencyCategory: deficiencyCategory.Dangerous }; - expect(component.isAdvisory).toBe(false); - }); - it('should return false when defect is major', () => { - component.defect = { deficiencyCategory: deficiencyCategory.Major }; - expect(component.isAdvisory).toBe(false); - }); - it('should return false when defect is minor', () => { - component.defect = { deficiencyCategory: deficiencyCategory.Minor }; - expect(component.isAdvisory).toBe(false); - }); - }); - - describe('should dispatch', () => { - it('should dispatch create defect action', fakeAsync(() => { - store.overrideSelector(selectRouteParams, { ref: '1.1.a' }); - store.overrideSelector(toEditOrNotToEdit, { - vehicleType: VehicleTypes.PSV, - testTypes: [{ defects: [{ imNumber: 1, imDescription: 'desc', deficiencyCategory: deficiencyCategory.Major }] }], - } as TestResultModel); - store.overrideSelector(defects, [defect]); - tick(); - fixture.detectChanges(); - - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.handleSubmit(); - - expect(dispatchSpy).toHaveBeenCalledWith(createDefect({ defect: component.form.getCleanValue(component.form) as TestResultDefect })); - })); - - it('should dispatch update defect action', fakeAsync(() => { - store.overrideSelector(selectRouteParams, { defectIndex: '0' }); - store.overrideSelector(toEditOrNotToEdit, { - vehicleType: VehicleTypes.PSV, - testTypes: [{ defects: [{ imNumber: 1, deficiencyCategory: deficiencyCategory.Major }] }], - } as TestResultModel); - store.overrideSelector(selectByImNumber(1, VehicleTypes.PSV), { imNumber: 1 } as Defect); - tick(); - fixture.detectChanges(); - - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.handleSubmit(); - - expect(dispatchSpy).toHaveBeenCalledWith( - updateDefect({ defect: component.form.getCleanValue(component.form) as TestResultDefect, index: component.index }), - ); - })); - - it('should dispatch delete defect action', fakeAsync(() => { - store.overrideSelector(selectRouteParams, { defectIndex: '0' }); - store.overrideSelector(toEditOrNotToEdit, { - vehicleType: VehicleTypes.PSV, - testTypes: [{ defects: [{ imNumber: 1, deficiencyCategory: deficiencyCategory.Major }] }], - } as TestResultModel); - store.overrideSelector(selectByImNumber(1, VehicleTypes.PSV), { imNumber: 1 } as Defect); - tick(); - fixture.detectChanges(); - - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.handleRemove(); - - expect(dispatchSpy).toHaveBeenCalledWith(removeDefect({ index: component.index })); - })); - }); + let component: DefectComponent; + let fixture: ComponentFixture; + let router: Router; + let store: MockStore; + + const deficiency: Deficiency = { + deficiencyCategory: deficiencyCategory.Major, + deficiencyId: 'a', + deficiencySubId: '', + deficiencyText: 'missing.', + forVehicleType: [VehicleTypes.PSV], + ref: '1.1.a', + stdForProhibition: false, + }; + + const item: Item = { + deficiencies: [deficiency], + forVehicleType: [VehicleTypes.PSV], + itemDescription: 'A registration plate:', + itemNumber: 1, + }; + + const defect: Defect = { + additionalInfo: { + [VehicleTypes.PSV]: { + location: { + longitudinal: ['front', 'rear'], + }, + notes: true, + }, + }, + forVehicleType: [VehicleTypes.PSV], + imDescription: 'Registration Plate', + imNumber: 1, + items: [item], + }; + + const fakeActivatedRoute = { + snapshot: { data: { key: 'value' } }, + }; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [], + imports: [SharedModule, DynamicFormsModule, RouterTestingModule, HttpClientTestingModule], + providers: [ + { provide: ActivatedRoute, useValue: fakeActivatedRoute }, + provideMockStore({ initialState: initialAppState }), + ], + }).compileComponents(); + + router = TestBed.inject(Router); + store = TestBed.inject(MockStore); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(DefectComponent); + component = fixture.componentInstance; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should navigate back to test record', () => { + const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation(() => Promise.resolve(true)); + component.navigateBack(); + expect(navigateSpy).toHaveBeenCalled(); + }); + + describe('should initialize info Dictionary', () => { + it('should initialize notes to true', fakeAsync(() => { + store.overrideSelector(selectRouteParams, { defectIndex: '0' }); + store.overrideSelector(toEditOrNotToEdit, { + vehicleType: VehicleTypes.PSV, + testTypes: [{ defects: [{ imNumber: 1, deficiencyCategory: deficiencyCategory.Major }] }], + } as TestResultModel); + store.overrideSelector(selectByImNumber(1, VehicleTypes.PSV), { imNumber: 1 } as Defect); + tick(); + fixture.detectChanges(); + + component.initializeInfoDictionary(defect); + expect(component.includeNotes).toBe(true); + })); + + it('should initialize info dictionary to the longitude', fakeAsync(() => { + store.overrideSelector(selectRouteParams, { defectIndex: '0' }); + store.overrideSelector(toEditOrNotToEdit, { + vehicleType: VehicleTypes.PSV, + testTypes: [{ defects: [{ imNumber: 1, deficiencyCategory: deficiencyCategory.Major }] }], + } as TestResultModel); + store.overrideSelector(selectByImNumber(1, VehicleTypes.PSV), { imNumber: 1 } as Defect); + tick(); + fixture.detectChanges(); + + component.initializeInfoDictionary(defect); + expect(component.infoDictionary).toEqual({ + longitudinal: [ + { + label: 'Front', + value: 'front', + }, + { + label: 'Rear', + value: 'rear', + }, + ], + }); + })); + }); + + describe('should initialize defect', () => { + it('should initialize defect using index', fakeAsync(() => { + store.overrideSelector(selectRouteParams, { defectIndex: '0' }); + store.overrideSelector(toEditOrNotToEdit, { + vehicleType: VehicleTypes.PSV, + testTypes: [{ defects: [{ imNumber: 1, deficiencyCategory: deficiencyCategory.Major }] }], + } as TestResultModel); + store.overrideSelector(selectByImNumber(1, VehicleTypes.PSV), { imNumber: 1 } as Defect); + tick(); + fixture.detectChanges(); + + expect(component.defect).toBeDefined(); + })); + + it('should initialize defect using ref', fakeAsync(() => { + store.overrideSelector(selectRouteParams, { ref: '1.1.a' }); + store.overrideSelector(toEditOrNotToEdit, { + vehicleType: VehicleTypes.PSV, + testTypes: [ + { defects: [{ imNumber: 1, imDescription: 'desc', deficiencyCategory: deficiencyCategory.Major }] }, + ], + } as TestResultModel); + store.overrideSelector(defects, [defect]); + tick(); + fixture.detectChanges(); + + expect(component.defect).toBeDefined(); + })); + }); + + describe('should get isDangerous', () => { + it('should return true when defect is dangerous', () => { + component.defect = { deficiencyCategory: deficiencyCategory.Dangerous }; + expect(component.isDangerous).toBe(true); + }); + it('should return false when defect is advisory', () => { + component.defect = { deficiencyCategory: deficiencyCategory.Advisory }; + expect(component.isDangerous).toBe(false); + }); + it('should return false when defect is major', () => { + component.defect = { deficiencyCategory: deficiencyCategory.Major }; + expect(component.isDangerous).toBe(false); + }); + it('should return false when defect is minor', () => { + component.defect = { deficiencyCategory: deficiencyCategory.Minor }; + expect(component.isDangerous).toBe(false); + }); + }); + + describe('should get isAdvisory', () => { + it('should return true when defect is advisory', () => { + component.defect = { deficiencyCategory: deficiencyCategory.Advisory }; + expect(component.isAdvisory).toBe(true); + }); + it('should return false when defect is dangerous', () => { + component.defect = { deficiencyCategory: deficiencyCategory.Dangerous }; + expect(component.isAdvisory).toBe(false); + }); + it('should return false when defect is major', () => { + component.defect = { deficiencyCategory: deficiencyCategory.Major }; + expect(component.isAdvisory).toBe(false); + }); + it('should return false when defect is minor', () => { + component.defect = { deficiencyCategory: deficiencyCategory.Minor }; + expect(component.isAdvisory).toBe(false); + }); + }); + + describe('should dispatch', () => { + it('should dispatch create defect action', fakeAsync(() => { + store.overrideSelector(selectRouteParams, { ref: '1.1.a' }); + store.overrideSelector(toEditOrNotToEdit, { + vehicleType: VehicleTypes.PSV, + testTypes: [ + { defects: [{ imNumber: 1, imDescription: 'desc', deficiencyCategory: deficiencyCategory.Major }] }, + ], + } as TestResultModel); + store.overrideSelector(defects, [defect]); + tick(); + fixture.detectChanges(); + + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.handleSubmit(); + + expect(dispatchSpy).toHaveBeenCalledWith( + createDefect({ defect: component.form.getCleanValue(component.form) as TestResultDefect }) + ); + })); + + it('should dispatch update defect action', fakeAsync(() => { + store.overrideSelector(selectRouteParams, { defectIndex: '0' }); + store.overrideSelector(toEditOrNotToEdit, { + vehicleType: VehicleTypes.PSV, + testTypes: [{ defects: [{ imNumber: 1, deficiencyCategory: deficiencyCategory.Major }] }], + } as TestResultModel); + store.overrideSelector(selectByImNumber(1, VehicleTypes.PSV), { imNumber: 1 } as Defect); + tick(); + fixture.detectChanges(); + + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.handleSubmit(); + + expect(dispatchSpy).toHaveBeenCalledWith( + updateDefect({ + defect: component.form.getCleanValue(component.form) as TestResultDefect, + index: component.index, + }) + ); + })); + + it('should dispatch delete defect action', fakeAsync(() => { + store.overrideSelector(selectRouteParams, { defectIndex: '0' }); + store.overrideSelector(toEditOrNotToEdit, { + vehicleType: VehicleTypes.PSV, + testTypes: [{ defects: [{ imNumber: 1, deficiencyCategory: deficiencyCategory.Major }] }], + } as TestResultModel); + store.overrideSelector(selectByImNumber(1, VehicleTypes.PSV), { imNumber: 1 } as Defect); + tick(); + fixture.detectChanges(); + + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.handleRemove(); + + expect(dispatchSpy).toHaveBeenCalledWith(removeDefect({ index: component.index })); + })); + }); }); diff --git a/src/app/forms/custom-sections/defect/defect.component.ts b/src/app/forms/custom-sections/defect/defect.component.ts index 6b967e408a..270dee2d2b 100644 --- a/src/app/forms/custom-sections/defect/defect.component.ts +++ b/src/app/forms/custom-sections/defect/defect.component.ts @@ -1,7 +1,5 @@ import { KeyValue } from '@angular/common'; -import { - ChangeDetectionStrategy, Component, OnDestroy, OnInit, -} from '@angular/core'; +import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalError } from '@core/components/global-error/global-error.interface'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; @@ -21,216 +19,222 @@ import { DefaultNullOrEmpty } from '@shared/pipes/default-null-or-empty/default- import { selectByDeficiencyRef, selectByImNumber } from '@store/defects'; import { State } from '@store/index'; import { selectRouteParam } from '@store/router/selectors/router.selectors'; -import { - createDefect, removeDefect, testResultInEdit, toEditOrNotToEdit, updateDefect, -} from '@store/test-records'; -import { - Subject, filter, take, takeUntil, withLatestFrom, -} from 'rxjs'; +import { createDefect, removeDefect, testResultInEdit, toEditOrNotToEdit, updateDefect } from '@store/test-records'; +import { Subject, filter, take, takeUntil, withLatestFrom } from 'rxjs'; @Component({ - selector: 'app-defect', - templateUrl: './defect.component.html', - styleUrls: ['./defect.component.scss'], - providers: [DefaultNullOrEmpty], - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-defect', + templateUrl: './defect.component.html', + styleUrls: ['./defect.component.scss'], + providers: [DefaultNullOrEmpty], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class DefectComponent implements OnInit, OnDestroy { - form!: CustomFormGroup; - index!: number; - isEditing: boolean; - includeNotes = false; - private vehicleType?: VehicleTypes; - - private defectsForm?: CustomFormArray; - private defects?: TestResultDefects; - defect?: TestResultDefect; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - infoDictionary: Record>> = {}; - onDestroy$ = new Subject(); - - booleanOptions: FormNodeOption[] = [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ]; - - constructor( - private activatedRoute: ActivatedRoute, - private dfs: DynamicFormService, - private router: Router, - private store: Store, - private resultService: ResultOfTestService, - private errorService: GlobalErrorService, - ) { - this.isEditing = this.activatedRoute.snapshot.data['isEditing']; - } - - ngOnInit(): void { - const defectIndex = this.store.pipe(select(selectRouteParam('defectIndex'))); - const defectRef = this.store.pipe(select(selectRouteParam('ref'))); - - this.store - .select(this.isEditing ? testResultInEdit : toEditOrNotToEdit) - .pipe( - withLatestFrom(defectIndex, defectRef), - takeUntil(this.onDestroy$), - filter(([testResult]) => !!testResult), - ) - .subscribe(([testResult, defectIndexValue, defectRefValue]) => { - if (!testResult) this.navigateBack(); - this.defects = testResult?.testTypes[0].defects; - this.vehicleType = testResult?.vehicleType; - this.defectsForm = (this.dfs.createForm(DefectsTpl, testResult) as CustomFormGroup).get(['testTypes', '0', 'defects']) as CustomFormArray; - if (defectIndexValue) { - this.index = Number(defectIndexValue); - this.form = this.defectsForm.controls[this.index] as CustomFormGroup; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.defect = this.defects![this.index]; - } else if (defectRefValue && this.vehicleType) { - this.store - .select(selectByDeficiencyRef(defectRefValue, this.vehicleType)) - .pipe(take(1)) - .subscribe(([defect, item, deficiency]) => { - this.initializeDefect(defect as Defect, item as Item, deficiency as Deficiency); - }); - } - }); - - if (!this.defect) this.navigateBack(); - - if (this.vehicleType) { - this.store - .select(selectByImNumber(this.defect?.imNumber || NaN, this.vehicleType)) - .pipe( - takeUntil(this.onDestroy$), - filter((d) => !!d), - ) - .subscribe((defectsTaxonomy) => { - this.initializeInfoDictionary(defectsTaxonomy); - }); - } - } - - ngOnDestroy(): void { - this.onDestroy$.next(true); - this.onDestroy$.complete(); - } - - get isDangerous(): boolean { - return this.defect?.deficiencyCategory === 'dangerous'; - } - - get isAdvisory(): boolean { - return this.defect?.deficiencyCategory === 'advisory'; - } - - get isDangerousAsterisk(): boolean { - return this.defect?.stdForProhibition === true; - } - - handleSubmit() { - const errors: GlobalError[] = []; - DynamicFormService.validate(this.form, errors); - - if (errors.length > 0) { - this.errorService.setErrors(errors); - } - - if (this.form.invalid) { - return; - } - - if (this.index || this.index === 0) { - this.store.dispatch(updateDefect({ defect: this.form.getCleanValue(this.form) as TestResultDefect, index: this.index })); - } else { - this.store.dispatch(createDefect({ defect: this.form.getCleanValue(this.form) as TestResultDefect })); - } - - this.navigateBack(); - } - - handleRemove() { - this.store.dispatch(removeDefect({ index: this.index })); - this.navigateBack(); - } - - navigateBack() { - this.resultService.updateResultOfTest(); - void this.router.navigate(['../..'], { relativeTo: this.activatedRoute, queryParamsHandling: 'preserve' }); - } - - toggleDefectField(field: keyof TestResultDefect) { - if (!this.defect) { - return; - } - this.defect = { ...this.defect, [field]: !this.defect[`${field}`] } as TestResultDefect; - this.defectsForm?.controls[this.index ?? this.defectsForm.length - 1].get(field)?.patchValue(this.defect[`${field}`]); - } - - initializeInfoDictionary(defect: Defect | undefined) { - const infoShorthand = defect?.additionalInfo; - - const info = defect?.additionalInfo[this.vehicleType as keyof typeof infoShorthand] as AdditionalInfoSection | undefined; - - this.includeNotes = !!info?.notes; - - if (info) { - type LocationKey = keyof typeof info.location; - - Object.keys(info.location).forEach((key) => { - const options = info?.location[key as LocationKey]; - if (options) { - this.infoDictionary[`${key}`] = this.mapOptions(options); - } - }); - } - } - - initializeDefect(defect: Defect, item: Item, deficiency: Deficiency) { - const testResultDefect: TestResultDefect = { - imDescription: defect.imDescription, - imNumber: defect.imNumber, - - itemDescription: item.itemDescription, - itemNumber: item.itemNumber, - - // initializing if defect is advisory - deficiencyCategory: DeficiencyCategoryEnum.Advisory, - deficiencyRef: `${defect.imNumber}.${item.itemNumber}`, - prohibitionIssued: false, - stdForProhibition: false, - }; - - if (deficiency) { - testResultDefect.deficiencyCategory = deficiency.deficiencyCategory; - testResultDefect.deficiencyId = deficiency.deficiencyId; - testResultDefect.deficiencySubId = deficiency.deficiencySubId; - testResultDefect.deficiencyText = deficiency.deficiencyText; - testResultDefect.deficiencyRef = deficiency.ref; - testResultDefect.stdForProhibition = deficiency.stdForProhibition; - } else if (item.itemDescription.endsWith(':')) { - testResultDefect.itemDescription = item.itemDescription.slice(0, -1); - } - - this.defectsForm?.addControl(testResultDefect); - this.form = this.defectsForm?.controls[this.defectsForm.length - 1] as CustomFormGroup; - this.defect = testResultDefect; - } - - categoryColor(category = 'major'): 'red' | 'orange' | 'yellow' | 'green' | 'blue' { - return (>{ - major: 'orange', - minor: 'yellow', - dangerous: 'red', - advisory: 'blue', - })[`${category}`]; - } - - trackByFn = (_index: number, keyValuePair: KeyValue>): string => keyValuePair.key; - - mapOptions = (options: Array): Array> => - options.map((option) => ({ value: option, label: this.pascalCase(String(option)) })); - - pascalCase = (s: string): string => s.charAt(0).toUpperCase() + s.slice(1).replace(/([A-Z])/g, ' $1'); + form!: CustomFormGroup; + index!: number; + isEditing: boolean; + includeNotes = false; + private vehicleType?: VehicleTypes; + + private defectsForm?: CustomFormArray; + private defects?: TestResultDefects; + defect?: TestResultDefect; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + infoDictionary: Record>> = {}; + onDestroy$ = new Subject(); + + booleanOptions: FormNodeOption[] = [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ]; + + constructor( + private activatedRoute: ActivatedRoute, + private dfs: DynamicFormService, + private router: Router, + private store: Store, + private resultService: ResultOfTestService, + private errorService: GlobalErrorService + ) { + this.isEditing = this.activatedRoute.snapshot.data['isEditing']; + } + + ngOnInit(): void { + const defectIndex = this.store.pipe(select(selectRouteParam('defectIndex'))); + const defectRef = this.store.pipe(select(selectRouteParam('ref'))); + + this.store + .select(this.isEditing ? testResultInEdit : toEditOrNotToEdit) + .pipe( + withLatestFrom(defectIndex, defectRef), + takeUntil(this.onDestroy$), + filter(([testResult]) => !!testResult) + ) + .subscribe(([testResult, defectIndexValue, defectRefValue]) => { + if (!testResult) this.navigateBack(); + this.defects = testResult?.testTypes[0].defects; + this.vehicleType = testResult?.vehicleType; + this.defectsForm = (this.dfs.createForm(DefectsTpl, testResult) as CustomFormGroup).get([ + 'testTypes', + '0', + 'defects', + ]) as CustomFormArray; + if (defectIndexValue) { + this.index = Number(defectIndexValue); + this.form = this.defectsForm.controls[this.index] as CustomFormGroup; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.defect = this.defects![this.index]; + } else if (defectRefValue && this.vehicleType) { + this.store + .select(selectByDeficiencyRef(defectRefValue, this.vehicleType)) + .pipe(take(1)) + .subscribe(([defect, item, deficiency]) => { + this.initializeDefect(defect as Defect, item as Item, deficiency as Deficiency); + }); + } + }); + + if (!this.defect) this.navigateBack(); + + if (this.vehicleType) { + this.store + .select(selectByImNumber(this.defect?.imNumber || Number.NaN, this.vehicleType)) + .pipe( + takeUntil(this.onDestroy$), + filter((d) => !!d) + ) + .subscribe((defectsTaxonomy) => { + this.initializeInfoDictionary(defectsTaxonomy); + }); + } + } + + ngOnDestroy(): void { + this.onDestroy$.next(true); + this.onDestroy$.complete(); + } + + get isDangerous(): boolean { + return this.defect?.deficiencyCategory === 'dangerous'; + } + + get isAdvisory(): boolean { + return this.defect?.deficiencyCategory === 'advisory'; + } + + get isDangerousAsterisk(): boolean { + return this.defect?.stdForProhibition === true; + } + + handleSubmit() { + const errors: GlobalError[] = []; + DynamicFormService.validate(this.form, errors); + + if (errors.length > 0) { + this.errorService.setErrors(errors); + } + + if (this.form.invalid) { + return; + } + + if (this.index || this.index === 0) { + this.store.dispatch( + updateDefect({ defect: this.form.getCleanValue(this.form) as TestResultDefect, index: this.index }) + ); + } else { + this.store.dispatch(createDefect({ defect: this.form.getCleanValue(this.form) as TestResultDefect })); + } + + this.navigateBack(); + } + + handleRemove() { + this.store.dispatch(removeDefect({ index: this.index })); + this.navigateBack(); + } + + navigateBack() { + this.resultService.updateResultOfTest(); + void this.router.navigate(['../..'], { relativeTo: this.activatedRoute, queryParamsHandling: 'preserve' }); + } + + toggleDefectField(field: keyof TestResultDefect) { + if (!this.defect) { + return; + } + this.defect = { ...this.defect, [field]: !this.defect[`${field}`] } as TestResultDefect; + this.defectsForm?.controls[this.index ?? this.defectsForm.length - 1] + .get(field) + ?.patchValue(this.defect[`${field}`]); + } + + initializeInfoDictionary(defect: Defect | undefined) { + const infoShorthand = defect?.additionalInfo; + + const info = defect?.additionalInfo[this.vehicleType as keyof typeof infoShorthand] as + | AdditionalInfoSection + | undefined; + + this.includeNotes = !!info?.notes; + + if (info) { + type LocationKey = keyof typeof info.location; + + Object.keys(info.location).forEach((key) => { + const options = info?.location[key as LocationKey]; + if (options) { + this.infoDictionary[`${key}`] = this.mapOptions(options); + } + }); + } + } + + initializeDefect(defect: Defect, item: Item, deficiency: Deficiency) { + const testResultDefect: TestResultDefect = { + imDescription: defect.imDescription, + imNumber: defect.imNumber, + + itemDescription: item.itemDescription, + itemNumber: item.itemNumber, + + // initializing if defect is advisory + deficiencyCategory: DeficiencyCategoryEnum.Advisory, + deficiencyRef: `${defect.imNumber}.${item.itemNumber}`, + prohibitionIssued: false, + stdForProhibition: false, + }; + + if (deficiency) { + testResultDefect.deficiencyCategory = deficiency.deficiencyCategory; + testResultDefect.deficiencyId = deficiency.deficiencyId; + testResultDefect.deficiencySubId = deficiency.deficiencySubId; + testResultDefect.deficiencyText = deficiency.deficiencyText; + testResultDefect.deficiencyRef = deficiency.ref; + testResultDefect.stdForProhibition = deficiency.stdForProhibition; + } else if (item.itemDescription.endsWith(':')) { + testResultDefect.itemDescription = item.itemDescription.slice(0, -1); + } + + this.defectsForm?.addControl(testResultDefect); + this.form = this.defectsForm?.controls[this.defectsForm.length - 1] as CustomFormGroup; + this.defect = testResultDefect; + } + + categoryColor(category = 'major'): 'red' | 'orange' | 'yellow' | 'green' | 'blue' { + return (>{ + major: 'orange', + minor: 'yellow', + dangerous: 'red', + advisory: 'blue', + })[`${category}`]; + } + + trackByFn = (_index: number, keyValuePair: KeyValue>): string => keyValuePair.key; + + mapOptions = (options: Array): Array> => + options.map((option) => ({ value: option, label: this.pascalCase(String(option)) })); + + pascalCase = (s: string): string => s.charAt(0).toUpperCase() + s.slice(1).replace(/([A-Z])/g, ' $1'); } diff --git a/src/app/forms/custom-sections/defects/defects.component.spec.ts b/src/app/forms/custom-sections/defects/defects.component.spec.ts index 55a8fdb260..57ecf9db38 100644 --- a/src/app/forms/custom-sections/defects/defects.component.spec.ts +++ b/src/app/forms/custom-sections/defects/defects.component.spec.ts @@ -1,8 +1,6 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { DebugElement } from '@angular/core'; -import { - ComponentFixture, fakeAsync, TestBed, tick, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { RouterTestingModule } from '@angular/router/testing'; @@ -17,48 +15,55 @@ import { DefectComponent } from '../defect/defect.component'; import { DefectsComponent } from './defects.component'; describe('DefectsComponent', () => { - let component: DefectsComponent; - let fixture: ComponentFixture; - let el: DebugElement; + let component: DefectsComponent; + let fixture: ComponentFixture; + let el: DebugElement; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [FormsModule, ReactiveFormsModule, RouterTestingModule, HttpClientTestingModule], - declarations: [DefectComponent, DefectSelectComponent, DefectsComponent, ButtonComponent, TruncatePipe, TagComponent], - providers: [DynamicFormService, provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [FormsModule, ReactiveFormsModule, RouterTestingModule, HttpClientTestingModule], + declarations: [ + DefectComponent, + DefectSelectComponent, + DefectsComponent, + ButtonComponent, + TruncatePipe, + TagComponent, + ], + providers: [DynamicFormService, provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(DefectsComponent); - component = fixture.componentInstance; - el = fixture.debugElement; - }); + beforeEach(() => { + fixture = TestBed.createComponent(DefectsComponent); + component = fixture.componentInstance; + el = fixture.debugElement; + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it('should render correct header', () => { - fixture.detectChanges(); - expect(el.query(By.css('h2')).nativeElement.innerHTML).toBe('Defects'); - }); + it('should render correct header', () => { + fixture.detectChanges(); + expect(el.query(By.css('h2')).nativeElement.innerHTML).toBe('Defects'); + }); - describe('No defects', () => { - it('should be displayed when defects is undefined or empty array', fakeAsync(() => { - const expectedText = 'No defects'; + describe('No defects', () => { + it('should be displayed when defects is undefined or empty array', fakeAsync(() => { + const expectedText = 'No defects'; - tick(); - fixture.detectChanges(); + tick(); + fixture.detectChanges(); - let text: HTMLParagraphElement = el.query(By.css('p')).nativeElement; - expect(text.innerHTML).toBe(expectedText); + let text: HTMLParagraphElement = el.query(By.css('p')).nativeElement; + expect(text.innerHTML).toBe(expectedText); - tick(); - fixture.detectChanges(); + tick(); + fixture.detectChanges(); - text = el.query(By.css('p')).nativeElement; - expect(text.innerHTML).toBe(expectedText); - })); - }); + text = el.query(By.css('p')).nativeElement; + expect(text.innerHTML).toBe(expectedText); + })); + }); }); diff --git a/src/app/forms/custom-sections/defects/defects.component.ts b/src/app/forms/custom-sections/defects/defects.component.ts index d1a359c0b3..6aa682007a 100644 --- a/src/app/forms/custom-sections/defects/defects.component.ts +++ b/src/app/forms/custom-sections/defects/defects.component.ts @@ -1,6 +1,4 @@ -import { - Component, EventEmitter, Input, OnDestroy, OnInit, Output, -} from '@angular/core'; +import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; import { CustomFormArray, CustomFormGroup, FormNode } from '@forms/services/dynamic-form.types'; import { Defect } from '@models/defects/defect.model'; @@ -9,59 +7,62 @@ import { TestResultModel } from '@models/test-results/test-result.model'; import { Subscription, debounceTime } from 'rxjs'; @Component({ - selector: 'app-defects[defects][template]', - templateUrl: './defects.component.html', + selector: 'app-defects[defects][template]', + templateUrl: './defects.component.html', }) export class DefectsComponent implements OnInit, OnDestroy { - @Input() isEditing = false; - @Input() defects!: Defect[] | null; - @Input() template!: FormNode; - @Input() data: Partial = {}; + @Input() isEditing = false; + @Input() defects!: Defect[] | null; + @Input() template!: FormNode; + @Input() data: Partial = {}; - @Output() formChange = new EventEmitter(); + @Output() formChange = new EventEmitter(); - public form!: CustomFormGroup; - private formSubscription = new Subscription(); - private defectsFormArray?: CustomFormArray; + public form!: CustomFormGroup; + private formSubscription = new Subscription(); + private defectsFormArray?: CustomFormArray; - constructor(private dfs: DynamicFormService) {} + constructor(private dfs: DynamicFormService) {} - ngOnInit(): void { - this.form = this.dfs.createForm(this.template, this.data) as CustomFormGroup; - this.formSubscription = this.form.cleanValueChanges.pipe(debounceTime(400)).subscribe((event) => { - this.formChange.emit(event); - }); - } + ngOnInit(): void { + this.form = this.dfs.createForm(this.template, this.data) as CustomFormGroup; + this.formSubscription = this.form.cleanValueChanges.pipe(debounceTime(400)).subscribe((event) => { + this.formChange.emit(event); + }); + } - ngOnDestroy(): void { - this.formSubscription.unsubscribe(); - } + ngOnDestroy(): void { + this.formSubscription.unsubscribe(); + } - get defectsForm(): CustomFormArray { - if (!this.defectsFormArray) { - this.defectsFormArray = this.form?.get(['testTypes', '0', 'defects']) as CustomFormArray; - } - return this.defectsFormArray; - } + get defectsForm(): CustomFormArray { + if (!this.defectsFormArray) { + this.defectsFormArray = this.form?.get(['testTypes', '0', 'defects']) as CustomFormArray; + } + return this.defectsFormArray; + } - get defectCount(): number { - return this.defectsForm?.controls.length; - } + get defectCount(): number { + return this.defectsForm?.controls.length; + } - get testDefects(): TestResultDefect[] { - return this.defectsForm.controls.map((control) => { - const formGroup = control as CustomFormGroup; - return formGroup.getCleanValue(formGroup) as TestResultDefect; - }); - } + get testDefects(): TestResultDefect[] { + return this.defectsForm.controls.map((control) => { + const formGroup = control as CustomFormGroup; + return formGroup.getCleanValue(formGroup) as TestResultDefect; + }); + } - categoryColor(category: CategoryColorKey): CategoryColor { - return categoryColors[`${category}`]; - } + categoryColor(category: CategoryColorKey): CategoryColor { + return categoryColors[`${category}`]; + } } const categoryColors = { - major: 'orange', minor: 'yellow', dangerous: 'red', advisory: 'blue', + major: 'orange', + minor: 'yellow', + dangerous: 'red', + advisory: 'blue', } as const; type CategoryColors = typeof categoryColors; diff --git a/src/app/forms/custom-sections/dimensions/dimensions.component.spec.ts b/src/app/forms/custom-sections/dimensions/dimensions.component.spec.ts index 1e57c7070f..3d0817b91b 100644 --- a/src/app/forms/custom-sections/dimensions/dimensions.component.spec.ts +++ b/src/app/forms/custom-sections/dimensions/dimensions.component.spec.ts @@ -10,23 +10,23 @@ import { initialAppState } from '@store/index'; import { DimensionsComponent } from './dimensions.component'; describe('DimensionsComponent', () => { - let component: DimensionsComponent; - let fixture: ComponentFixture; + let component: DimensionsComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [DimensionsComponent], - imports: [DynamicFormsModule, FormsModule, ReactiveFormsModule, HttpClientTestingModule, RouterTestingModule], - providers: [provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [DimensionsComponent], + imports: [DynamicFormsModule, FormsModule, ReactiveFormsModule, HttpClientTestingModule, RouterTestingModule], + providers: [provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(DimensionsComponent); - component = fixture.componentInstance; - component.techRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'hgv'>; - }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(DimensionsComponent); + component = fixture.componentInstance; + component.techRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'hgv'>; + }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/custom-sections/dimensions/dimensions.component.ts b/src/app/forms/custom-sections/dimensions/dimensions.component.ts index 1c0dfb467a..79dc58a25a 100644 --- a/src/app/forms/custom-sections/dimensions/dimensions.component.ts +++ b/src/app/forms/custom-sections/dimensions/dimensions.component.ts @@ -1,10 +1,12 @@ -import { - Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, -} from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; import { - CustomFormArray, CustomFormGroup, FormNode, FormNodeEditTypes, FormNodeWidth, + CustomFormArray, + CustomFormGroup, + FormNode, + FormNodeEditTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; import { HgvDimensionsTemplate } from '@forms/templates/hgv/hgv-dimensions.template'; import { PsvDimensionsTemplate } from '@forms/templates/psv/psv-dimensions.template'; @@ -13,86 +15,88 @@ import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { Subject, debounceTime, takeUntil } from 'rxjs'; @Component({ - selector: 'app-dimensions', - templateUrl: './dimensions.component.html', - styleUrls: ['./dimensions.component.scss'], + selector: 'app-dimensions', + templateUrl: './dimensions.component.html', + styleUrls: ['./dimensions.component.scss'], }) export class DimensionsComponent implements OnInit, OnChanges, OnDestroy { - @Input() techRecord!: TechRecordType<'trl'> | TechRecordType<'psv'> | TechRecordType<'hgv'>; - @Input() isEditing = false; - @Output() formChange = new EventEmitter(); - - form!: CustomFormGroup; - - private destroy$ = new Subject(); - - constructor(private dfs: DynamicFormService) {} - - ngOnInit(): void { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.form = this.dfs.createForm(this.template!, this.techRecord) as CustomFormGroup; - - this.form.cleanValueChanges.pipe(debounceTime(400), takeUntil(this.destroy$)).subscribe((e) => this.formChange.emit(e)); - } - - ngOnChanges(changes: SimpleChanges): void { - const { techRecord } = changes; - - if (this.form && techRecord?.currentValue && techRecord.currentValue !== techRecord.previousValue) { - this.form.patchValue(techRecord.currentValue, { emitEvent: false }); - } - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - get template(): FormNode | undefined { - switch (this.techRecord.techRecord_vehicleType) { - case VehicleTypes.PSV: - return PsvDimensionsTemplate; - case VehicleTypes.HGV: - return HgvDimensionsTemplate; - case VehicleTypes.TRL: - return TrlDimensionsTemplate; - default: - return undefined; - } - } - - get isPsv(): boolean { - return this.techRecord.techRecord_vehicleType === VehicleTypes.PSV; - } - - get isTrl(): boolean { - return this.techRecord.techRecord_vehicleType === VehicleTypes.TRL; - } - - get widths(): typeof FormNodeWidth { - return FormNodeWidth; - } - - get types(): typeof FormNodeEditTypes { - return FormNodeEditTypes; - } - - get dimensions(): CustomFormGroup { - return this.form.get(['dimensions']) as CustomFormGroup; - } - - get hasAxleSpacings(): boolean { - if (this.techRecord.techRecord_vehicleType === 'psv') { - return false; - } - return !!this.techRecord.techRecord_dimensions_axleSpacing?.length; - } - - get axleSpacings(): CustomFormArray { - return this.form.get(['techRecord_dimensions_axleSpacing']) as CustomFormArray; - } - - getAxleSpacing(i: number): CustomFormGroup { - return this.form.get(['techRecord_dimensions_axleSpacing', i]) as CustomFormGroup; - } + @Input() techRecord!: TechRecordType<'trl'> | TechRecordType<'psv'> | TechRecordType<'hgv'>; + @Input() isEditing = false; + @Output() formChange = new EventEmitter(); + + form!: CustomFormGroup; + + private destroy$ = new Subject(); + + constructor(private dfs: DynamicFormService) {} + + ngOnInit(): void { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + this.form = this.dfs.createForm(this.template!, this.techRecord) as CustomFormGroup; + + this.form.cleanValueChanges + .pipe(debounceTime(400), takeUntil(this.destroy$)) + .subscribe((e) => this.formChange.emit(e)); + } + + ngOnChanges(changes: SimpleChanges): void { + const { techRecord } = changes; + + if (this.form && techRecord?.currentValue && techRecord.currentValue !== techRecord.previousValue) { + this.form.patchValue(techRecord.currentValue, { emitEvent: false }); + } + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + get template(): FormNode | undefined { + switch (this.techRecord.techRecord_vehicleType) { + case VehicleTypes.PSV: + return PsvDimensionsTemplate; + case VehicleTypes.HGV: + return HgvDimensionsTemplate; + case VehicleTypes.TRL: + return TrlDimensionsTemplate; + default: + return undefined; + } + } + + get isPsv(): boolean { + return this.techRecord.techRecord_vehicleType === VehicleTypes.PSV; + } + + get isTrl(): boolean { + return this.techRecord.techRecord_vehicleType === VehicleTypes.TRL; + } + + get widths(): typeof FormNodeWidth { + return FormNodeWidth; + } + + get types(): typeof FormNodeEditTypes { + return FormNodeEditTypes; + } + + get dimensions(): CustomFormGroup { + return this.form.get(['dimensions']) as CustomFormGroup; + } + + get hasAxleSpacings(): boolean { + if (this.techRecord.techRecord_vehicleType === 'psv') { + return false; + } + return !!this.techRecord.techRecord_dimensions_axleSpacing?.length; + } + + get axleSpacings(): CustomFormArray { + return this.form.get(['techRecord_dimensions_axleSpacing']) as CustomFormArray; + } + + getAxleSpacing(i: number): CustomFormGroup { + return this.form.get(['techRecord_dimensions_axleSpacing', i]) as CustomFormGroup; + } } diff --git a/src/app/forms/custom-sections/letters/letters.component.spec.ts b/src/app/forms/custom-sections/letters/letters.component.spec.ts index b561d57279..564d15b5ab 100644 --- a/src/app/forms/custom-sections/letters/letters.component.spec.ts +++ b/src/app/forms/custom-sections/letters/letters.component.spec.ts @@ -19,110 +19,118 @@ import { of } from 'rxjs'; import { LettersComponent } from './letters.component'; const mockTechRecordService = { - techRecordHistory$: of([{ - vin: 'test', - techRecord_statusCode: 'current', - techRecord_vehicleType: 'trl', - createdTimestamp: '12345', - systemNumber: '123', - techRecord_manufactureYear: 2021, - }] as TechRecordSearchSchema[]), + techRecordHistory$: of([ + { + vin: 'test', + techRecord_statusCode: 'current', + techRecord_vehicleType: 'trl', + createdTimestamp: '12345', + systemNumber: '123', + techRecord_manufactureYear: 2021, + }, + ] as TechRecordSearchSchema[]), }; describe('LettersComponent', () => { - let component: LettersComponent; - let fixture: ComponentFixture; + let component: LettersComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [DynamicFormsModule, SharedModule, StoreModule.forRoot({}), HttpClientTestingModule, RouterModule.forRoot([]), RouterTestingModule], - declarations: [LettersComponent], - providers: [ - provideMockStore({ initialState: initialAppState }), - { - provide: UserService, - useValue: { - roles$: of([Roles.TechRecordAmend]), - }, - }, - { - provide: ActivatedRoute, - useValue: { - useValue: { params: of([{ id: 1 }]) }, - }, - }, - { - provide: APP_BASE_HREF, - useValue: '/', - }, - { - provide: TechnicalRecordService, - useValue: mockTechRecordService, - }, - ], - }).compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + DynamicFormsModule, + SharedModule, + StoreModule.forRoot({}), + HttpClientTestingModule, + RouterModule.forRoot([]), + RouterTestingModule, + ], + declarations: [LettersComponent], + providers: [ + provideMockStore({ initialState: initialAppState }), + { + provide: UserService, + useValue: { + roles$: of([Roles.TechRecordAmend]), + }, + }, + { + provide: ActivatedRoute, + useValue: { + useValue: { params: of([{ id: 1 }]) }, + }, + }, + { + provide: APP_BASE_HREF, + useValue: '/', + }, + { + provide: TechnicalRecordService, + useValue: mockTechRecordService, + }, + ], + }).compileComponents(); + }); - }); + beforeEach(() => { + fixture = TestBed.createComponent(LettersComponent); + component = fixture.componentInstance; + component.techRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_statusCode: 'current', + } as TechRecordType<'trl'>; + fixture.detectChanges(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(LettersComponent); - component = fixture.componentInstance; - component.techRecord = { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_statusCode: 'current', - } as TechRecordType<'trl'>; - fixture.detectChanges(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); + describe('eligibleForLetter', () => { + it('should return true if the approval type is valid', () => { + (component.techRecord as TechRecordType<'trl'>).techRecord_approvalType = ApprovalType.EU_WVTA_23_ON; + expect(component.eligibleForLetter).toBeTruthy(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); - describe('eligibleForLetter', () => { - it('should return true if the approval type is valid', () => { - (component.techRecord as TechRecordType<'trl'>).techRecord_approvalType = ApprovalType.EU_WVTA_23_ON; - expect(component.eligibleForLetter).toBeTruthy(); - }); + it('should return false if the approval type is valid', () => { + (component.techRecord as TechRecordType<'trl'>).techRecord_approvalType = ApprovalType.NTA; + expect(component.eligibleForLetter).toBeFalsy(); + }); - it('should return false if the approval type is valid', () => { - (component.techRecord as TechRecordType<'trl'>).techRecord_approvalType = ApprovalType.NTA; - expect(component.eligibleForLetter).toBeFalsy(); - }); + it('should return false if the statuscode is archived', () => { + (component.techRecord as TechRecordType<'trl'>).techRecord_approvalType = ApprovalType.GB_WVTA; + (component.techRecord as TechRecordType<'trl'>).techRecord_statusCode = StatusCodes.ARCHIVED; + expect(component.eligibleForLetter).toBeFalsy(); + }); + }); - it('should return false if the statuscode is archived', () => { - (component.techRecord as TechRecordType<'trl'>).techRecord_approvalType = ApprovalType.GB_WVTA; - (component.techRecord as TechRecordType<'trl'>).techRecord_statusCode = StatusCodes.ARCHIVED; - expect(component.eligibleForLetter).toBeFalsy(); - }); - }); + describe('checkRecordHistoryHasCurrent', () => { + it('should return false if the current technical record history has current status', () => { + expect(component.hasCurrent).toBeFalsy(); + }); - describe('checkRecordHistoryHasCurrent', () => { - it('should return false if the current technical record history has current status', () => { - expect(component.hasCurrent).toBeFalsy(); - }); + it('should return true if the provisional technical record history has current status', () => { + (component.techRecord as TechRecordType<'trl'>).techRecord_statusCode = 'provisional'; + component.ngOnInit(); + expect(component.hasCurrent).toBeTruthy(); + }); + }); - it('should return true if the provisional technical record history has current status', () => { - (component.techRecord as TechRecordType<'trl'>).techRecord_statusCode = 'provisional'; - component.ngOnInit(); - expect(component.hasCurrent).toBeTruthy(); - }); - }); + describe('letter', () => { + it('should return the letter if it exists', () => { + (component.techRecord as TechRecordType<'trl'>).techRecord_letterOfAuth_letterType = 'trailer acceptance'; + (component.techRecord as TechRecordType<'trl'>).techRecord_letterOfAuth_paragraphId = 3; + (component.techRecord as TechRecordType<'trl'>).techRecord_letterOfAuth_letterIssuer = 'issuer'; + expect(component.letter).toBeTruthy(); + expect(component.letter?.paragraphId).toBe(3); + expect(component.letter?.letterIssuer).toBe('issuer'); + }); - describe('letter', () => { - it('should return the letter if it exists', () => { - (component.techRecord as TechRecordType<'trl'>).techRecord_letterOfAuth_letterType = 'trailer acceptance'; - (component.techRecord as TechRecordType<'trl'>).techRecord_letterOfAuth_paragraphId = 3; - (component.techRecord as TechRecordType<'trl'>).techRecord_letterOfAuth_letterIssuer = 'issuer'; - expect(component.letter).toBeTruthy(); - expect(component.letter?.paragraphId).toBe(3); - expect(component.letter?.letterIssuer).toBe('issuer'); - }); + it('should return undefined if it does not exist', () => { + (component.techRecord as TechRecordType<'trl'>).techRecord_letterOfAuth_letterType = undefined; - it('should return undefined if it does not exist', () => { - (component.techRecord as TechRecordType<'trl'>).techRecord_letterOfAuth_letterType = undefined; - - expect(component.letter).toBeUndefined(); - }); - }); + expect(component.letter).toBeUndefined(); + }); + }); }); diff --git a/src/app/forms/custom-sections/letters/letters.component.ts b/src/app/forms/custom-sections/letters/letters.component.ts index c47017ec4a..ceb21c8d60 100644 --- a/src/app/forms/custom-sections/letters/letters.component.ts +++ b/src/app/forms/custom-sections/letters/letters.component.ts @@ -1,8 +1,6 @@ /* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ import { ViewportScroller } from '@angular/common'; -import { - Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, -} from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; import { ParagraphIds } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/trl/complete'; @@ -16,141 +14,147 @@ import { LettersIntoAuthApprovalType, LettersOfAuth, StatusCodes } from '@models import { Store } from '@ngrx/store'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { updateScrollPosition } from '@store/technical-records'; -import { - ReplaySubject, Subscription, debounceTime, takeUntil, -} from 'rxjs'; +import { ReplaySubject, Subscription, debounceTime, takeUntil } from 'rxjs'; @Component({ - selector: 'app-letters[techRecord]', - templateUrl: './letters.component.html', - styleUrls: ['./letters.component.scss'], + selector: 'app-letters[techRecord]', + templateUrl: './letters.component.html', + styleUrls: ['./letters.component.scss'], }) export class LettersComponent implements OnInit, OnDestroy, OnChanges { - @Input() techRecord?: TechRecordType<'trl'>; - @Input() isEditing = false; - - @Output() formChange = new EventEmitter(); - - form!: CustomFormGroup; - - hasCurrent = false; - - private formSubscription = new Subscription(); - private destroy$ = new ReplaySubject(1); - - constructor( - private dynamicFormService: DynamicFormService, - private techRecordService: TechnicalRecordService, - private viewportScroller: ViewportScroller, - private router: Router, - private route: ActivatedRoute, - private store: Store, - ) {} - - ngOnInit(): void { - this.form = this.dynamicFormService.createForm(LettersTemplate, this.techRecord) as CustomFormGroup; - this.formSubscription = this.form.cleanValueChanges.pipe(debounceTime(400)).subscribe((event) => this.formChange.emit(event)); - this.checkForCurrentRecordInHistory(); - } - - ngOnChanges(): void { - if (this.techRecord) { - this.form?.patchValue(this.techRecord, { emitEvent: false }); - } - } - - ngOnDestroy(): void { - this.formSubscription.unsubscribe(); - this.destroy$.next(true); - this.destroy$.unsubscribe(); - } - - checkForCurrentRecordInHistory() { - this.techRecordService.techRecordHistory$.pipe(takeUntil(this.destroy$)).subscribe((historyArray: TechRecordSearchSchema[] | undefined) => { - historyArray?.forEach((history: TechRecordSearchSchema) => { - if (history.techRecord_statusCode === StatusCodes.CURRENT - && this.techRecord?.techRecord_statusCode === StatusCodes.PROVISIONAL) { - this.hasCurrent = true; - } - }); - }); - } - - get roles(): typeof Roles { - return Roles; - } - - get types(): typeof FormNodeEditTypes { - return FormNodeEditTypes; - } - - get letter(): LettersOfAuth | undefined { - return this.techRecord?.techRecord_letterOfAuth_letterType - ? { - letterType: this.techRecord?.techRecord_letterOfAuth_letterType, - paragraphId: this.techRecord?.techRecord_letterOfAuth_paragraphId as ParagraphIds, - letterIssuer: this.techRecord?.techRecord_letterOfAuth_letterIssuer as string, - letterDateRequested: this.techRecord?.techRecord_letterOfAuth_letterDateRequested as string, - letterContents: '', - } - : undefined; - } - - get eligibleForLetter(): boolean { - const isArchivedTechRecord = this.techRecord?.techRecord_statusCode === StatusCodes.ARCHIVED; - return this.correctApprovalType && !isArchivedTechRecord && !this.isEditing && !this.hasCurrent; - } - - get reasonForIneligibility(): string { - if (this.isEditing) { - return 'This section is not available when amending or creating a technical record.'; - } - - if (this.techRecord?.techRecord_statusCode === StatusCodes.PROVISIONAL) { - if (this.hasCurrent) { - // eslint-disable-next-line max-len - return 'Generating letters is not applicable to provisional records, where a current record also exists for a vehicle. Open the current record to generate letters.'; - } - } else if (this.techRecord?.techRecord_statusCode === StatusCodes.ARCHIVED) { - return 'Generating letters is not applicable to archived technical records.'; - } - - if (!this.correctApprovalType) { - return 'This trailer does not have the right approval type to be eligible for a letter of authorisation.'; - } - - return ''; - } - - get correctApprovalType(): boolean { - return ( - !!this.techRecord?.techRecord_approvalType - && (Object.values(LettersIntoAuthApprovalType) as string[]).includes(this.techRecord.techRecord_approvalType.valueOf()) - ); - } - - get documentParams(): Map { - if (!this.techRecord) { - throw new Error('Could not find vehicle record associated with this technical record.'); - } - return new Map([ - ['systemNumber', (this.techRecord as TechRecordTypeVehicleVerb<'trl', 'get'>)?.systemNumber], - ['vinNumber', this.techRecord?.vin], - ]); - } - - get fileName(): string { - if (!this.letter) { - return ''; - } - if (!this.techRecord) { - return ''; - } - return `letter_${(this.techRecord as TechRecordTypeVehicleVerb<'trl', 'get'>).systemNumber}_${this.techRecord.vin}`; - } - - generateLetter() { - this.store.dispatch(updateScrollPosition({ position: this.viewportScroller.getScrollPosition() })); - void this.router.navigate(['generate-letter'], { relativeTo: this.route }); - } + @Input() techRecord?: TechRecordType<'trl'>; + @Input() isEditing = false; + + @Output() formChange = new EventEmitter(); + + form!: CustomFormGroup; + + hasCurrent = false; + + private formSubscription = new Subscription(); + private destroy$ = new ReplaySubject(1); + + constructor( + private dynamicFormService: DynamicFormService, + private techRecordService: TechnicalRecordService, + private viewportScroller: ViewportScroller, + private router: Router, + private route: ActivatedRoute, + private store: Store + ) {} + + ngOnInit(): void { + this.form = this.dynamicFormService.createForm(LettersTemplate, this.techRecord) as CustomFormGroup; + this.formSubscription = this.form.cleanValueChanges + .pipe(debounceTime(400)) + .subscribe((event) => this.formChange.emit(event)); + this.checkForCurrentRecordInHistory(); + } + + ngOnChanges(): void { + if (this.techRecord) { + this.form?.patchValue(this.techRecord, { emitEvent: false }); + } + } + + ngOnDestroy(): void { + this.formSubscription.unsubscribe(); + this.destroy$.next(true); + this.destroy$.unsubscribe(); + } + + checkForCurrentRecordInHistory() { + this.techRecordService.techRecordHistory$ + .pipe(takeUntil(this.destroy$)) + .subscribe((historyArray: TechRecordSearchSchema[] | undefined) => { + historyArray?.forEach((history: TechRecordSearchSchema) => { + if ( + history.techRecord_statusCode === StatusCodes.CURRENT && + this.techRecord?.techRecord_statusCode === StatusCodes.PROVISIONAL + ) { + this.hasCurrent = true; + } + }); + }); + } + + get roles(): typeof Roles { + return Roles; + } + + get types(): typeof FormNodeEditTypes { + return FormNodeEditTypes; + } + + get letter(): LettersOfAuth | undefined { + return this.techRecord?.techRecord_letterOfAuth_letterType + ? { + letterType: this.techRecord?.techRecord_letterOfAuth_letterType, + paragraphId: this.techRecord?.techRecord_letterOfAuth_paragraphId as ParagraphIds, + letterIssuer: this.techRecord?.techRecord_letterOfAuth_letterIssuer as string, + letterDateRequested: this.techRecord?.techRecord_letterOfAuth_letterDateRequested as string, + letterContents: '', + } + : undefined; + } + + get eligibleForLetter(): boolean { + const isArchivedTechRecord = this.techRecord?.techRecord_statusCode === StatusCodes.ARCHIVED; + return this.correctApprovalType && !isArchivedTechRecord && !this.isEditing && !this.hasCurrent; + } + + get reasonForIneligibility(): string { + if (this.isEditing) { + return 'This section is not available when amending or creating a technical record.'; + } + + if (this.techRecord?.techRecord_statusCode === StatusCodes.PROVISIONAL) { + if (this.hasCurrent) { + // eslint-disable-next-line max-len + return 'Generating letters is not applicable to provisional records, where a current record also exists for a vehicle. Open the current record to generate letters.'; + } + } else if (this.techRecord?.techRecord_statusCode === StatusCodes.ARCHIVED) { + return 'Generating letters is not applicable to archived technical records.'; + } + + if (!this.correctApprovalType) { + return 'This trailer does not have the right approval type to be eligible for a letter of authorisation.'; + } + + return ''; + } + + get correctApprovalType(): boolean { + return ( + !!this.techRecord?.techRecord_approvalType && + (Object.values(LettersIntoAuthApprovalType) as string[]).includes( + this.techRecord.techRecord_approvalType.valueOf() + ) + ); + } + + get documentParams(): Map { + if (!this.techRecord) { + throw new Error('Could not find vehicle record associated with this technical record.'); + } + return new Map([ + ['systemNumber', (this.techRecord as TechRecordTypeVehicleVerb<'trl', 'get'>)?.systemNumber], + ['vinNumber', this.techRecord?.vin], + ]); + } + + get fileName(): string { + if (!this.letter) { + return ''; + } + if (!this.techRecord) { + return ''; + } + return `letter_${(this.techRecord as TechRecordTypeVehicleVerb<'trl', 'get'>).systemNumber}_${this.techRecord.vin}`; + } + + generateLetter() { + this.store.dispatch(updateScrollPosition({ position: this.viewportScroller.getScrollPosition() })); + void this.router.navigate(['generate-letter'], { relativeTo: this.route }); + } } diff --git a/src/app/forms/custom-sections/modified-weights/modified-weights.component.spec.ts b/src/app/forms/custom-sections/modified-weights/modified-weights.component.spec.ts index ef47f6be92..d904fe6aec 100644 --- a/src/app/forms/custom-sections/modified-weights/modified-weights.component.spec.ts +++ b/src/app/forms/custom-sections/modified-weights/modified-weights.component.spec.ts @@ -9,163 +9,163 @@ import { initialAppState } from '@store/index'; import { ModifiedWeightsComponent } from './modified-weights.component'; describe('ModifiedWeightsComponent', () => { - let component: ModifiedWeightsComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ModifiedWeightsComponent], - imports: [HttpClientTestingModule, RouterTestingModule], - providers: [provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - - fixture = TestBed.createComponent(ModifiedWeightsComponent); - component = fixture.componentInstance; - component.changes = {}; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('ngOnInit', () => { - it('Vehicle type: PSV, Axle changed: Gross. Should determine that only the PSV gross axle have changed', () => { - component.vehicleType = VehicleTypes.PSV; - component.changes = { - techRecord_grossKerbWeight: 1, - techRecord_grossLadenWeight: 3, - techRecord_grossGbWeight: 4, - techRecord_grossDesignWeight: 5, - }; - fixture.detectChanges(); - component.ngOnInit(); - - expect(component.psvGrossAxleChanged).toBe(true); - expect(component.hgvGrossAxleChanged).toBe(false); - expect(component.trlGrossAxleChanged).toBe(false); - expect(component.hgvTrainAxleChanged).toBe(false); - expect(component.psvTrainAxleChanged).toBe(false); - expect(component.maxTrainAxleChanged).toBe(false); - }); - - it('Vehicle type: HGV, Axle changed: Gross. Should determine that only the PSV gross axle have changed', () => { - component.vehicleType = VehicleTypes.HGV; - component.changes = { - techRecord_grossGbWeight: 1, - techRecord_grossEecWeight: 2, - techRecord_grossDesignWeight: 3, - }; - - fixture.detectChanges(); - component.ngOnInit(); - - expect(component.psvGrossAxleChanged).toBe(false); - expect(component.hgvGrossAxleChanged).toBe(true); - expect(component.trlGrossAxleChanged).toBe(false); - expect(component.hgvTrainAxleChanged).toBe(false); - expect(component.psvTrainAxleChanged).toBe(false); - expect(component.maxTrainAxleChanged).toBe(false); - }); - - it('Vehicle type: TRL, Axle changed: Gross. Should determine that only the HGV gross axle have changed', () => { - component.vehicleType = VehicleTypes.TRL; - component.changes = { - techRecord_grossGbWeight: 1, - techRecord_grossEecWeight: 2, - techRecord_grossDesignWeight: 3, - }; - fixture.detectChanges(); - component.ngOnInit(); - - expect(component.psvGrossAxleChanged).toBe(false); - expect(component.hgvGrossAxleChanged).toBe(false); - expect(component.trlGrossAxleChanged).toBe(true); - expect(component.hgvTrainAxleChanged).toBe(false); - expect(component.psvTrainAxleChanged).toBe(false); - expect(component.maxTrainAxleChanged).toBe(false); - }); - - it('Vehicle type: HGV, Axle changed: Gross. Should determine that only the HGV gross axle have changed', () => { - component.vehicleType = VehicleTypes.HGV; - component.changes = { - techRecord_trainGbWeight: 1, - techRecord_trainEecWeight: 2, - techRecord_trainDesignWeight: 3, - }; - - fixture.detectChanges(); - component.ngOnInit(); - - expect(component.psvGrossAxleChanged).toBe(false); - expect(component.hgvGrossAxleChanged).toBe(false); - expect(component.trlGrossAxleChanged).toBe(false); - expect(component.hgvTrainAxleChanged).toBe(true); - expect(component.psvTrainAxleChanged).toBe(false); - expect(component.maxTrainAxleChanged).toBe(false); - }); - - it('Vehicle type: PSV, Axle changed: Train. Should determine that only the PSV train axle have changed', () => { - component.vehicleType = VehicleTypes.PSV; - component.changes = { - techRecord_trainDesignWeight: 1, - techRecord_maxTrainGbWeight: 3, - }; - - fixture.detectChanges(); - component.ngOnInit(); - - expect(component.psvGrossAxleChanged).toBe(false); - expect(component.hgvGrossAxleChanged).toBe(false); - expect(component.trlGrossAxleChanged).toBe(false); - expect(component.hgvTrainAxleChanged).toBe(false); - expect(component.psvTrainAxleChanged).toBe(true); - expect(component.maxTrainAxleChanged).toBe(false); - }); - - it('Vehicle type: HGV, Axle changed: Max Train. Should determine that only the HGV max train axle have changed', () => { - component.vehicleType = VehicleTypes.HGV; - component.changes = { - techRecord_maxTrainGbWeight: 1, - techRecord_maxTrainEecWeight: 2, - techRecord_maxTrainDesignWeight: 3, - }; - - fixture.detectChanges(); - component.ngOnInit(); - - expect(component.psvGrossAxleChanged).toBe(false); - expect(component.hgvGrossAxleChanged).toBe(false); - expect(component.trlGrossAxleChanged).toBe(false); - expect(component.hgvTrainAxleChanged).toBe(false); - expect(component.psvTrainAxleChanged).toBe(false); - expect(component.maxTrainAxleChanged).toBe(true); - }); - }); - - describe('getAxleTemplate', () => { - it('should return the correct template for the vehicle type', () => { - component.vehicleType = VehicleTypes.HGV; - fixture.detectChanges(); - - const getAxleTemplateSpy = jest.spyOn(component, 'getAxleTemplate'); - const template = component.getAxleTemplate(); - - expect(getAxleTemplateSpy).toHaveBeenCalled(); - expect(template).toBeDefined(); - expect(template).toBeInstanceOf(Array); - }); - - it('should return undefined, as an invalid vehicle type has been provided', () => { - component.vehicleType = '' as VehicleTypes; - fixture.detectChanges(); - - const getAxleTemplateSpy = jest.spyOn(component, 'getAxleTemplate'); - jest.spyOn(vehicleTemplateMap, 'get').mockReturnValue(undefined); - const template = component.getAxleTemplate(); - - expect(getAxleTemplateSpy).toHaveBeenCalled(); - expect(template).toBeUndefined(); - }); - }); + let component: ModifiedWeightsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ModifiedWeightsComponent], + imports: [HttpClientTestingModule, RouterTestingModule], + providers: [provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + + fixture = TestBed.createComponent(ModifiedWeightsComponent); + component = fixture.componentInstance; + component.changes = {}; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('ngOnInit', () => { + it('Vehicle type: PSV, Axle changed: Gross. Should determine that only the PSV gross axle have changed', () => { + component.vehicleType = VehicleTypes.PSV; + component.changes = { + techRecord_grossKerbWeight: 1, + techRecord_grossLadenWeight: 3, + techRecord_grossGbWeight: 4, + techRecord_grossDesignWeight: 5, + }; + fixture.detectChanges(); + component.ngOnInit(); + + expect(component.psvGrossAxleChanged).toBe(true); + expect(component.hgvGrossAxleChanged).toBe(false); + expect(component.trlGrossAxleChanged).toBe(false); + expect(component.hgvTrainAxleChanged).toBe(false); + expect(component.psvTrainAxleChanged).toBe(false); + expect(component.maxTrainAxleChanged).toBe(false); + }); + + it('Vehicle type: HGV, Axle changed: Gross. Should determine that only the PSV gross axle have changed', () => { + component.vehicleType = VehicleTypes.HGV; + component.changes = { + techRecord_grossGbWeight: 1, + techRecord_grossEecWeight: 2, + techRecord_grossDesignWeight: 3, + }; + + fixture.detectChanges(); + component.ngOnInit(); + + expect(component.psvGrossAxleChanged).toBe(false); + expect(component.hgvGrossAxleChanged).toBe(true); + expect(component.trlGrossAxleChanged).toBe(false); + expect(component.hgvTrainAxleChanged).toBe(false); + expect(component.psvTrainAxleChanged).toBe(false); + expect(component.maxTrainAxleChanged).toBe(false); + }); + + it('Vehicle type: TRL, Axle changed: Gross. Should determine that only the HGV gross axle have changed', () => { + component.vehicleType = VehicleTypes.TRL; + component.changes = { + techRecord_grossGbWeight: 1, + techRecord_grossEecWeight: 2, + techRecord_grossDesignWeight: 3, + }; + fixture.detectChanges(); + component.ngOnInit(); + + expect(component.psvGrossAxleChanged).toBe(false); + expect(component.hgvGrossAxleChanged).toBe(false); + expect(component.trlGrossAxleChanged).toBe(true); + expect(component.hgvTrainAxleChanged).toBe(false); + expect(component.psvTrainAxleChanged).toBe(false); + expect(component.maxTrainAxleChanged).toBe(false); + }); + + it('Vehicle type: HGV, Axle changed: Gross. Should determine that only the HGV gross axle have changed', () => { + component.vehicleType = VehicleTypes.HGV; + component.changes = { + techRecord_trainGbWeight: 1, + techRecord_trainEecWeight: 2, + techRecord_trainDesignWeight: 3, + }; + + fixture.detectChanges(); + component.ngOnInit(); + + expect(component.psvGrossAxleChanged).toBe(false); + expect(component.hgvGrossAxleChanged).toBe(false); + expect(component.trlGrossAxleChanged).toBe(false); + expect(component.hgvTrainAxleChanged).toBe(true); + expect(component.psvTrainAxleChanged).toBe(false); + expect(component.maxTrainAxleChanged).toBe(false); + }); + + it('Vehicle type: PSV, Axle changed: Train. Should determine that only the PSV train axle have changed', () => { + component.vehicleType = VehicleTypes.PSV; + component.changes = { + techRecord_trainDesignWeight: 1, + techRecord_maxTrainGbWeight: 3, + }; + + fixture.detectChanges(); + component.ngOnInit(); + + expect(component.psvGrossAxleChanged).toBe(false); + expect(component.hgvGrossAxleChanged).toBe(false); + expect(component.trlGrossAxleChanged).toBe(false); + expect(component.hgvTrainAxleChanged).toBe(false); + expect(component.psvTrainAxleChanged).toBe(true); + expect(component.maxTrainAxleChanged).toBe(false); + }); + + it('Vehicle type: HGV, Axle changed: Max Train. Should determine that only the HGV max train axle have changed', () => { + component.vehicleType = VehicleTypes.HGV; + component.changes = { + techRecord_maxTrainGbWeight: 1, + techRecord_maxTrainEecWeight: 2, + techRecord_maxTrainDesignWeight: 3, + }; + + fixture.detectChanges(); + component.ngOnInit(); + + expect(component.psvGrossAxleChanged).toBe(false); + expect(component.hgvGrossAxleChanged).toBe(false); + expect(component.trlGrossAxleChanged).toBe(false); + expect(component.hgvTrainAxleChanged).toBe(false); + expect(component.psvTrainAxleChanged).toBe(false); + expect(component.maxTrainAxleChanged).toBe(true); + }); + }); + + describe('getAxleTemplate', () => { + it('should return the correct template for the vehicle type', () => { + component.vehicleType = VehicleTypes.HGV; + fixture.detectChanges(); + + const getAxleTemplateSpy = jest.spyOn(component, 'getAxleTemplate'); + const template = component.getAxleTemplate(); + + expect(getAxleTemplateSpy).toHaveBeenCalled(); + expect(template).toBeDefined(); + expect(template).toBeInstanceOf(Array); + }); + + it('should return undefined, as an invalid vehicle type has been provided', () => { + component.vehicleType = '' as VehicleTypes; + fixture.detectChanges(); + + const getAxleTemplateSpy = jest.spyOn(component, 'getAxleTemplate'); + jest.spyOn(vehicleTemplateMap, 'get').mockReturnValue(undefined); + const template = component.getAxleTemplate(); + + expect(getAxleTemplateSpy).toHaveBeenCalled(); + expect(template).toBeUndefined(); + }); + }); }); diff --git a/src/app/forms/custom-sections/modified-weights/modified-weights.component.ts b/src/app/forms/custom-sections/modified-weights/modified-weights.component.ts index 2b760b8e69..10d73cb456 100644 --- a/src/app/forms/custom-sections/modified-weights/modified-weights.component.ts +++ b/src/app/forms/custom-sections/modified-weights/modified-weights.component.ts @@ -1,73 +1,83 @@ import { Component, Input, OnInit } from '@angular/core'; -import { TechRecordGETHGV, TechRecordGETPSV, TechRecordGETTRL } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb-vehicle-type'; +import { + TechRecordGETHGV, + TechRecordGETPSV, + TechRecordGETTRL, +} from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb-vehicle-type'; import { FormNode } from '@forms/services/dynamic-form.types'; import { vehicleTemplateMap } from '@forms/utils/tech-record-constants'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; @Component({ - selector: 'app-modified-weights', - templateUrl: './modified-weights.component.html', - styleUrls: ['./modified-weights.component.scss'], + selector: 'app-modified-weights', + templateUrl: './modified-weights.component.html', + styleUrls: ['./modified-weights.component.scss'], }) export class ModifiedWeightsComponent implements OnInit { - @Input() vehicleType!: VehicleTypes; - @Input() changes!: Partial; + @Input() vehicleType!: VehicleTypes; + @Input() changes!: Partial; - axleTemplate: FormNode[] | undefined; - psvGrossAxleChanged = false; - hgvGrossAxleChanged = false; - trlGrossAxleChanged = false; - hgvTrainAxleChanged = false; - psvTrainAxleChanged = false; - maxTrainAxleChanged = false; + axleTemplate: FormNode[] | undefined; + psvGrossAxleChanged = false; + hgvGrossAxleChanged = false; + trlGrossAxleChanged = false; + hgvTrainAxleChanged = false; + psvTrainAxleChanged = false; + maxTrainAxleChanged = false; - constructor(private readonly technicalRecordService: TechnicalRecordService) {} + constructor(private readonly technicalRecordService: TechnicalRecordService) {} - get isPSV(): boolean { - return this.vehicleType === VehicleTypes.PSV; - } + get isPSV(): boolean { + return this.vehicleType === VehicleTypes.PSV; + } - get isHGV(): boolean { - return this.vehicleType === VehicleTypes.HGV; - } + get isHGV(): boolean { + return this.vehicleType === VehicleTypes.HGV; + } - get isTRL(): boolean { - return this.vehicleType === VehicleTypes.TRL; - } + get isTRL(): boolean { + return this.vehicleType === VehicleTypes.TRL; + } - get psvChanges(): Partial | undefined { - return this.isPSV ? (this.changes as Partial) : undefined; - } + get psvChanges(): Partial | undefined { + return this.isPSV ? (this.changes as Partial) : undefined; + } - get hgvChanges(): Partial | undefined { - return this.isHGV ? (this.changes as Partial) : undefined; - } + get hgvChanges(): Partial | undefined { + return this.isHGV ? (this.changes as Partial) : undefined; + } - get trlChanges(): Partial | undefined { - return this.isTRL ? (this.changes as Partial) : undefined; - } + get trlChanges(): Partial | undefined { + return this.isTRL ? (this.changes as Partial) : undefined; + } - get hgvAndtrlGrossAxleChanged() { - return this.hgvGrossAxleChanged || this.trlGrossAxleChanged; - } + get hgvAndtrlGrossAxleChanged() { + return this.hgvGrossAxleChanged || this.trlGrossAxleChanged; + } - ngOnInit(): void { - this.axleTemplate = this.getAxleTemplate(); - this.psvGrossAxleChanged = this.isPSV && this.technicalRecordService.hasPsvGrossAxleChanged(this.changes as Partial); - this.hgvGrossAxleChanged = this.isHGV && this.technicalRecordService.hasHgvGrossAxleChanged(this.changes as Partial); - this.trlGrossAxleChanged = this.isTRL && this.technicalRecordService.hasTrlGrossAxleChanged(this.changes as Partial); - this.hgvTrainAxleChanged = this.isHGV && this.technicalRecordService.hasHgvTrainAxleChanged(this.changes as Partial); - this.psvTrainAxleChanged = this.isPSV && this.technicalRecordService.hasPsvTrainAxleChanged(this.changes as Partial); - this.maxTrainAxleChanged = this.isHGV && this.technicalRecordService.hasMaxTrainAxleChanged(this.changes as Partial); - } + ngOnInit(): void { + this.axleTemplate = this.getAxleTemplate(); + this.psvGrossAxleChanged = + this.isPSV && this.technicalRecordService.hasPsvGrossAxleChanged(this.changes as Partial); + this.hgvGrossAxleChanged = + this.isHGV && this.technicalRecordService.hasHgvGrossAxleChanged(this.changes as Partial); + this.trlGrossAxleChanged = + this.isTRL && this.technicalRecordService.hasTrlGrossAxleChanged(this.changes as Partial); + this.hgvTrainAxleChanged = + this.isHGV && this.technicalRecordService.hasHgvTrainAxleChanged(this.changes as Partial); + this.psvTrainAxleChanged = + this.isPSV && this.technicalRecordService.hasPsvTrainAxleChanged(this.changes as Partial); + this.maxTrainAxleChanged = + this.isHGV && this.technicalRecordService.hasMaxTrainAxleChanged(this.changes as Partial); + } - getAxleTemplate(): FormNode[] | undefined { - return vehicleTemplateMap - .get(this.vehicleType) - ?.find((template) => template.name === 'weightsSection') - ?.children?.find((child) => child.name === 'techRecord_axles') - ?.children?.at(0) - ?.children?.filter((child) => child.name !== 'axleNumber'); - } + getAxleTemplate(): FormNode[] | undefined { + return vehicleTemplateMap + .get(this.vehicleType) + ?.find((template) => template.name === 'weightsSection') + ?.children?.find((child) => child.name === 'techRecord_axles') + ?.children?.at(0) + ?.children?.filter((child) => child.name !== 'axleNumber'); + } } diff --git a/src/app/forms/custom-sections/plates/plates.component.spec.ts b/src/app/forms/custom-sections/plates/plates.component.spec.ts index fa6e9feb40..ff51aa45a5 100644 --- a/src/app/forms/custom-sections/plates/plates.component.spec.ts +++ b/src/app/forms/custom-sections/plates/plates.component.spec.ts @@ -22,457 +22,514 @@ import { PlatesComponent } from './plates.component'; global.scrollTo = jest.fn(); describe('PlatesComponent', () => { - let component: PlatesComponent; - let fixture: ComponentFixture; - let router: Router; - let errorService: GlobalErrorService; - let store: MockStore; + let component: PlatesComponent; + let fixture: ComponentFixture; + let router: Router; + let errorService: GlobalErrorService; + let store: MockStore; - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [DynamicFormsModule, SharedModule, StoreModule.forRoot({}), HttpClientTestingModule, RouterModule.forRoot([]), RouterTestingModule], - declarations: [PlatesComponent], - providers: [ - provideMockStore({ initialState: initialAppState }), - { - provide: UserService, - useValue: { - roles$: of([Roles.TechRecordAmend]), - }, - }, - { - provide: ActivatedRoute, - useValue: { - useValue: { params: of([{ id: 1 }]) }, - }, - }, - { - provide: APP_BASE_HREF, - useValue: '/', - }, - GlobalErrorService, - ], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + DynamicFormsModule, + SharedModule, + StoreModule.forRoot({}), + HttpClientTestingModule, + RouterModule.forRoot([]), + RouterTestingModule, + ], + declarations: [PlatesComponent], + providers: [ + provideMockStore({ initialState: initialAppState }), + { + provide: UserService, + useValue: { + roles$: of([Roles.TechRecordAmend]), + }, + }, + { + provide: ActivatedRoute, + useValue: { + useValue: { params: of([{ id: 1 }]) }, + }, + }, + { + provide: APP_BASE_HREF, + useValue: '/', + }, + GlobalErrorService, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(PlatesComponent); - component = fixture.componentInstance; - router = TestBed.inject(Router); - errorService = TestBed.inject(GlobalErrorService); - component.techRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'hgv' | 'trl'>; - store = TestBed.inject(MockStore); - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(PlatesComponent); + component = fixture.componentInstance; + router = TestBed.inject(Router); + errorService = TestBed.inject(GlobalErrorService); + component.techRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType< + 'hgv' | 'trl' + >; + store = TestBed.inject(MockStore); + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - describe('mostRecentPlate', () => { - it('should fetch the plate if only 1 exists', () => { - (component.techRecord as TechRecordType<'trl'>).techRecord_plates = [ - { - plateIssueDate: new Date().toISOString(), - plateSerialNumber: '123456', - plateIssuer: 'issuer', - plateReasonForIssue: 'Replacement', - }, - ]; - const plateFetched = component.mostRecentPlate; + describe('mostRecentPlate', () => { + it('should fetch the plate if only 1 exists', () => { + (component.techRecord as TechRecordType<'trl'>).techRecord_plates = [ + { + plateIssueDate: new Date().toISOString(), + plateSerialNumber: '123456', + plateIssuer: 'issuer', + plateReasonForIssue: 'Replacement', + }, + ]; + const plateFetched = component.mostRecentPlate; - expect(plateFetched).toBeDefined(); - expect(plateFetched?.plateSerialNumber).toBe('123456'); - }); + expect(plateFetched).toBeDefined(); + expect(plateFetched?.plateSerialNumber).toBe('123456'); + }); - it('should fetch the latest plate if more than 1 exists', () => { - component.techRecord = { - techRecord_plates: [ - { - plateIssueDate: new Date(new Date().getTime()).toISOString(), - plateSerialNumber: '123456', - plateIssuer: 'issuer', - plateReasonForIssue: 'Replacement', - }, - { - plateIssueDate: new Date(new Date().getTime() + 5).toISOString(), - plateSerialNumber: '234567', - plateIssuer: 'issuer', - plateReasonForIssue: 'Replacement', - }, - { - plateIssueDate: new Date(new Date().getTime() - 5).toISOString(), - plateSerialNumber: '345678', - plateIssuer: 'issuer', - plateReasonForIssue: 'Replacement', - }, - ], - } as TechRecordType<'trl'>; + it('should fetch the latest plate if more than 1 exists', () => { + component.techRecord = { + techRecord_plates: [ + { + plateIssueDate: new Date(new Date().getTime()).toISOString(), + plateSerialNumber: '123456', + plateIssuer: 'issuer', + plateReasonForIssue: 'Replacement', + }, + { + plateIssueDate: new Date(new Date().getTime() + 5).toISOString(), + plateSerialNumber: '234567', + plateIssuer: 'issuer', + plateReasonForIssue: 'Replacement', + }, + { + plateIssueDate: new Date(new Date().getTime() - 5).toISOString(), + plateSerialNumber: '345678', + plateIssuer: 'issuer', + plateReasonForIssue: 'Replacement', + }, + ], + } as TechRecordType<'trl'>; - const plateFetched = component.mostRecentPlate; + const plateFetched = component.mostRecentPlate; - expect(plateFetched).toBeDefined(); - expect(plateFetched?.plateSerialNumber).toBe('234567'); - }); + expect(plateFetched).toBeDefined(); + expect(plateFetched?.plateSerialNumber).toBe('234567'); + }); - it('should return null if plates are empty', () => { - component.techRecord = { techRecord_plates: [] } as unknown as TechRecordType<'trl'>; + it('should return null if plates are empty', () => { + component.techRecord = { techRecord_plates: [] } as unknown as TechRecordType<'trl'>; - const plateFetched = component.mostRecentPlate; + const plateFetched = component.mostRecentPlate; - expect(plateFetched).toBeUndefined(); - }); - }); + expect(plateFetched).toBeUndefined(); + }); + }); - describe('hasPlates', () => { - it('should return false if plates is undefined', () => { - component.techRecord = { techRecord_plates: undefined } as unknown as TechRecordType<'trl'>; + describe('hasPlates', () => { + it('should return false if plates is undefined', () => { + component.techRecord = { techRecord_plates: undefined } as unknown as TechRecordType<'trl'>; - expect(component.hasPlates).toBeFalsy(); - }); + expect(component.hasPlates).toBeFalsy(); + }); - it('should return false if plates is empty', () => { - component.techRecord = { techRecord_plates: [] } as unknown as TechRecordType<'trl'>; + it('should return false if plates is empty', () => { + component.techRecord = { techRecord_plates: [] } as unknown as TechRecordType<'trl'>; - expect(component.hasPlates).toBeFalsy(); - }); + expect(component.hasPlates).toBeFalsy(); + }); - it('should return true if plates is not empty', () => { - component.techRecord = { - techRecord_plates: [ - { - plateIssueDate: new Date().toISOString(), - plateSerialNumber: '123456', - plateIssuer: 'issuer', - plateReasonForIssue: 'Replacement', - }, - ], - } as TechRecordType<'trl'>; + it('should return true if plates is not empty', () => { + component.techRecord = { + techRecord_plates: [ + { + plateIssueDate: new Date().toISOString(), + plateSerialNumber: '123456', + plateIssuer: 'issuer', + plateReasonForIssue: 'Replacement', + }, + ], + } as TechRecordType<'trl'>; - expect(component.hasPlates).toBeTruthy(); - }); - }); + expect(component.hasPlates).toBeTruthy(); + }); + }); - describe('validateTechRecordPlates', () => { - beforeEach(() => { - component.techRecord = { - primaryVrm: '123456', - techRecord_approvalType: 'NTA', - techRecord_approvalTypeNumber: '1', - techRecord_bodyType_code: 'b', - techRecord_bodyType_description: 'box', - techRecord_brakes_dtpNumber: '12345', - techRecord_dimensions_length: 1, - techRecord_dimensions_width: 1, - techRecord_frontVehicleTo5thWheelCouplingMax: 1, - techRecord_frontVehicleTo5thWheelCouplingMin: 1, - techRecord_functionCode: 'R', - techRecord_grossDesignWeight: 1, - techRecord_grossEecWeight: 1, - techRecord_grossGbWeight: 1, - techRecord_make: 'AEC', - techRecord_manufactureYear: 2020, - techRecord_maxTrainDesignWeight: 1, - techRecord_maxTrainEecWeight: 11, - techRecord_maxTrainGbWeight: 1, - techRecord_model: '123', - techRecord_noOfAxles: 1, - techRecord_ntaNumber: '1', - techRecord_reasonForCreation: 'Test', - techRecord_recordCompleteness: 'skeleton', - techRecord_regnDate: '2020-10-10', - techRecord_speedLimiterMrk: true, - techRecord_statusCode: 'current', - techRecord_trainDesignWeight: 1, - techRecord_trainEecWeight: 1, - techRecord_trainGbWeight: 1, - techRecord_tyreUseCode: 'a', - techRecord_vehicleType: 'hgv', - techRecord_variantNumber: '1', - techRecord_roadFriendly: true, - techRecord_vehicleConfiguration: VehicleConfigurations.RIGID, - vin: 'HGVTEST01', - techRecord_axles: [], - } as unknown as TechRecordType<'hgv' | 'trl'>; + describe('validateTechRecordPlates', () => { + beforeEach(() => { + component.techRecord = { + primaryVrm: '123456', + techRecord_approvalType: 'NTA', + techRecord_approvalTypeNumber: '1', + techRecord_bodyType_code: 'b', + techRecord_bodyType_description: 'box', + techRecord_brakes_dtpNumber: '12345', + techRecord_dimensions_length: 1, + techRecord_dimensions_width: 1, + techRecord_frontVehicleTo5thWheelCouplingMax: 1, + techRecord_frontVehicleTo5thWheelCouplingMin: 1, + techRecord_functionCode: 'R', + techRecord_grossDesignWeight: 1, + techRecord_grossEecWeight: 1, + techRecord_grossGbWeight: 1, + techRecord_make: 'AEC', + techRecord_manufactureYear: 2020, + techRecord_maxTrainDesignWeight: 1, + techRecord_maxTrainEecWeight: 11, + techRecord_maxTrainGbWeight: 1, + techRecord_model: '123', + techRecord_noOfAxles: 1, + techRecord_ntaNumber: '1', + techRecord_reasonForCreation: 'Test', + techRecord_recordCompleteness: 'skeleton', + techRecord_regnDate: '2020-10-10', + techRecord_speedLimiterMrk: true, + techRecord_statusCode: 'current', + techRecord_trainDesignWeight: 1, + techRecord_trainEecWeight: 1, + techRecord_trainGbWeight: 1, + techRecord_tyreUseCode: 'a', + techRecord_vehicleType: 'hgv', + techRecord_variantNumber: '1', + techRecord_roadFriendly: true, + techRecord_vehicleConfiguration: VehicleConfigurations.RIGID, + vin: 'HGVTEST01', + techRecord_axles: [], + } as unknown as TechRecordType<'hgv' | 'trl'>; - component.techRecord.techRecord_axles = [ - { - parkingBrakeMrk: true, - axleNumber: 1, - brakes_brakeActuator: 1, - brakes_leverLength: 1, - brakes_springBrakeParking: true, - weights_gbWeight: 1, - weights_designWeight: 2, - weights_ladenWeight: 3, - weights_kerbWeight: 4, - weights_eecWeight: 5, - tyres_tyreCode: 1, - tyres_tyreSize: '2', - tyres_plyRating: '3', - tyres_fitmentCode: 'single', - tyres_dataTrAxles: 1, - tyres_speedCategorySymbol: 'a7', - }, - ]; - }); - it('should show an error if tech record is not valid for plates', () => { - component.techRecord.vin = ''; - const plateFieldsErrorMessage = 'All fields marked plate are mandatory to generate a plate.'; - const errorSpy = jest.spyOn(errorService, 'addError'); - component.validateTechRecordPlates(); - expect(errorSpy).toHaveBeenCalledWith({ error: plateFieldsErrorMessage }); - }); - it('should dispatch the canGeneratePlate action if the record is valid', () => { - fixture.ngZone?.run(() => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.validateTechRecordPlates(); - expect(dispatchSpy).toHaveBeenCalledWith(canGeneratePlate()); - }); - }); - it('should call router.navigate on a valid record', () => { - fixture.ngZone?.run(() => { - const navigateSpy = jest.spyOn(router, 'navigate'); - component.validateTechRecordPlates(); - expect(navigateSpy).toHaveBeenCalledWith(['generate-plate'], { relativeTo: expect.anything() }); - }); - }); - }); + component.techRecord.techRecord_axles = [ + { + parkingBrakeMrk: true, + axleNumber: 1, + brakes_brakeActuator: 1, + brakes_leverLength: 1, + brakes_springBrakeParking: true, + weights_gbWeight: 1, + weights_designWeight: 2, + weights_ladenWeight: 3, + weights_kerbWeight: 4, + weights_eecWeight: 5, + tyres_tyreCode: 1, + tyres_tyreSize: '2', + tyres_plyRating: '3', + tyres_fitmentCode: 'single', + tyres_dataTrAxles: 1, + tyres_speedCategorySymbol: 'a7', + }, + ]; + }); + it('should show an error if tech record is not valid for plates', () => { + component.techRecord.vin = ''; + const plateFieldsErrorMessage = 'All fields marked plate are mandatory to generate a plate.'; + const errorSpy = jest.spyOn(errorService, 'addError'); + component.validateTechRecordPlates(); + expect(errorSpy).toHaveBeenCalledWith({ error: plateFieldsErrorMessage }); + }); + it('should dispatch the canGeneratePlate action if the record is valid', () => { + fixture.ngZone?.run(() => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.validateTechRecordPlates(); + expect(dispatchSpy).toHaveBeenCalledWith(canGeneratePlate()); + }); + }); + it('should call router.navigate on a valid record', () => { + fixture.ngZone?.run(() => { + const navigateSpy = jest.spyOn(router, 'navigate'); + component.validateTechRecordPlates(); + expect(navigateSpy).toHaveBeenCalledWith(['generate-plate'], { relativeTo: expect.anything() }); + }); + }); + }); - describe('cannotGeneratePlate', () => { - it('should not generate if missing a tyre fitment code', () => { - component.techRecord = { - primaryVrm: 'thing', - vin: 'thing', - techRecord_brakes_dtpNumber: 'thing', - techRecord_regnDate: 'thing', - techRecord_manufactureYear: 1, - techRecord_speedLimiterMrk: true, - techRecord_variantNumber: 'thing', - techRecord_make: 'thing', - techRecord_model: 'thing', - techRecord_functionCode: 'thing', - techRecord_frontVehicleTo5thWheelCouplingMin: 1, - techRecord_frontVehicleTo5thWheelCouplingMax: 1, - techRecord_dimensions_length: 1, - techRecord_dimensions_width: 1, - techRecord_tyreUseCode: '2R', - techRecord_roadFriendly: true, - techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, - techRecord_axles: [{ - tyres_tyreSize: '215/25', weights_gbWeight: '123', tyres_plyRating: '2R', - }, - { - tyres_fitmentCode: 'single', tyres_tyreSize: '215/25', weights_gbWeight: '123', tyres_plyRating: '2R', - }], - techRecord_noOfAxles: 2, - } as unknown as TechRecordType<'hgv'>; - const res = component.cannotGeneratePlate(hgvRequiredFields); - expect(res).toBeTruthy(); - }); - it('should not generate if both axles missing a tyre fitment code', () => { - component.techRecord = { - primaryVrm: 'thing', - vin: 'thing', - techRecord_brakes_dtpNumber: 'thing', - techRecord_regnDate: 'thing', - techRecord_manufactureYear: 1, - techRecord_speedLimiterMrk: true, - techRecord_variantNumber: 'thing', - techRecord_make: 'thing', - techRecord_model: 'thing', - techRecord_functionCode: 'thing', - techRecord_frontVehicleTo5thWheelCouplingMin: 1, - techRecord_frontVehicleTo5thWheelCouplingMax: 1, - techRecord_dimensions_length: 1, - techRecord_dimensions_width: 1, - techRecord_tyreUseCode: '2R', - techRecord_roadFriendly: true, - techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, - techRecord_axles: [{ - tyres_tyreSize: '215/25', weights_gbWeight: '123', tyres_plyRating: '2R', - }, - { - tyres_tyreSize: '215/25', weights_gbWeight: '123', tyres_plyRating: '2R', - }], - techRecord_noOfAxles: 2, - } as unknown as TechRecordType<'hgv'>; - const res = component.cannotGeneratePlate(hgvRequiredFields); - expect(res).toBeTruthy(); - }); - it('should not generate if missing a tyre size', () => { - component.techRecord = { - primaryVrm: 'thing', - vin: 'thing', - techRecord_brakes_dtpNumber: 'thing', - techRecord_regnDate: 'thing', - techRecord_manufactureYear: 1, - techRecord_speedLimiterMrk: true, - techRecord_variantNumber: 'thing', - techRecord_make: 'thing', - techRecord_model: 'thing', - techRecord_functionCode: 'thing', - techRecord_frontVehicleTo5thWheelCouplingMin: 1, - techRecord_frontVehicleTo5thWheelCouplingMax: 1, - techRecord_dimensions_length: 1, - techRecord_dimensions_width: 1, - techRecord_tyreUseCode: '2R', - techRecord_roadFriendly: true, - techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, - techRecord_axles: [{ - tyres_fitmentCode: 'single', weights_gbWeight: '123', tyres_plyRating: '2R', - }, - { - tyres_fitmentCode: 'single', tyres_tyreSize: '215/25', weights_gbWeight: '123', tyres_plyRating: '2R', - }], - techRecord_noOfAxles: 2, - } as unknown as TechRecordType<'hgv'>; - const res = component.cannotGeneratePlate(hgvRequiredFields); - expect(res).toBeTruthy(); - }); - it('should not generate if a load/plyRating', () => { - component.techRecord = { - primaryVrm: 'thing', - vin: 'thing', - techRecord_brakes_dtpNumber: 'thing', - techRecord_regnDate: 'thing', - techRecord_manufactureYear: 1, - techRecord_speedLimiterMrk: true, - techRecord_variantNumber: 'thing', - techRecord_make: 'thing', - techRecord_model: 'thing', - techRecord_functionCode: 'thing', - techRecord_frontVehicleTo5thWheelCouplingMin: 1, - techRecord_frontVehicleTo5thWheelCouplingMax: 1, - techRecord_dimensions_length: 1, - techRecord_dimensions_width: 1, - techRecord_tyreUseCode: '2R', - techRecord_roadFriendly: true, - techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, - techRecord_axles: [{ - tyres_fitmentCode: 'single', tyres_tyreSize: '215/25', weights_gbWeight: '123', - }, - { - tyres_fitmentCode: 'single', tyres_tyreSize: '215/25', weights_gbWeight: '123', - }], - techRecord_noOfAxles: 2, - } as unknown as TechRecordType<'hgv'>; - const res = component.cannotGeneratePlate(hgvRequiredFields); - expect(res).toBeTruthy(); - }); - it('should not generate if missing axles', () => { - component.techRecord = { - primaryVrm: 'thing', - vin: 'thing', - techRecord_brakes_dtpNumber: 'thing', - techRecord_regnDate: 'thing', - techRecord_manufactureYear: 1, - techRecord_speedLimiterMrk: true, - techRecord_variantNumber: 'thing', - techRecord_make: 'thing', - techRecord_model: 'thing', - techRecord_functionCode: 'thing', - techRecord_frontVehicleTo5thWheelCouplingMin: 1, - techRecord_frontVehicleTo5thWheelCouplingMax: 1, - techRecord_dimensions_length: 1, - techRecord_dimensions_width: 1, - techRecord_tyreUseCode: '2R', - techRecord_roadFriendly: true, - techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, - techRecord_axles: [], - techRecord_noOfAxles: 0, - } as unknown as TechRecordType<'hgv'>; - const res = component.cannotGeneratePlate(hgvRequiredFields); - expect(res).toBeTruthy(); - }); - it('should not generate without gbWeight on axle 1', () => { - component.techRecord = { - primaryVrm: 'thing', - vin: 'thing', - techRecord_brakes_dtpNumber: 'thing', - techRecord_regnDate: 'thing', - techRecord_manufactureYear: 1, - techRecord_speedLimiterMrk: true, - techRecord_variantNumber: 'thing', - techRecord_make: 'thing', - techRecord_model: 'thing', - techRecord_functionCode: 'thing', - techRecord_frontVehicleTo5thWheelCouplingMin: 1, - techRecord_frontVehicleTo5thWheelCouplingMax: 1, - techRecord_dimensions_length: 1, - techRecord_dimensions_width: 1, - techRecord_tyreUseCode: '2R', - techRecord_roadFriendly: true, - techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, - techRecord_axles: [{ - tyres_fitmentCode: 'single', tyres_tyreSize: '215/25', tyres_plyRating: '2R', - }, - { - tyres_fitmentCode: 'single', tyres_tyreSize: '215/25', tyres_plyRating: '2R', - }], - techRecord_noOfAxles: 2, - } as unknown as TechRecordType<'hgv'>; - const res = component.cannotGeneratePlate(hgvRequiredFields); - expect(res).toBeTruthy(); - }); - it('should not generate with a missing required hgv validation field', () => { - component.techRecord = { - primaryVrm: 'thing', - vin: 'thing', - techRecord_brakes_dtpNumber: 'thing', - techRecord_regnDate: 'thing', - techRecord_manufactureYear: 1, - techRecord_speedLimiterMrk: true, - techRecord_variantNumber: 'thing', - techRecord_model: 'thing', - techRecord_functionCode: 'thing', - techRecord_frontVehicleTo5thWheelCouplingMin: 1, - techRecord_frontVehicleTo5thWheelCouplingMax: 1, - techRecord_dimensions_length: 1, - techRecord_dimensions_width: 1, - techRecord_tyreUseCode: '2R', - techRecord_roadFriendly: true, - techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, - techRecord_axles: [{ - tyres_fitmentCode: 'single', tyres_tyreSize: '215/25', weights_gbWeight: '123', tyres_plyRating: '2R', - }, - { - tyres_fitmentCode: 'single', tyres_tyreSize: '215/25', weights_gbWeight: '123', tyres_plyRating: '2R', - }], - techRecord_noOfAxles: 2, - } as unknown as TechRecordType<'hgv'>; - const res = component.cannotGeneratePlate(hgvRequiredFields); - expect(res).toBeTruthy(); - }); - it('should generate with a hgv plate', () => { - component.techRecord = { - primaryVrm: 'thing', - vin: 'thing', - techRecord_brakes_dtpNumber: 'thing', - techRecord_regnDate: 'thing', - techRecord_manufactureYear: 1, - techRecord_speedLimiterMrk: true, - techRecord_variantNumber: 'thing', - techRecord_make: 'thing', - techRecord_model: 'thing', - techRecord_functionCode: 'thing', - techRecord_frontVehicleTo5thWheelCouplingMin: 1, - techRecord_frontVehicleTo5thWheelCouplingMax: 1, - techRecord_dimensions_length: 1, - techRecord_dimensions_width: 1, - techRecord_tyreUseCode: '2R', - techRecord_roadFriendly: true, - techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, - techRecord_axles: [{ - tyres_fitmentCode: 'single', tyres_tyreSize: '215/25', weights_gbWeight: '123', tyres_plyRating: '2R', - }, - { - tyres_fitmentCode: 'single', tyres_tyreSize: '215/25', weights_gbWeight: '123', tyres_plyRating: '2R', - }], - techRecord_noOfAxles: 2, - } as unknown as TechRecordType<'hgv'>; - const res = component.cannotGeneratePlate(hgvRequiredFields); - expect(res).toBeFalsy(); - }); - }); + describe('cannotGeneratePlate', () => { + it('should not generate if missing a tyre fitment code', () => { + component.techRecord = { + primaryVrm: 'thing', + vin: 'thing', + techRecord_brakes_dtpNumber: 'thing', + techRecord_regnDate: 'thing', + techRecord_manufactureYear: 1, + techRecord_speedLimiterMrk: true, + techRecord_variantNumber: 'thing', + techRecord_make: 'thing', + techRecord_model: 'thing', + techRecord_functionCode: 'thing', + techRecord_frontVehicleTo5thWheelCouplingMin: 1, + techRecord_frontVehicleTo5thWheelCouplingMax: 1, + techRecord_dimensions_length: 1, + techRecord_dimensions_width: 1, + techRecord_tyreUseCode: '2R', + techRecord_roadFriendly: true, + techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, + techRecord_axles: [ + { + tyres_tyreSize: '215/25', + weights_gbWeight: '123', + tyres_plyRating: '2R', + }, + { + tyres_fitmentCode: 'single', + tyres_tyreSize: '215/25', + weights_gbWeight: '123', + tyres_plyRating: '2R', + }, + ], + techRecord_noOfAxles: 2, + } as unknown as TechRecordType<'hgv'>; + const res = component.cannotGeneratePlate(hgvRequiredFields); + expect(res).toBeTruthy(); + }); + it('should not generate if both axles missing a tyre fitment code', () => { + component.techRecord = { + primaryVrm: 'thing', + vin: 'thing', + techRecord_brakes_dtpNumber: 'thing', + techRecord_regnDate: 'thing', + techRecord_manufactureYear: 1, + techRecord_speedLimiterMrk: true, + techRecord_variantNumber: 'thing', + techRecord_make: 'thing', + techRecord_model: 'thing', + techRecord_functionCode: 'thing', + techRecord_frontVehicleTo5thWheelCouplingMin: 1, + techRecord_frontVehicleTo5thWheelCouplingMax: 1, + techRecord_dimensions_length: 1, + techRecord_dimensions_width: 1, + techRecord_tyreUseCode: '2R', + techRecord_roadFriendly: true, + techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, + techRecord_axles: [ + { + tyres_tyreSize: '215/25', + weights_gbWeight: '123', + tyres_plyRating: '2R', + }, + { + tyres_tyreSize: '215/25', + weights_gbWeight: '123', + tyres_plyRating: '2R', + }, + ], + techRecord_noOfAxles: 2, + } as unknown as TechRecordType<'hgv'>; + const res = component.cannotGeneratePlate(hgvRequiredFields); + expect(res).toBeTruthy(); + }); + it('should not generate if missing a tyre size', () => { + component.techRecord = { + primaryVrm: 'thing', + vin: 'thing', + techRecord_brakes_dtpNumber: 'thing', + techRecord_regnDate: 'thing', + techRecord_manufactureYear: 1, + techRecord_speedLimiterMrk: true, + techRecord_variantNumber: 'thing', + techRecord_make: 'thing', + techRecord_model: 'thing', + techRecord_functionCode: 'thing', + techRecord_frontVehicleTo5thWheelCouplingMin: 1, + techRecord_frontVehicleTo5thWheelCouplingMax: 1, + techRecord_dimensions_length: 1, + techRecord_dimensions_width: 1, + techRecord_tyreUseCode: '2R', + techRecord_roadFriendly: true, + techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, + techRecord_axles: [ + { + tyres_fitmentCode: 'single', + weights_gbWeight: '123', + tyres_plyRating: '2R', + }, + { + tyres_fitmentCode: 'single', + tyres_tyreSize: '215/25', + weights_gbWeight: '123', + tyres_plyRating: '2R', + }, + ], + techRecord_noOfAxles: 2, + } as unknown as TechRecordType<'hgv'>; + const res = component.cannotGeneratePlate(hgvRequiredFields); + expect(res).toBeTruthy(); + }); + it('should not generate if a load/plyRating', () => { + component.techRecord = { + primaryVrm: 'thing', + vin: 'thing', + techRecord_brakes_dtpNumber: 'thing', + techRecord_regnDate: 'thing', + techRecord_manufactureYear: 1, + techRecord_speedLimiterMrk: true, + techRecord_variantNumber: 'thing', + techRecord_make: 'thing', + techRecord_model: 'thing', + techRecord_functionCode: 'thing', + techRecord_frontVehicleTo5thWheelCouplingMin: 1, + techRecord_frontVehicleTo5thWheelCouplingMax: 1, + techRecord_dimensions_length: 1, + techRecord_dimensions_width: 1, + techRecord_tyreUseCode: '2R', + techRecord_roadFriendly: true, + techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, + techRecord_axles: [ + { + tyres_fitmentCode: 'single', + tyres_tyreSize: '215/25', + weights_gbWeight: '123', + }, + { + tyres_fitmentCode: 'single', + tyres_tyreSize: '215/25', + weights_gbWeight: '123', + }, + ], + techRecord_noOfAxles: 2, + } as unknown as TechRecordType<'hgv'>; + const res = component.cannotGeneratePlate(hgvRequiredFields); + expect(res).toBeTruthy(); + }); + it('should not generate if missing axles', () => { + component.techRecord = { + primaryVrm: 'thing', + vin: 'thing', + techRecord_brakes_dtpNumber: 'thing', + techRecord_regnDate: 'thing', + techRecord_manufactureYear: 1, + techRecord_speedLimiterMrk: true, + techRecord_variantNumber: 'thing', + techRecord_make: 'thing', + techRecord_model: 'thing', + techRecord_functionCode: 'thing', + techRecord_frontVehicleTo5thWheelCouplingMin: 1, + techRecord_frontVehicleTo5thWheelCouplingMax: 1, + techRecord_dimensions_length: 1, + techRecord_dimensions_width: 1, + techRecord_tyreUseCode: '2R', + techRecord_roadFriendly: true, + techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, + techRecord_axles: [], + techRecord_noOfAxles: 0, + } as unknown as TechRecordType<'hgv'>; + const res = component.cannotGeneratePlate(hgvRequiredFields); + expect(res).toBeTruthy(); + }); + it('should not generate without gbWeight on axle 1', () => { + component.techRecord = { + primaryVrm: 'thing', + vin: 'thing', + techRecord_brakes_dtpNumber: 'thing', + techRecord_regnDate: 'thing', + techRecord_manufactureYear: 1, + techRecord_speedLimiterMrk: true, + techRecord_variantNumber: 'thing', + techRecord_make: 'thing', + techRecord_model: 'thing', + techRecord_functionCode: 'thing', + techRecord_frontVehicleTo5thWheelCouplingMin: 1, + techRecord_frontVehicleTo5thWheelCouplingMax: 1, + techRecord_dimensions_length: 1, + techRecord_dimensions_width: 1, + techRecord_tyreUseCode: '2R', + techRecord_roadFriendly: true, + techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, + techRecord_axles: [ + { + tyres_fitmentCode: 'single', + tyres_tyreSize: '215/25', + tyres_plyRating: '2R', + }, + { + tyres_fitmentCode: 'single', + tyres_tyreSize: '215/25', + tyres_plyRating: '2R', + }, + ], + techRecord_noOfAxles: 2, + } as unknown as TechRecordType<'hgv'>; + const res = component.cannotGeneratePlate(hgvRequiredFields); + expect(res).toBeTruthy(); + }); + it('should not generate with a missing required hgv validation field', () => { + component.techRecord = { + primaryVrm: 'thing', + vin: 'thing', + techRecord_brakes_dtpNumber: 'thing', + techRecord_regnDate: 'thing', + techRecord_manufactureYear: 1, + techRecord_speedLimiterMrk: true, + techRecord_variantNumber: 'thing', + techRecord_model: 'thing', + techRecord_functionCode: 'thing', + techRecord_frontVehicleTo5thWheelCouplingMin: 1, + techRecord_frontVehicleTo5thWheelCouplingMax: 1, + techRecord_dimensions_length: 1, + techRecord_dimensions_width: 1, + techRecord_tyreUseCode: '2R', + techRecord_roadFriendly: true, + techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, + techRecord_axles: [ + { + tyres_fitmentCode: 'single', + tyres_tyreSize: '215/25', + weights_gbWeight: '123', + tyres_plyRating: '2R', + }, + { + tyres_fitmentCode: 'single', + tyres_tyreSize: '215/25', + weights_gbWeight: '123', + tyres_plyRating: '2R', + }, + ], + techRecord_noOfAxles: 2, + } as unknown as TechRecordType<'hgv'>; + const res = component.cannotGeneratePlate(hgvRequiredFields); + expect(res).toBeTruthy(); + }); + it('should generate with a hgv plate', () => { + component.techRecord = { + primaryVrm: 'thing', + vin: 'thing', + techRecord_brakes_dtpNumber: 'thing', + techRecord_regnDate: 'thing', + techRecord_manufactureYear: 1, + techRecord_speedLimiterMrk: true, + techRecord_variantNumber: 'thing', + techRecord_make: 'thing', + techRecord_model: 'thing', + techRecord_functionCode: 'thing', + techRecord_frontVehicleTo5thWheelCouplingMin: 1, + techRecord_frontVehicleTo5thWheelCouplingMax: 1, + techRecord_dimensions_length: 1, + techRecord_dimensions_width: 1, + techRecord_tyreUseCode: '2R', + techRecord_roadFriendly: true, + techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, + techRecord_axles: [ + { + tyres_fitmentCode: 'single', + tyres_tyreSize: '215/25', + weights_gbWeight: '123', + tyres_plyRating: '2R', + }, + { + tyres_fitmentCode: 'single', + tyres_tyreSize: '215/25', + weights_gbWeight: '123', + tyres_plyRating: '2R', + }, + ], + techRecord_noOfAxles: 2, + } as unknown as TechRecordType<'hgv'>; + const res = component.cannotGeneratePlate(hgvRequiredFields); + expect(res).toBeFalsy(); + }); + }); }); diff --git a/src/app/forms/custom-sections/plates/plates.component.ts b/src/app/forms/custom-sections/plates/plates.component.ts index 572fd06cb4..b76a8969e9 100644 --- a/src/app/forms/custom-sections/plates/plates.component.ts +++ b/src/app/forms/custom-sections/plates/plates.component.ts @@ -1,7 +1,5 @@ import { ViewportScroller } from '@angular/common'; -import { - ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, -} from '@angular/core'; +import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { HGVPlates } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/hgv/complete'; @@ -20,152 +18,161 @@ import { cloneDeep } from 'lodash'; import { Subscription, debounceTime } from 'rxjs'; @Component({ - selector: 'app-plates[techRecord]', - templateUrl: './plates.component.html', - styleUrls: ['./plates.component.scss'], + selector: 'app-plates[techRecord]', + templateUrl: './plates.component.html', + styleUrls: ['./plates.component.scss'], }) export class PlatesComponent implements OnInit, OnDestroy, OnChanges { - @Input() techRecord!: TechRecordType<'hgv' | 'trl'>; - @Input() isEditing = false; - - @Output() formChange = new EventEmitter(); - - form!: CustomFormGroup; - pageStart?: number; - pageEnd?: number; - - private formSubscription = new Subscription(); - - constructor( - private dynamicFormService: DynamicFormService, - private cdr: ChangeDetectorRef, - private globalErrorService: GlobalErrorService, - private router: Router, - private route: ActivatedRoute, - private store: Store, - private viewportScroller: ViewportScroller, - ) {} - - ngOnInit(): void { - this.form = this.dynamicFormService.createForm(PlatesTemplate, this.techRecord) as CustomFormGroup; - this.formSubscription = this.form.cleanValueChanges.pipe(debounceTime(400)).subscribe((event) => this.formChange.emit(event)); - } - - ngOnChanges(): void { - this.form?.patchValue(this.techRecord, { emitEvent: false }); - } - - ngOnDestroy(): void { - this.formSubscription.unsubscribe(); - } - - get roles(): typeof Roles { - return Roles; - } - - get types(): typeof FormNodeEditTypes { - return FormNodeEditTypes; - } - - get hasPlates(): boolean { - return !!this.techRecord.techRecord_plates?.length; - } - - get sortedPlates(): HGVPlates[] | TRLPlates[] | undefined { - return cloneDeep(this.techRecord.techRecord_plates)?.sort((a, b) => - a.plateIssueDate && b.plateIssueDate ? new Date(b.plateIssueDate).getTime() - new Date(a.plateIssueDate).getTime() : 0); - } - - get plates() { - return this.sortedPlates?.slice(this.pageStart, this.pageEnd) ?? []; - } - - get mostRecentPlate() { - return cloneDeep(this.techRecord.techRecord_plates) - ?.sort((a, b) => - a.plateIssueDate && b.plateIssueDate ? new Date(a.plateIssueDate).getTime() - new Date(b.plateIssueDate).getTime() : 0) - ?.pop(); - } - - get numberOfPlates(): number { - return this.sortedPlates?.length || 0; - } - - handlePaginationChange({ start, end }: { start: number; end: number }) { - this.pageStart = start; - this.pageEnd = end; - this.cdr.detectChanges(); - } - - trackByFn(i: number, tr: HGVPlates | TRLPlates) { - return tr.plateIssueDate; - } - - get documentParams(): Map { - return new Map([['plateSerialNumber', this.fileName]]); - } - - get fileName(): string { - if (this.mostRecentPlate) { - return `plate_${this.mostRecentPlate.plateSerialNumber}`; - } - throw new Error('Could not find plate.'); - } - - get eligibleForPlates(): boolean { - return this.techRecord.techRecord_statusCode === StatusCodes.CURRENT && !this.isEditing; - } - - get reasonForIneligibility(): string { - if (this.isEditing) { - return 'This section is not available when amending or creating a technical record.'; - } - - if (this.techRecord.techRecord_statusCode !== StatusCodes.CURRENT) { - return 'Generating plates is only applicable to current technical records.'; - } - return ''; - } - - validateTechRecordPlates(): void { - this.globalErrorService.clearErrors(); - const plateValidationTable = this.techRecord.techRecord_vehicleType === 'trl' ? trlRequiredFields : hgvRequiredFields; - - if (this.cannotGeneratePlate(plateValidationTable)) { - this.viewportScroller.scrollToPosition([0, 0]); - this.globalErrorService.addError({ error: 'All fields marked plate are mandatory to generate a plate.' }); - return; - } - this.store.dispatch(canGeneratePlate()); - this.store.dispatch(updateScrollPosition({ position: this.viewportScroller.getScrollPosition() })); - void this.router.navigate(['generate-plate'], { relativeTo: this.route }); - } - - cannotGeneratePlate(plateRequiredFields: string[]): boolean { - const isOneFieldEmpty = plateRequiredFields.some((field) => { - const value = this.techRecord[field as keyof TechRecordType<'hgv' | 'trl'>]; - return value === undefined || value === null || value === ''; - }); - - // Only gbWeight of Axle 1 is required - const { techRecord_noOfAxles: noOfAxles, techRecord_axles: axles } = this.techRecord; - const areAxlesInvalid = !noOfAxles || noOfAxles < 1 || !axles || axles[0].weights_gbWeight == null; - - // check tyre fields - const areTyresInvalid = this.techRecord.techRecord_axles?.some((axle) => { - const tyreRequiredInvalid = tyreRequiredFields.map((field) => { - const value = axle[field as keyof Axle<'hgv'>]; - return value === undefined || value === null || value === ''; - }); - - if (tyreRequiredInvalid.some((value) => value)) { - return true; - } - // either one of ply rating or load index is required - const plyOrLoad = axle['tyres_plyRating' as keyof Axle<'hgv'>] || axle['tyres_dataTrAxles' as keyof Axle<'hgv'>]; - return plyOrLoad === undefined || plyOrLoad === null || plyOrLoad === ''; - }); - - return isOneFieldEmpty || areAxlesInvalid || !!areTyresInvalid; - } + @Input() techRecord!: TechRecordType<'hgv' | 'trl'>; + @Input() isEditing = false; + + @Output() formChange = new EventEmitter(); + + form!: CustomFormGroup; + pageStart?: number; + pageEnd?: number; + + private formSubscription = new Subscription(); + + constructor( + private dynamicFormService: DynamicFormService, + private cdr: ChangeDetectorRef, + private globalErrorService: GlobalErrorService, + private router: Router, + private route: ActivatedRoute, + private store: Store, + private viewportScroller: ViewportScroller + ) {} + + ngOnInit(): void { + this.form = this.dynamicFormService.createForm(PlatesTemplate, this.techRecord) as CustomFormGroup; + this.formSubscription = this.form.cleanValueChanges + .pipe(debounceTime(400)) + .subscribe((event) => this.formChange.emit(event)); + } + + ngOnChanges(): void { + this.form?.patchValue(this.techRecord, { emitEvent: false }); + } + + ngOnDestroy(): void { + this.formSubscription.unsubscribe(); + } + + get roles(): typeof Roles { + return Roles; + } + + get types(): typeof FormNodeEditTypes { + return FormNodeEditTypes; + } + + get hasPlates(): boolean { + return !!this.techRecord.techRecord_plates?.length; + } + + get sortedPlates(): HGVPlates[] | TRLPlates[] | undefined { + return cloneDeep(this.techRecord.techRecord_plates)?.sort((a, b) => + a.plateIssueDate && b.plateIssueDate + ? new Date(b.plateIssueDate).getTime() - new Date(a.plateIssueDate).getTime() + : 0 + ); + } + + get plates() { + return this.sortedPlates?.slice(this.pageStart, this.pageEnd) ?? []; + } + + get mostRecentPlate() { + return cloneDeep(this.techRecord.techRecord_plates) + ?.sort((a, b) => + a.plateIssueDate && b.plateIssueDate + ? new Date(a.plateIssueDate).getTime() - new Date(b.plateIssueDate).getTime() + : 0 + ) + ?.pop(); + } + + get numberOfPlates(): number { + return this.sortedPlates?.length || 0; + } + + handlePaginationChange({ start, end }: { start: number; end: number }) { + this.pageStart = start; + this.pageEnd = end; + this.cdr.detectChanges(); + } + + trackByFn(i: number, tr: HGVPlates | TRLPlates) { + return tr.plateIssueDate; + } + + get documentParams(): Map { + return new Map([['plateSerialNumber', this.fileName]]); + } + + get fileName(): string { + if (this.mostRecentPlate) { + return `plate_${this.mostRecentPlate.plateSerialNumber}`; + } + throw new Error('Could not find plate.'); + } + + get eligibleForPlates(): boolean { + return this.techRecord.techRecord_statusCode === StatusCodes.CURRENT && !this.isEditing; + } + + get reasonForIneligibility(): string { + if (this.isEditing) { + return 'This section is not available when amending or creating a technical record.'; + } + + if (this.techRecord.techRecord_statusCode !== StatusCodes.CURRENT) { + return 'Generating plates is only applicable to current technical records.'; + } + return ''; + } + + validateTechRecordPlates(): void { + this.globalErrorService.clearErrors(); + const plateValidationTable = + this.techRecord.techRecord_vehicleType === 'trl' ? trlRequiredFields : hgvRequiredFields; + + if (this.cannotGeneratePlate(plateValidationTable)) { + this.viewportScroller.scrollToPosition([0, 0]); + this.globalErrorService.addError({ error: 'All fields marked plate are mandatory to generate a plate.' }); + return; + } + this.store.dispatch(canGeneratePlate()); + this.store.dispatch(updateScrollPosition({ position: this.viewportScroller.getScrollPosition() })); + void this.router.navigate(['generate-plate'], { relativeTo: this.route }); + } + + cannotGeneratePlate(plateRequiredFields: string[]): boolean { + const isOneFieldEmpty = plateRequiredFields.some((field) => { + const value = this.techRecord[field as keyof TechRecordType<'hgv' | 'trl'>]; + return value === undefined || value === null || value === ''; + }); + + // Only gbWeight of Axle 1 is required + const { techRecord_noOfAxles: noOfAxles, techRecord_axles: axles } = this.techRecord; + const areAxlesInvalid = !noOfAxles || noOfAxles < 1 || !axles || axles[0].weights_gbWeight == null; + + // check tyre fields + const areTyresInvalid = this.techRecord.techRecord_axles?.some((axle) => { + const tyreRequiredInvalid = tyreRequiredFields.map((field) => { + const value = axle[field as keyof Axle<'hgv'>]; + return value === undefined || value === null || value === ''; + }); + + if (tyreRequiredInvalid.some((value) => value)) { + return true; + } + // either one of ply rating or load index is required + const plyOrLoad = axle['tyres_plyRating' as keyof Axle<'hgv'>] || axle['tyres_dataTrAxles' as keyof Axle<'hgv'>]; + return plyOrLoad === undefined || plyOrLoad === null || plyOrLoad === ''; + }); + + return isOneFieldEmpty || areAxlesInvalid || !!areTyresInvalid; + } } diff --git a/src/app/forms/custom-sections/psv-brakes/psv-brakes.component.spec.ts b/src/app/forms/custom-sections/psv-brakes/psv-brakes.component.spec.ts index 474090df76..9be07a56a1 100644 --- a/src/app/forms/custom-sections/psv-brakes/psv-brakes.component.spec.ts +++ b/src/app/forms/custom-sections/psv-brakes/psv-brakes.component.spec.ts @@ -2,7 +2,10 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { RouterTestingModule } from '@angular/router/testing'; -import { TechRecordPSV, TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; +import { + TechRecordPSV, + TechRecordType, +} from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; import { DynamicFormsModule } from '@forms/dynamic-forms.module'; import { MultiOptionsService } from '@forms/services/multi-options.service'; import { mockVehicleTechnicalRecord } from '@mocks/mock-vehicle-technical-record.mock'; @@ -13,109 +16,113 @@ import { initialAppState } from '@store/index'; import { PsvBrakesComponent } from './psv-brakes.component'; describe('PsvBrakesComponent', () => { - let component: PsvBrakesComponent; - let fixture: ComponentFixture; + let component: PsvBrakesComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [PsvBrakesComponent], - imports: [DynamicFormsModule, FormsModule, HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule], - providers: [ - MultiOptionsService, - provideMockStore({ initialState: initialAppState }), - ReferenceDataService, - { provide: UserService, useValue: {} }, - ], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [PsvBrakesComponent], + imports: [DynamicFormsModule, FormsModule, HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule], + providers: [ + MultiOptionsService, + provideMockStore({ initialState: initialAppState }), + ReferenceDataService, + { provide: UserService, useValue: {} }, + ], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(PsvBrakesComponent); - component = fixture.componentInstance; + beforeEach(() => { + fixture = TestBed.createComponent(PsvBrakesComponent); + component = fixture.componentInstance; - component.vehicleTechRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>; - component.vehicleTechRecord.techRecord_axles = [ - { - axleNumber: 1, - tyres_tyreSize: '295/80-22.5', - tyres_speedCategorySymbol: 'p', - tyres_fitmentCode: 'double', - tyres_dataTrAxles: 0, - tyres_plyRating: 'A', - tyres_tyreCode: 456, - parkingBrakeMrk: false, + component.vehicleTechRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>; + component.vehicleTechRecord.techRecord_axles = [ + { + axleNumber: 1, + tyres_tyreSize: '295/80-22.5', + tyres_speedCategorySymbol: 'p', + tyres_fitmentCode: 'double', + tyres_dataTrAxles: 0, + tyres_plyRating: 'A', + tyres_tyreCode: 456, + parkingBrakeMrk: false, - weights_kerbWeight: 1, - weights_ladenWeight: 2, - weights_gbWeight: 3, - // TODO: V3 2 eecweights in type package, which is this? - // weights_eecWeight: 4, - weights_designWeight: 5, - }, - { - axleNumber: 2, - parkingBrakeMrk: true, + weights_kerbWeight: 1, + weights_ladenWeight: 2, + weights_gbWeight: 3, + // TODO: V3 2 eecweights in type package, which is this? + // weights_eecWeight: 4, + weights_designWeight: 5, + }, + { + axleNumber: 2, + parkingBrakeMrk: true, - tyres_tyreSize: '295/80-22.5', - tyres_speedCategorySymbol: 'p', - tyres_fitmentCode: 'double', - tyres_dataTrAxles: 0, - tyres_plyRating: 'A', - tyres_tyreCode: 456, + tyres_tyreSize: '295/80-22.5', + tyres_speedCategorySymbol: 'p', + tyres_fitmentCode: 'double', + tyres_dataTrAxles: 0, + tyres_plyRating: 'A', + tyres_tyreCode: 456, - weights_kerbWeight: 1, - weights_ladenWeight: 2, - weights_gbWeight: 3, - // weights_eecWeight: 4, - weights_designWeight: 5, - }, - { - axleNumber: 3, - parkingBrakeMrk: true, + weights_kerbWeight: 1, + weights_ladenWeight: 2, + weights_gbWeight: 3, + // weights_eecWeight: 4, + weights_designWeight: 5, + }, + { + axleNumber: 3, + parkingBrakeMrk: true, - tyres_tyreSize: '295/80-22.5', - tyres_speedCategorySymbol: 'p', - tyres_fitmentCode: 'double', - tyres_dataTrAxles: 0, - tyres_plyRating: 'A', - tyres_tyreCode: 456, + tyres_tyreSize: '295/80-22.5', + tyres_speedCategorySymbol: 'p', + tyres_fitmentCode: 'double', + tyres_dataTrAxles: 0, + tyres_plyRating: 'A', + tyres_tyreCode: 456, - weights_kerbWeight: 1, - weights_ladenWeight: 2, - weights_gbWeight: 3, - // weights_eecWeight: 4, - weights_designWeight: 5, - }, - ]; + weights_kerbWeight: 1, + weights_ladenWeight: 2, + weights_gbWeight: 3, + // weights_eecWeight: 4, + weights_designWeight: 5, + }, + ]; - fixture.detectChanges(); - }); + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); - describe('The brake code value on this.form', () => { - it('should match the corresponding values on vehicleTechRecord', () => { - expect(component.vehicleTechRecord?.techRecord_brakes_brakeCode).toStrictEqual(component.form.value.techRecord_brakes_brakeCode); - }); - }); - describe('The dataTrBrakeOne value on this.form', () => { - it('should match the corresponding values on vehicleTechRecord', () => { - expect(component.vehicleTechRecord?.techRecord_brakes_retarderBrakeOne).toStrictEqual(component.form.value.techRecord_brakes_retarderBrakeOne); - }); - }); - describe('The brakeCodeOriginal value on this.form', () => { - it('should match the corresponding values on vehicleTechRecord', () => { - expect(component.vehicleTechRecord?.techRecord_brakes_brakeCodeOriginal).toStrictEqual( - component.form.controls['techRecord_brakes_brakeCodeOriginal']?.value, - ); - }); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); + describe('The brake code value on this.form', () => { + it('should match the corresponding values on vehicleTechRecord', () => { + expect(component.vehicleTechRecord?.techRecord_brakes_brakeCode).toStrictEqual( + component.form.value.techRecord_brakes_brakeCode + ); + }); + }); + describe('The dataTrBrakeOne value on this.form', () => { + it('should match the corresponding values on vehicleTechRecord', () => { + expect(component.vehicleTechRecord?.techRecord_brakes_retarderBrakeOne).toStrictEqual( + component.form.value.techRecord_brakes_retarderBrakeOne + ); + }); + }); + describe('The brakeCodeOriginal value on this.form', () => { + it('should match the corresponding values on vehicleTechRecord', () => { + expect(component.vehicleTechRecord?.techRecord_brakes_brakeCodeOriginal).toStrictEqual( + component.form.controls['techRecord_brakes_brakeCodeOriginal']?.value + ); + }); + }); - describe('The axle value on this.form', () => { - it('should match the corresponding values on vehicleTechRecord', () => { - const axles = component.vehicleTechRecord?.techRecord_axles as NonNullable; - expect(axles[0]).toEqual(expect.objectContaining(component.form.controls['techRecord_axles']?.value[0])); - }); - }); + describe('The axle value on this.form', () => { + it('should match the corresponding values on vehicleTechRecord', () => { + const axles = component.vehicleTechRecord?.techRecord_axles as NonNullable; + expect(axles[0]).toEqual(expect.objectContaining(component.form.controls['techRecord_axles']?.value[0])); + }); + }); }); diff --git a/src/app/forms/custom-sections/psv-brakes/psv-brakes.component.ts b/src/app/forms/custom-sections/psv-brakes/psv-brakes.component.ts index f715f7aed1..cfc142c26a 100644 --- a/src/app/forms/custom-sections/psv-brakes/psv-brakes.component.ts +++ b/src/app/forms/custom-sections/psv-brakes/psv-brakes.component.ts @@ -1,13 +1,9 @@ -import { - Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, -} from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core'; import { FormArray, FormGroup } from '@angular/forms'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; import { MultiOptions } from '@forms/models/options.model'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; -import { - CustomFormGroup, FormNode, FormNodeEditTypes, FormNodeWidth, -} from '@forms/services/dynamic-form.types'; +import { CustomFormGroup, FormNode, FormNodeEditTypes, FormNodeWidth } from '@forms/services/dynamic-form.types'; import { MultiOptionsService } from '@forms/services/multi-options.service'; import { PsvBrakesTemplate } from '@forms/templates/psv/psv-brakes.template'; import { getOptionsFromEnum } from '@forms/utils/enum-map'; @@ -17,135 +13,137 @@ import { Store } from '@ngrx/store'; import { ReferenceDataState, selectBrakeByCode } from '@store/reference-data'; import { updateBrakeForces } from '@store/technical-records'; import { TechnicalRecordServiceState } from '@store/technical-records/reducers/technical-record-service.reducer'; -import { - debounceTime, Observable, of, Subject, switchMap, takeUntil, withLatestFrom, -} from 'rxjs'; +import { Observable, Subject, debounceTime, of, switchMap, takeUntil, withLatestFrom } from 'rxjs'; @Component({ - selector: 'app-psv-brakes', - templateUrl: './psv-brakes.component.html', - styleUrls: ['./psv-brakes.component.scss'], + selector: 'app-psv-brakes', + templateUrl: './psv-brakes.component.html', + styleUrls: ['./psv-brakes.component.scss'], }) export class PsvBrakesComponent implements OnInit, OnChanges, OnDestroy { - @Input() vehicleTechRecord?: TechRecordType<'psv'>; - @Input() isEditing = false; - - @Output() formChange = new EventEmitter(); - - form!: CustomFormGroup; - template!: FormNode; - - selectedBrake?: Brake; - - private destroy$ = new Subject(); - - constructor( - private dfs: DynamicFormService, - private optionsService: MultiOptionsService, - private referenceDataStore: Store, - private store: Store, - ) {} - - ngOnInit(): void { - this.form = this.dfs.createForm(PsvBrakesTemplate, this.vehicleTechRecord) as CustomFormGroup; - - (this.form.cleanValueChanges as Observable>>) - .pipe( - switchMap((event) => { - return event?.techRecord_brakes_brakeCodeOriginal - ? this.referenceDataStore.select(selectBrakeByCode(event.techRecord_brakes_brakeCodeOriginal)) - : of(undefined); - }), - withLatestFrom(this.form.cleanValueChanges as Observable>>), - debounceTime(400), - takeUntil(this.destroy$), - ) - .subscribe(([selectedBrake, event]) => { - // Set the brake details automatically based selection - if (selectedBrake && event?.techRecord_brakes_brakeCodeOriginal) { - event.techRecord_brakeCode = `${this.brakeCodePrefix}${selectedBrake.resourceKey}`; - event.techRecord_brakes_brakeCode = `${this.brakeCodePrefix}${selectedBrake.resourceKey}`; - event.techRecord_brakes_dataTrBrakeOne = selectedBrake.service; - event.techRecord_brakes_dataTrBrakeTwo = selectedBrake.secondary; - event.techRecord_brakes_dataTrBrakeThree = selectedBrake.parking; - } - - if (event?.techRecord_axles) { - event.techRecord_axles = event.techRecord_axles.filter((axle) => !!axle?.axleNumber); - } - - this.formChange.emit(event); - - if (event.techRecord_brakes_brakeCodeOriginal) { - this.store.dispatch(updateBrakeForces({})); - } - }); - - this.optionsService.loadOptions(ReferenceDataResourceType.Brakes); - } - - ngOnChanges(changes: SimpleChanges): void { - const { vehicleTechRecord } = changes; - - if (this.form && vehicleTechRecord?.currentValue && vehicleTechRecord.currentValue !== vehicleTechRecord.previousValue) { - this.form.patchValue(vehicleTechRecord.currentValue, { emitEvent: false }); - } - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - get brakeCode(): string { - return `${this.brakeCodePrefix}${this.form.get('techRecord_brakes_brakeCodeOriginal')?.value}`; - } - - get brakesForm(): FormGroup { - return this.form.get('brakes') as FormGroup; - } - - get booleanOptions(): MultiOptions { - return [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ]; - } - - get retarderOptions(): MultiOptions { - return getOptionsFromEnum(Retarders); - } - - get brakeCodeOptions$(): Observable { - return this.optionsService.getOptions(ReferenceDataResourceType.Brakes) as Observable; - } - - get editTypes(): typeof FormNodeEditTypes { - return FormNodeEditTypes; - } - - get widths(): typeof FormNodeWidth { - return FormNodeWidth; - } - - get brakeCodePrefix(): string { - if (!this.vehicleTechRecord?.techRecord_grossLadenWeight) { - return ''; - } - const prefix = `${Math.round(this.vehicleTechRecord.techRecord_grossLadenWeight / 100)}`; - - return prefix.length <= 2 ? `0${prefix}` : prefix; - } - - get axles(): FormArray { - return this.form.get(['techRecord_axles']) as FormArray; - } - - getAxleForm(i: number): FormGroup { - return this.form.get(['techRecord_axles', i]) as FormGroup; - } - - round(n: number): number { - return Math.round(n); - } + @Input() vehicleTechRecord?: TechRecordType<'psv'>; + @Input() isEditing = false; + + @Output() formChange = new EventEmitter(); + + form!: CustomFormGroup; + template!: FormNode; + + selectedBrake?: Brake; + + private destroy$ = new Subject(); + + constructor( + private dfs: DynamicFormService, + private optionsService: MultiOptionsService, + private referenceDataStore: Store, + private store: Store + ) {} + + ngOnInit(): void { + this.form = this.dfs.createForm(PsvBrakesTemplate, this.vehicleTechRecord) as CustomFormGroup; + + (this.form.cleanValueChanges as Observable>>) + .pipe( + switchMap((event) => { + return event?.techRecord_brakes_brakeCodeOriginal + ? this.referenceDataStore.select(selectBrakeByCode(event.techRecord_brakes_brakeCodeOriginal)) + : of(undefined); + }), + withLatestFrom(this.form.cleanValueChanges as Observable>>), + debounceTime(400), + takeUntil(this.destroy$) + ) + .subscribe(([selectedBrake, event]) => { + // Set the brake details automatically based selection + if (selectedBrake && event?.techRecord_brakes_brakeCodeOriginal) { + event.techRecord_brakeCode = `${this.brakeCodePrefix}${selectedBrake.resourceKey}`; + event.techRecord_brakes_brakeCode = `${this.brakeCodePrefix}${selectedBrake.resourceKey}`; + event.techRecord_brakes_dataTrBrakeOne = selectedBrake.service; + event.techRecord_brakes_dataTrBrakeTwo = selectedBrake.secondary; + event.techRecord_brakes_dataTrBrakeThree = selectedBrake.parking; + } + + if (event?.techRecord_axles) { + event.techRecord_axles = event.techRecord_axles.filter((axle) => !!axle?.axleNumber); + } + + this.formChange.emit(event); + + if (event.techRecord_brakes_brakeCodeOriginal) { + this.store.dispatch(updateBrakeForces({})); + } + }); + + this.optionsService.loadOptions(ReferenceDataResourceType.Brakes); + } + + ngOnChanges(changes: SimpleChanges): void { + const { vehicleTechRecord } = changes; + + if ( + this.form && + vehicleTechRecord?.currentValue && + vehicleTechRecord.currentValue !== vehicleTechRecord.previousValue + ) { + this.form.patchValue(vehicleTechRecord.currentValue, { emitEvent: false }); + } + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + get brakeCode(): string { + return `${this.brakeCodePrefix}${this.form.get('techRecord_brakes_brakeCodeOriginal')?.value}`; + } + + get brakesForm(): FormGroup { + return this.form.get('brakes') as FormGroup; + } + + get booleanOptions(): MultiOptions { + return [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ]; + } + + get retarderOptions(): MultiOptions { + return getOptionsFromEnum(Retarders); + } + + get brakeCodeOptions$(): Observable { + return this.optionsService.getOptions(ReferenceDataResourceType.Brakes) as Observable; + } + + get editTypes(): typeof FormNodeEditTypes { + return FormNodeEditTypes; + } + + get widths(): typeof FormNodeWidth { + return FormNodeWidth; + } + + get brakeCodePrefix(): string { + if (!this.vehicleTechRecord?.techRecord_grossLadenWeight) { + return ''; + } + const prefix = `${Math.round(this.vehicleTechRecord.techRecord_grossLadenWeight / 100)}`; + + return prefix.length <= 2 ? `0${prefix}` : prefix; + } + + get axles(): FormArray { + return this.form.get(['techRecord_axles']) as FormArray; + } + + getAxleForm(i: number): FormGroup { + return this.form.get(['techRecord_axles', i]) as FormGroup; + } + + round(n: number): number { + return Math.round(n); + } } diff --git a/src/app/forms/custom-sections/required-standard/required-standard.component.spec.ts b/src/app/forms/custom-sections/required-standard/required-standard.component.spec.ts index ef3afe706a..d8b0e9ed9b 100644 --- a/src/app/forms/custom-sections/required-standard/required-standard.component.spec.ts +++ b/src/app/forms/custom-sections/required-standard/required-standard.component.spec.ts @@ -16,173 +16,173 @@ import { testResultInEdit } from '@store/test-records'; import { RequiredStandardComponent } from './required-standard.component'; describe('RequiredStandardComponent', () => { - let component: RequiredStandardComponent; - let fixture: ComponentFixture; - let router: Router; - let store: MockStore; - let resultService: ResultOfTestService; - let dfs: DynamicFormService; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [FormsModule, ReactiveFormsModule, RouterTestingModule, HttpClientTestingModule], - declarations: [RequiredStandardComponent], - providers: [DynamicFormService, provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(RequiredStandardComponent); - router = TestBed.inject(Router); - store = TestBed.inject(MockStore); - resultService = TestBed.inject(ResultOfTestService); - dfs = TestBed.inject(DynamicFormService); - component = fixture.componentInstance; - jest.clearAllMocks(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('ngOnInit', () => { - it('should init and navigate back if no test result', () => { - component.isEditing = true; - store.overrideSelector(testResultInEdit, undefined); - const spy = jest.spyOn(component, 'navigateBack'); - - component.ngOnInit(); - - expect(spy).toHaveBeenCalledTimes(1); - }); - - it('should init and use index to amend the required standard', () => { - component.isEditing = true; - store.overrideSelector( - testResultInEdit, - mockTestResult(), - ); - store.overrideSelector(selectRouteParams, { requiredStandardIndex: '0' }); - component.ngOnInit(); - - expect(component.amendingRs).toBeTruthy(); - expect(component.requiredStandard).toBeDefined(); - }); - - it('should init and get required standard from the store', () => { - component.isEditing = true; - store.overrideSelector( - testResultInEdit, - mockTestResult(), - ); - store.overrideSelector(selectRouteParams, { ref: '1.1', inspectionType: 'basic', requiredStandardIndex: undefined }); - - store.overrideSelector( - getRequiredStandardFromTypeAndRef(INSPECTION_TYPE.BASIC, '1.1'), - { sectionNumber: '1' } as unknown as TestResultRequiredStandard, - ); - - component.ngOnInit(); - - expect(component.amendingRs).toBeFalsy(); - expect(component.requiredStandard).toBeDefined(); - }); - - it('should init and fail to required standard from the store so navigate back', () => { - component.isEditing = true; - store.overrideSelector( - testResultInEdit, - mockTestResult(), - ); - store.overrideSelector(selectRouteParams, { ref: '1.1', inspectionType: 'basic', requiredStandardIndex: undefined }); - - store.overrideSelector( - getRequiredStandardFromTypeAndRef(INSPECTION_TYPE.BASIC, '1.1'), - undefined, - ); - const spy = jest.spyOn(component, 'navigateBack'); - - component.ngOnInit(); - - expect(spy).toHaveBeenCalledTimes(1); - }); - }); - - describe('navigateBack', () => { - it('should navigate back two levels if in amend mode', () => { - jest.spyOn(resultService, 'updateResultOfTestRequiredStandards').getMockImplementation(); - component.amendingRs = true; - const spy = jest.spyOn(router, 'navigate'); - - component.navigateBack(); - - expect(spy).toHaveBeenCalledWith(['../../'], expect.anything()); - - }); - - it('should navigate back three levels if not in amend mode', () => { - jest.spyOn(resultService, 'updateResultOfTestRequiredStandards').getMockImplementation(); - component.amendingRs = false; - const spy = jest.spyOn(router, 'navigate'); - - component.navigateBack(); - - expect(spy).toHaveBeenCalledWith(['../../../'], expect.anything()); - }); - }); - - describe('toggleRsPrsField', () => { - it('should error if there is no required standard', () => { - component.requiredStandard = undefined; - - const res = component.toggleRsPrsField(); - - expect(res).toBeUndefined(); - }); - it('should flip bool value of prs', () => { - component.requiredStandard = { prs: true } as unknown as TestResultRequiredStandard; - - component.toggleRsPrsField(); - - expect(component.requiredStandard).toStrictEqual({ prs: false }); - }); - }); - - describe('handleSubmit', () => { - beforeEach(() => { - component.form = dfs.createForm({ - name: 'test section', - type: FormNodeTypes.SECTION, - children: [{ name: 'prs', type: FormNodeTypes.CONTROL }], - }, { prs: false }) as CustomFormGroup; - }); - it('should return if the form is invalid', () => { - jest.spyOn(DynamicFormService, 'validate').mockImplementation(); - component.form.controls['prs'].setErrors({ incorrect: true }); - - const res = component.handleSubmit(); - - expect(res).toBeUndefined(); - }); - - it('should call update RS if in amend mode', () => { - jest.spyOn(DynamicFormService, 'validate').mockImplementation(); - component.index = 1; - const dispatchSpy = jest.spyOn(store, 'dispatch'); - - component.handleSubmit(); - - expect(dispatchSpy).toHaveBeenCalledWith(expect.objectContaining({ type: '[test-results] update required standard' })); - }); - - it('should call create RS if not in amend mode', () => { - jest.spyOn(DynamicFormService, 'validate').mockImplementation(); - const dispatchSpy = jest.spyOn(store, 'dispatch'); - - component.handleSubmit(); - - expect(dispatchSpy).toHaveBeenCalledWith(expect.objectContaining({ type: '[test-results] create required standard' })); - }); - }); - + let component: RequiredStandardComponent; + let fixture: ComponentFixture; + let router: Router; + let store: MockStore; + let resultService: ResultOfTestService; + let dfs: DynamicFormService; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [FormsModule, ReactiveFormsModule, RouterTestingModule, HttpClientTestingModule], + declarations: [RequiredStandardComponent], + providers: [DynamicFormService, provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(RequiredStandardComponent); + router = TestBed.inject(Router); + store = TestBed.inject(MockStore); + resultService = TestBed.inject(ResultOfTestService); + dfs = TestBed.inject(DynamicFormService); + component = fixture.componentInstance; + jest.clearAllMocks(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('ngOnInit', () => { + it('should init and navigate back if no test result', () => { + component.isEditing = true; + store.overrideSelector(testResultInEdit, undefined); + const spy = jest.spyOn(component, 'navigateBack'); + + component.ngOnInit(); + + expect(spy).toHaveBeenCalledTimes(1); + }); + + it('should init and use index to amend the required standard', () => { + component.isEditing = true; + store.overrideSelector(testResultInEdit, mockTestResult()); + store.overrideSelector(selectRouteParams, { requiredStandardIndex: '0' }); + component.ngOnInit(); + + expect(component.amendingRs).toBeTruthy(); + expect(component.requiredStandard).toBeDefined(); + }); + + it('should init and get required standard from the store', () => { + component.isEditing = true; + store.overrideSelector(testResultInEdit, mockTestResult()); + store.overrideSelector(selectRouteParams, { + ref: '1.1', + inspectionType: 'basic', + requiredStandardIndex: undefined, + }); + + store.overrideSelector(getRequiredStandardFromTypeAndRef(INSPECTION_TYPE.BASIC, '1.1'), { + sectionNumber: '1', + } as unknown as TestResultRequiredStandard); + + component.ngOnInit(); + + expect(component.amendingRs).toBeFalsy(); + expect(component.requiredStandard).toBeDefined(); + }); + + it('should init and fail to required standard from the store so navigate back', () => { + component.isEditing = true; + store.overrideSelector(testResultInEdit, mockTestResult()); + store.overrideSelector(selectRouteParams, { + ref: '1.1', + inspectionType: 'basic', + requiredStandardIndex: undefined, + }); + + store.overrideSelector(getRequiredStandardFromTypeAndRef(INSPECTION_TYPE.BASIC, '1.1'), undefined); + const spy = jest.spyOn(component, 'navigateBack'); + + component.ngOnInit(); + + expect(spy).toHaveBeenCalledTimes(1); + }); + }); + + describe('navigateBack', () => { + it('should navigate back two levels if in amend mode', () => { + jest.spyOn(resultService, 'updateResultOfTestRequiredStandards').getMockImplementation(); + component.amendingRs = true; + const spy = jest.spyOn(router, 'navigate'); + + component.navigateBack(); + + expect(spy).toHaveBeenCalledWith(['../../'], expect.anything()); + }); + + it('should navigate back three levels if not in amend mode', () => { + jest.spyOn(resultService, 'updateResultOfTestRequiredStandards').getMockImplementation(); + component.amendingRs = false; + const spy = jest.spyOn(router, 'navigate'); + + component.navigateBack(); + + expect(spy).toHaveBeenCalledWith(['../../../'], expect.anything()); + }); + }); + + describe('toggleRsPrsField', () => { + it('should error if there is no required standard', () => { + component.requiredStandard = undefined; + + const res = component.toggleRsPrsField(); + + expect(res).toBeUndefined(); + }); + it('should flip bool value of prs', () => { + component.requiredStandard = { prs: true } as unknown as TestResultRequiredStandard; + + component.toggleRsPrsField(); + + expect(component.requiredStandard).toStrictEqual({ prs: false }); + }); + }); + + describe('handleSubmit', () => { + beforeEach(() => { + component.form = dfs.createForm( + { + name: 'test section', + type: FormNodeTypes.SECTION, + children: [{ name: 'prs', type: FormNodeTypes.CONTROL }], + }, + { prs: false } + ) as CustomFormGroup; + }); + it('should return if the form is invalid', () => { + jest.spyOn(DynamicFormService, 'validate').mockImplementation(); + component.form.controls['prs'].setErrors({ incorrect: true }); + + const res = component.handleSubmit(); + + expect(res).toBeUndefined(); + }); + + it('should call update RS if in amend mode', () => { + jest.spyOn(DynamicFormService, 'validate').mockImplementation(); + component.index = 1; + const dispatchSpy = jest.spyOn(store, 'dispatch'); + + component.handleSubmit(); + + expect(dispatchSpy).toHaveBeenCalledWith( + expect.objectContaining({ type: '[test-results] update required standard' }) + ); + }); + + it('should call create RS if not in amend mode', () => { + jest.spyOn(DynamicFormService, 'validate').mockImplementation(); + const dispatchSpy = jest.spyOn(store, 'dispatch'); + + component.handleSubmit(); + + expect(dispatchSpy).toHaveBeenCalledWith( + expect.objectContaining({ type: '[test-results] create required standard' }) + ); + }); + }); }); diff --git a/src/app/forms/custom-sections/required-standard/required-standard.component.ts b/src/app/forms/custom-sections/required-standard/required-standard.component.ts index 51a35c9e36..4d8f112977 100644 --- a/src/app/forms/custom-sections/required-standard/required-standard.component.ts +++ b/src/app/forms/custom-sections/required-standard/required-standard.component.ts @@ -1,6 +1,4 @@ -import { - ChangeDetectionStrategy, Component, OnDestroy, OnInit, -} from '@angular/core'; +import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalError } from '@core/components/global-error/global-error.interface'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; @@ -14,124 +12,145 @@ import { DefaultNullOrEmpty } from '@shared/pipes/default-null-or-empty/default- import { getRequiredStandardFromTypeAndRef } from '@store/required-standards/selectors/required-standards.selector'; import { selectRouteParam } from '@store/router/selectors/router.selectors'; import { - createRequiredStandard, removeRequiredStandard, testResultInEdit, toEditOrNotToEdit, updateRequiredStandard, + createRequiredStandard, + removeRequiredStandard, + testResultInEdit, + toEditOrNotToEdit, + updateRequiredStandard, } from '@store/test-records'; -import { - Subject, distinctUntilChanged, - takeUntil, withLatestFrom, -} from 'rxjs'; +import { Subject, distinctUntilChanged, takeUntil, withLatestFrom } from 'rxjs'; @Component({ - selector: 'app-required-standard', - templateUrl: './required-standard.component.html', - providers: [DefaultNullOrEmpty], - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-required-standard', + templateUrl: './required-standard.component.html', + providers: [DefaultNullOrEmpty], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class RequiredStandardComponent implements OnInit, OnDestroy { - form!: CustomFormGroup; - index!: number; - requiredStandard?: TestResultRequiredStandard; - onDestroy$ = new Subject(); - isEditing: boolean; - amendingRs?: boolean; - - private requiredStandardForm?: CustomFormArray; + form!: CustomFormGroup; + index!: number; + requiredStandard?: TestResultRequiredStandard; + onDestroy$ = new Subject(); + isEditing: boolean; + amendingRs?: boolean; - constructor( - private store: Store, - private activatedRoute: ActivatedRoute, - private resultService: ResultOfTestService, - private router: Router, - private dfs: DynamicFormService, - private errorService: GlobalErrorService, - ) { - this.isEditing = this.activatedRoute.snapshot.data['isEditing']; - } + private requiredStandardForm?: CustomFormArray; - ngOnInit(): void { - const inspectionType = this.store.pipe(select(selectRouteParam('inspectionType'))); - const rsRefCalculation = this.store.pipe(select(selectRouteParam('ref'))); - const requiredStandardIndex = this.store.pipe(select(selectRouteParam('requiredStandardIndex'))); + constructor( + private store: Store, + private activatedRoute: ActivatedRoute, + private resultService: ResultOfTestService, + private router: Router, + private dfs: DynamicFormService, + private errorService: GlobalErrorService + ) { + this.isEditing = this.activatedRoute.snapshot.data['isEditing']; + } - this.store.pipe(select(this.isEditing ? testResultInEdit : toEditOrNotToEdit)).pipe( - withLatestFrom(inspectionType, rsRefCalculation, requiredStandardIndex), - takeUntil(this.onDestroy$), - distinctUntilChanged((prev, curr) => prev[0]?.testTypes[0]?.testResult === curr[0]?.testTypes[0]?.testResult), - ).subscribe(([testResult, inspectionTypeValue, rsRefCalculationValue, requiredStandardIndexValue]) => { - if (!testResult) this.navigateBack(); - this.requiredStandardForm = (this.dfs.createForm(RequiredStandardsTpl, testResult) as CustomFormGroup) - .get(['testTypes', '0', 'requiredStandards']) as CustomFormArray; - if (requiredStandardIndexValue) { - this.amendingRs = true; - this.index = Number(requiredStandardIndexValue); - this.form = this.requiredStandardForm.controls[this.index] as CustomFormGroup; - this.requiredStandard = testResult?.testTypes[0]?.requiredStandards?.at(this.index); - } else { - this.amendingRs = false; - this.store.pipe( - select(getRequiredStandardFromTypeAndRef(inspectionTypeValue as INSPECTION_TYPE, rsRefCalculationValue ?? '')), - takeUntil(this.onDestroy$), - ) - .subscribe((requiredStandard) => { - if (!requiredStandard) this.navigateBack(); - const rsControl = { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - ...requiredStandard!, - prs: false, - additionalNotes: '', - }; + ngOnInit(): void { + const inspectionType = this.store.pipe(select(selectRouteParam('inspectionType'))); + const rsRefCalculation = this.store.pipe(select(selectRouteParam('ref'))); + const requiredStandardIndex = this.store.pipe(select(selectRouteParam('requiredStandardIndex'))); - this.requiredStandard = rsControl; - this.requiredStandardForm?.addControl(rsControl); - this.form = this.requiredStandardForm?.controls[this.index ?? this.requiredStandardForm.length - 1] as CustomFormGroup; + this.store + .pipe(select(this.isEditing ? testResultInEdit : toEditOrNotToEdit)) + .pipe( + withLatestFrom(inspectionType, rsRefCalculation, requiredStandardIndex), + takeUntil(this.onDestroy$), + distinctUntilChanged((prev, curr) => prev[0]?.testTypes[0]?.testResult === curr[0]?.testTypes[0]?.testResult) + ) + .subscribe(([testResult, inspectionTypeValue, rsRefCalculationValue, requiredStandardIndexValue]) => { + if (!testResult) this.navigateBack(); + this.requiredStandardForm = (this.dfs.createForm(RequiredStandardsTpl, testResult) as CustomFormGroup).get([ + 'testTypes', + '0', + 'requiredStandards', + ]) as CustomFormArray; + if (requiredStandardIndexValue) { + this.amendingRs = true; + this.index = Number(requiredStandardIndexValue); + this.form = this.requiredStandardForm.controls[this.index] as CustomFormGroup; + this.requiredStandard = testResult?.testTypes[0]?.requiredStandards?.at(this.index); + } else { + this.amendingRs = false; + this.store + .pipe( + select( + getRequiredStandardFromTypeAndRef(inspectionTypeValue as INSPECTION_TYPE, rsRefCalculationValue ?? '') + ), + takeUntil(this.onDestroy$) + ) + .subscribe((requiredStandard) => { + if (!requiredStandard) this.navigateBack(); + const rsControl = { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + ...requiredStandard!, + prs: false, + additionalNotes: '', + }; - }); - } - }); - } + this.requiredStandard = rsControl; + this.requiredStandardForm?.addControl(rsControl); + this.form = this.requiredStandardForm?.controls[ + this.index ?? this.requiredStandardForm.length - 1 + ] as CustomFormGroup; + }); + } + }); + } - ngOnDestroy(): void { - this.onDestroy$.next(true); - this.onDestroy$.complete(); - } + ngOnDestroy(): void { + this.onDestroy$.next(true); + this.onDestroy$.complete(); + } - navigateBack() { - this.resultService.updateResultOfTestRequiredStandards(); - void this.router.navigate(this.amendingRs ? ['../../'] : ['../../../'], { relativeTo: this.activatedRoute, queryParamsHandling: 'preserve' }); - } + navigateBack() { + this.resultService.updateResultOfTestRequiredStandards(); + void this.router.navigate(this.amendingRs ? ['../../'] : ['../../../'], { + relativeTo: this.activatedRoute, + queryParamsHandling: 'preserve', + }); + } - toggleRsPrsField() { - if (!this.requiredStandard) { - return; - } - this.requiredStandard.prs = !this.requiredStandard.prs; - this.requiredStandardForm?.controls[this.index ?? this.requiredStandardForm.length - 1].get('prs')?.patchValue(this.requiredStandard.prs); - } + toggleRsPrsField() { + if (!this.requiredStandard) { + return; + } + this.requiredStandard.prs = !this.requiredStandard.prs; + this.requiredStandardForm?.controls[this.index ?? this.requiredStandardForm.length - 1] + .get('prs') + ?.patchValue(this.requiredStandard.prs); + } - handleSubmit() { - const errors: GlobalError[] = []; - DynamicFormService.validate(this.form, errors); + handleSubmit() { + const errors: GlobalError[] = []; + DynamicFormService.validate(this.form, errors); - if (errors.length > 0) { - this.errorService.setErrors(errors); - } + if (errors.length > 0) { + this.errorService.setErrors(errors); + } - if (this.form.invalid) { - return; - } + if (this.form.invalid) { + return; + } - if (this.index || this.index === 0) { - this.store.dispatch( - updateRequiredStandard({ requiredStandard: this.form.getCleanValue(this.form) as TestResultRequiredStandard, index: this.index }), - ); - } else { - this.store.dispatch(createRequiredStandard({ requiredStandard: this.form.getCleanValue(this.form) as TestResultRequiredStandard })); - } - this.navigateBack(); - } + if (this.index || this.index === 0) { + this.store.dispatch( + updateRequiredStandard({ + requiredStandard: this.form.getCleanValue(this.form) as TestResultRequiredStandard, + index: this.index, + }) + ); + } else { + this.store.dispatch( + createRequiredStandard({ requiredStandard: this.form.getCleanValue(this.form) as TestResultRequiredStandard }) + ); + } + this.navigateBack(); + } - handleRemove() { - this.store.dispatch(removeRequiredStandard({ index: this.index })); - this.navigateBack(); - } + handleRemove() { + this.store.dispatch(removeRequiredStandard({ index: this.index })); + this.navigateBack(); + } } diff --git a/src/app/forms/custom-sections/required-standards/required-standards.component.spec.ts b/src/app/forms/custom-sections/required-standards/required-standards.component.spec.ts index 4565712825..74a5ec5554 100644 --- a/src/app/forms/custom-sections/required-standards/required-standards.component.spec.ts +++ b/src/app/forms/custom-sections/required-standards/required-standards.component.spec.ts @@ -1,8 +1,6 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { DebugElement } from '@angular/core'; -import { - ComponentFixture, TestBed, fakeAsync, tick, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { Router } from '@angular/router'; @@ -17,80 +15,78 @@ import { initialAppState } from '@store/index'; import { RequiredStandardsComponent } from './required-standards.component'; describe('RequiredStandardsComponent', () => { - let component: RequiredStandardsComponent; - let fixture: ComponentFixture; - let el: DebugElement; - let router: Router; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [FormsModule, ReactiveFormsModule, RouterTestingModule, HttpClientTestingModule], - declarations: [RequiredStandardsComponent, ButtonComponent, TruncatePipe, TagComponent], - providers: [DynamicFormService, provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(RequiredStandardsComponent); - router = TestBed.inject(Router); - component = fixture.componentInstance; - el = fixture.debugElement; - jest.clearAllMocks(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should render correct header', () => { - fixture.detectChanges(); - expect(el.query(By.css('h2')).nativeElement.innerHTML).toBe('Required Standards'); - }); - - describe('No required standards', () => { - it('should be displayed when required standards is undefined or empty array', fakeAsync(() => { - const expectedText = 'No required standards'; - - tick(); - fixture.detectChanges(); - - let text: HTMLParagraphElement = el.query(By.css('p')).nativeElement; - expect(text.innerHTML).toBe(expectedText); - - tick(); - fixture.detectChanges(); - - text = el.query(By.css('p')).nativeElement; - expect(text.innerHTML).toBe(expectedText); - })); - }); - - describe('onAddRequiredStandards', () => { - it('should let me add a RS and call the navigator', () => { - - const spy = jest.spyOn(router, 'navigate'); - - component.testData = { - euVehicleCategory: EUVehicleCategory.M1, - }; - - component.onAddRequiredStandard(); - - expect(spy).toHaveBeenCalledTimes(1); - - }); - it('should not add a RS and emit a value to the parent', () => { - const spy = jest.spyOn(router, 'navigate'); - const emitSpy = jest.spyOn(component.validateEuVehicleCategory, 'emit'); - - component.testData = { - testerName: 'bar', - }; - - component.onAddRequiredStandard(); - - expect(spy).toHaveBeenCalledTimes(0); - expect(emitSpy).toHaveBeenCalledTimes(1); - }); - }); + let component: RequiredStandardsComponent; + let fixture: ComponentFixture; + let el: DebugElement; + let router: Router; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [FormsModule, ReactiveFormsModule, RouterTestingModule, HttpClientTestingModule], + declarations: [RequiredStandardsComponent, ButtonComponent, TruncatePipe, TagComponent], + providers: [DynamicFormService, provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(RequiredStandardsComponent); + router = TestBed.inject(Router); + component = fixture.componentInstance; + el = fixture.debugElement; + jest.clearAllMocks(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should render correct header', () => { + fixture.detectChanges(); + expect(el.query(By.css('h2')).nativeElement.innerHTML).toBe('Required Standards'); + }); + + describe('No required standards', () => { + it('should be displayed when required standards is undefined or empty array', fakeAsync(() => { + const expectedText = 'No required standards'; + + tick(); + fixture.detectChanges(); + + let text: HTMLParagraphElement = el.query(By.css('p')).nativeElement; + expect(text.innerHTML).toBe(expectedText); + + tick(); + fixture.detectChanges(); + + text = el.query(By.css('p')).nativeElement; + expect(text.innerHTML).toBe(expectedText); + })); + }); + + describe('onAddRequiredStandards', () => { + it('should let me add a RS and call the navigator', () => { + const spy = jest.spyOn(router, 'navigate'); + + component.testData = { + euVehicleCategory: EUVehicleCategory.M1, + }; + + component.onAddRequiredStandard(); + + expect(spy).toHaveBeenCalledTimes(1); + }); + it('should not add a RS and emit a value to the parent', () => { + const spy = jest.spyOn(router, 'navigate'); + const emitSpy = jest.spyOn(component.validateEuVehicleCategory, 'emit'); + + component.testData = { + testerName: 'bar', + }; + + component.onAddRequiredStandard(); + + expect(spy).toHaveBeenCalledTimes(0); + expect(emitSpy).toHaveBeenCalledTimes(1); + }); + }); }); diff --git a/src/app/forms/custom-sections/required-standards/required-standards.component.ts b/src/app/forms/custom-sections/required-standards/required-standards.component.ts index 812796ee4f..e2c34e3a12 100644 --- a/src/app/forms/custom-sections/required-standards/required-standards.component.ts +++ b/src/app/forms/custom-sections/required-standards/required-standards.component.ts @@ -1,7 +1,5 @@ import { ViewportScroller } from '@angular/common'; -import { - Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, -} from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalErrorService } from '@core/components/global-error/global-error.service'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; @@ -12,91 +10,91 @@ import { Store, select } from '@ngrx/store'; import { ResultOfTestService } from '@services/result-of-test/result-of-test.service'; import { testResultInEdit } from '@store/test-records'; import { isEqual } from 'lodash'; -import { - Subject, Subscription, debounceTime, distinctUntilChanged, - takeUntil, -} from 'rxjs'; +import { Subject, Subscription, debounceTime, distinctUntilChanged, takeUntil } from 'rxjs'; @Component({ - selector: 'app-required-standards[template]', - templateUrl: './required-standards.component.html', + selector: 'app-required-standards[template]', + templateUrl: './required-standards.component.html', }) export class RequiredStandardsComponent implements OnInit, OnDestroy, OnChanges { - @Input() isEditing = false; - @Input() template!: FormNode; - @Input() testData: Partial = {}; + @Input() isEditing = false; + @Input() template!: FormNode; + @Input() testData: Partial = {}; - @Output() formChange = new EventEmitter(); - @Output() validateEuVehicleCategory = new EventEmitter(); + @Output() formChange = new EventEmitter(); + @Output() validateEuVehicleCategory = new EventEmitter(); - public form!: CustomFormGroup; - private formSubscription = new Subscription(); - private requiredStandardsFormArray?: CustomFormArray; + public form!: CustomFormGroup; + private formSubscription = new Subscription(); + private requiredStandardsFormArray?: CustomFormArray; - onDestroy$ = new Subject(); + onDestroy$ = new Subject(); - constructor( - private dfs: DynamicFormService, - private router: Router, - private route: ActivatedRoute, - private viewportScroller: ViewportScroller, - private globalErrorService: GlobalErrorService, - private resultService: ResultOfTestService, - private store: Store, - ) {} + constructor( + private dfs: DynamicFormService, + private router: Router, + private route: ActivatedRoute, + private viewportScroller: ViewportScroller, + private globalErrorService: GlobalErrorService, + private resultService: ResultOfTestService, + private store: Store + ) {} - ngOnInit(): void { - this.form = this.dfs.createForm(this.template, this.testData) as CustomFormGroup; - this.formSubscription = this.form.cleanValueChanges.pipe(debounceTime(400)).subscribe((event) => { - this.formChange.emit(event); - }); - this.store.pipe(select(testResultInEdit)).pipe( - takeUntil(this.onDestroy$), - distinctUntilChanged((prev, curr) => isEqual(prev?.testTypes?.at(0)?.requiredStandards, curr?.testTypes?.at(0)?.requiredStandards)), - ) - .subscribe(() => { - this.resultService.updateResultOfTestRequiredStandards(); - }); - } + ngOnInit(): void { + this.form = this.dfs.createForm(this.template, this.testData) as CustomFormGroup; + this.formSubscription = this.form.cleanValueChanges.pipe(debounceTime(400)).subscribe((event) => { + this.formChange.emit(event); + }); + this.store + .pipe(select(testResultInEdit)) + .pipe( + takeUntil(this.onDestroy$), + distinctUntilChanged((prev, curr) => + isEqual(prev?.testTypes?.at(0)?.requiredStandards, curr?.testTypes?.at(0)?.requiredStandards) + ) + ) + .subscribe(() => { + this.resultService.updateResultOfTestRequiredStandards(); + }); + } - ngOnDestroy(): void { - this.formSubscription.unsubscribe(); - } + ngOnDestroy(): void { + this.formSubscription.unsubscribe(); + } - ngOnChanges(changes: SimpleChanges): void { - const { testData } = changes; + ngOnChanges(changes: SimpleChanges): void { + const { testData } = changes; - if (testData?.currentValue?.euVehicleCategory !== testData?.previousValue?.euVehicleCategory) { - this.form?.get(['testTypes', '0', 'requiredStandards'])?.patchValue([], { emitEvent: true }); - } + if (testData?.currentValue?.euVehicleCategory !== testData?.previousValue?.euVehicleCategory) { + this.form?.get(['testTypes', '0', 'requiredStandards'])?.patchValue([], { emitEvent: true }); + } + } - } + onAddRequiredStandard(): void { + this.globalErrorService.clearErrors(); + if (!this.testData?.euVehicleCategory) { + this.validateEuVehicleCategory.emit(); + this.viewportScroller.scrollToPosition([0, 0]); + return; + } + void this.router.navigate(['selectRequiredStandard'], { queryParamsHandling: 'preserve', relativeTo: this.route }); + } - onAddRequiredStandard(): void { - this.globalErrorService.clearErrors(); - if (!this.testData?.euVehicleCategory) { - this.validateEuVehicleCategory.emit(); - this.viewportScroller.scrollToPosition([0, 0]); - return; - } - void this.router.navigate(['selectRequiredStandard'], { queryParamsHandling: 'preserve', relativeTo: this.route }); - } + get requiredStandardsForm(): CustomFormArray { + if (!this.requiredStandardsFormArray) { + this.requiredStandardsFormArray = this.form?.get(['testTypes', '0', 'requiredStandards']) as CustomFormArray; + } + return this.requiredStandardsFormArray; + } - get requiredStandardsForm(): CustomFormArray { - if (!this.requiredStandardsFormArray) { - this.requiredStandardsFormArray = this.form?.get(['testTypes', '0', 'requiredStandards']) as CustomFormArray; - } - return this.requiredStandardsFormArray; - } + get requiredStandardsCount(): number { + return this.requiredStandardsForm?.controls.length; + } - get requiredStandardsCount(): number { - return this.requiredStandardsForm?.controls.length; - } - - get testRequiredStandards(): TestResultRequiredStandard[] { - return this.requiredStandardsForm.controls.map((control) => { - const formGroup = control as CustomFormGroup; - return formGroup.getCleanValue(formGroup) as TestResultRequiredStandard; - }); - } + get testRequiredStandards(): TestResultRequiredStandard[] { + return this.requiredStandardsForm.controls.map((control) => { + const formGroup = control as CustomFormGroup; + return formGroup.getCleanValue(formGroup) as TestResultRequiredStandard; + }); + } } diff --git a/src/app/forms/custom-sections/trl-brakes/trl-brakes.component.spec.ts b/src/app/forms/custom-sections/trl-brakes/trl-brakes.component.spec.ts index c62b3e86dd..9c28fbe1ee 100644 --- a/src/app/forms/custom-sections/trl-brakes/trl-brakes.component.spec.ts +++ b/src/app/forms/custom-sections/trl-brakes/trl-brakes.component.spec.ts @@ -5,102 +5,107 @@ import { DynamicFormsModule } from '@forms/dynamic-forms.module'; import { provideMockStore } from '@ngrx/store/testing'; import { initialAppState } from '@store/index'; -import { TechRecordTRL, TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; +import { + TechRecordTRL, + TechRecordType, +} from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; import { mockVehicleTechnicalRecord } from '@mocks/mock-vehicle-technical-record.mock'; import { TrlBrakesComponent } from './trl-brakes.component'; describe('BrakesComponent', () => { - let component: TrlBrakesComponent; - let fixture: ComponentFixture; + let component: TrlBrakesComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TrlBrakesComponent], - imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule], - providers: [provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TrlBrakesComponent], + imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule], + providers: [provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TrlBrakesComponent); - component = fixture.componentInstance; - component.vehicleTechRecord = mockVehicleTechnicalRecord('trl') as TechRecordType<'trl'>; - component.vehicleTechRecord.techRecord_axles = [ - { - parkingBrakeMrk: true, - axleNumber: 1, - brakes_brakeActuator: 1, - brakes_leverLength: 1, - brakes_springBrakeParking: true, - weights_gbWeight: 1, - weights_designWeight: 2, - weights_ladenWeight: 3, - weights_kerbWeight: 4, - tyres_tyreCode: 1, - tyres_tyreSize: '2', - tyres_plyRating: '3', - tyres_fitmentCode: 'single', - tyres_dataTrAxles: 1, - tyres_speedCategorySymbol: 'a7', - }, - { - parkingBrakeMrk: true, - axleNumber: 2, - brakes_brakeActuator: 1, - brakes_leverLength: 1, - brakes_springBrakeParking: false, - weights_gbWeight: 1, - weights_designWeight: 2, - weights_ladenWeight: 3, - weights_kerbWeight: 4, - tyres_tyreCode: 1, - tyres_tyreSize: '2', - tyres_plyRating: '3', - tyres_fitmentCode: 'single', - tyres_dataTrAxles: 1, - tyres_speedCategorySymbol: 'a7', - }, - { - parkingBrakeMrk: false, - axleNumber: 3, - brakes_brakeActuator: 1, - brakes_leverLength: 1, - brakes_springBrakeParking: true, - weights_gbWeight: 1, - weights_designWeight: 2, - weights_ladenWeight: 3, - weights_kerbWeight: 4, - tyres_tyreCode: 1, - tyres_tyreSize: '2', - tyres_plyRating: '3', - tyres_fitmentCode: 'single', - tyres_dataTrAxles: 1, - tyres_speedCategorySymbol: 'a7', - }, - ]; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(TrlBrakesComponent); + component = fixture.componentInstance; + component.vehicleTechRecord = mockVehicleTechnicalRecord('trl') as TechRecordType<'trl'>; + component.vehicleTechRecord.techRecord_axles = [ + { + parkingBrakeMrk: true, + axleNumber: 1, + brakes_brakeActuator: 1, + brakes_leverLength: 1, + brakes_springBrakeParking: true, + weights_gbWeight: 1, + weights_designWeight: 2, + weights_ladenWeight: 3, + weights_kerbWeight: 4, + tyres_tyreCode: 1, + tyres_tyreSize: '2', + tyres_plyRating: '3', + tyres_fitmentCode: 'single', + tyres_dataTrAxles: 1, + tyres_speedCategorySymbol: 'a7', + }, + { + parkingBrakeMrk: true, + axleNumber: 2, + brakes_brakeActuator: 1, + brakes_leverLength: 1, + brakes_springBrakeParking: false, + weights_gbWeight: 1, + weights_designWeight: 2, + weights_ladenWeight: 3, + weights_kerbWeight: 4, + tyres_tyreCode: 1, + tyres_tyreSize: '2', + tyres_plyRating: '3', + tyres_fitmentCode: 'single', + tyres_dataTrAxles: 1, + tyres_speedCategorySymbol: 'a7', + }, + { + parkingBrakeMrk: false, + axleNumber: 3, + brakes_brakeActuator: 1, + brakes_leverLength: 1, + brakes_springBrakeParking: true, + weights_gbWeight: 1, + weights_designWeight: 2, + weights_ladenWeight: 3, + weights_kerbWeight: 4, + tyres_tyreCode: 1, + tyres_tyreSize: '2', + tyres_plyRating: '3', + tyres_fitmentCode: 'single', + tyres_dataTrAxles: 1, + tyres_speedCategorySymbol: 'a7', + }, + ]; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); - describe('The brake code value on this.form', () => { - it('should match the corresponding values on vehicleTechRecord', () => { - expect(component.vehicleTechRecord.techRecord_brakes_loadSensingValve).toStrictEqual(component.form.value.techRecord_brakes_loadSensingValve); - }); - }); - describe('The dataTrBrakeOne value on this.form', () => { - it('should match the corresponding values on vehicleTechRecord', () => { - expect(component.vehicleTechRecord.techRecord_brakes_antilockBrakingSystem).toStrictEqual( - component.form.value.techRecord_brakes_antilockBrakingSystem, - ); - }); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); + describe('The brake code value on this.form', () => { + it('should match the corresponding values on vehicleTechRecord', () => { + expect(component.vehicleTechRecord.techRecord_brakes_loadSensingValve).toStrictEqual( + component.form.value.techRecord_brakes_loadSensingValve + ); + }); + }); + describe('The dataTrBrakeOne value on this.form', () => { + it('should match the corresponding values on vehicleTechRecord', () => { + expect(component.vehicleTechRecord.techRecord_brakes_antilockBrakingSystem).toStrictEqual( + component.form.value.techRecord_brakes_antilockBrakingSystem + ); + }); + }); - describe('The axle value on this.form', () => { - it('should match the corresponding values on vehicleTechRecord', () => { - const axles = component.vehicleTechRecord.techRecord_axles as NonNullable; - expect(axles[0]).toEqual(expect.objectContaining(component.form.controls['techRecord_axles']?.value[0])); - }); - }); + describe('The axle value on this.form', () => { + it('should match the corresponding values on vehicleTechRecord', () => { + const axles = component.vehicleTechRecord.techRecord_axles as NonNullable; + expect(axles[0]).toEqual(expect.objectContaining(component.form.controls['techRecord_axles']?.value[0])); + }); + }); }); diff --git a/src/app/forms/custom-sections/trl-brakes/trl-brakes.component.ts b/src/app/forms/custom-sections/trl-brakes/trl-brakes.component.ts index 0470b17d7a..4e7bdb3615 100644 --- a/src/app/forms/custom-sections/trl-brakes/trl-brakes.component.ts +++ b/src/app/forms/custom-sections/trl-brakes/trl-brakes.component.ts @@ -1,6 +1,4 @@ -import { - Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, -} from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core'; import { FormArray, FormGroup } from '@angular/forms'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; import { MultiOptions } from '@forms/models/options.model'; @@ -10,77 +8,81 @@ import { TrlBrakesTemplate } from '@forms/templates/trl/trl-brakes.template'; import { Subject, debounceTime, takeUntil } from 'rxjs'; @Component({ - selector: 'app-trl-brakes[vehicleTechRecord]', - templateUrl: './trl-brakes.component.html', - styleUrls: ['./trl-brakes.component.scss'], + selector: 'app-trl-brakes[vehicleTechRecord]', + templateUrl: './trl-brakes.component.html', + styleUrls: ['./trl-brakes.component.scss'], }) export class TrlBrakesComponent implements OnInit, OnChanges, OnDestroy { - @Input() vehicleTechRecord!: TechRecordType<'trl'>; - @Input() isEditing = false; - @Output() formChange = new EventEmitter(); - - form!: CustomFormGroup; - - booleanOptions: MultiOptions = [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ]; - - private destroy$ = new Subject(); - - constructor(private dfs: DynamicFormService) {} - - ngOnInit(): void { - this.form = this.dfs.createForm(TrlBrakesTemplate, this.vehicleTechRecord) as CustomFormGroup; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - this.form.cleanValueChanges.pipe(debounceTime(400), takeUntil(this.destroy$)).subscribe((event: any) => { - if (event?.techRecord_axles) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - event.techRecord_axles = (event.techRecord_axles).filter((axle: any) => !!axle?.axleNumber); - } - - this.formChange.emit(event); - }); - } - - ngOnChanges(changes: SimpleChanges): void { - const { vehicleTechRecord } = changes; - - if (this.form && vehicleTechRecord?.currentValue && vehicleTechRecord.currentValue !== vehicleTechRecord.previousValue) { - this.form.patchValue(vehicleTechRecord.currentValue, { emitEvent: false }); - } - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } - - get types(): typeof FormNodeEditTypes { - return FormNodeEditTypes; - } - - get axles(): FormArray { - return this.form.get(['techRecord_axles']) as FormArray; - } - - getAxleForm(i: number): FormGroup { - return this.form.get(['techRecord_axles', i]) as FormGroup; - } - - getAxleBrakes(i: number): FormGroup { - return this.form.get(['techRecord_axles', i, 'brakes']) as FormGroup; - } - - stripName = (s: string): string => { - const splitString = s.split('_').pop() ?? ''; - return ( - splitString.charAt(0).toUpperCase() - + splitString - .slice(1) - .replace(/([A-Z])/g, ' $1') - .toLowerCase() - ); - }; + @Input() vehicleTechRecord!: TechRecordType<'trl'>; + @Input() isEditing = false; + @Output() formChange = new EventEmitter(); + + form!: CustomFormGroup; + + booleanOptions: MultiOptions = [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ]; + + private destroy$ = new Subject(); + + constructor(private dfs: DynamicFormService) {} + + ngOnInit(): void { + this.form = this.dfs.createForm(TrlBrakesTemplate, this.vehicleTechRecord) as CustomFormGroup; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + this.form.cleanValueChanges.pipe(debounceTime(400), takeUntil(this.destroy$)).subscribe((event: any) => { + if (event?.techRecord_axles) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + event.techRecord_axles = event.techRecord_axles.filter((axle: any) => !!axle?.axleNumber); + } + + this.formChange.emit(event); + }); + } + + ngOnChanges(changes: SimpleChanges): void { + const { vehicleTechRecord } = changes; + + if ( + this.form && + vehicleTechRecord?.currentValue && + vehicleTechRecord.currentValue !== vehicleTechRecord.previousValue + ) { + this.form.patchValue(vehicleTechRecord.currentValue, { emitEvent: false }); + } + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + get types(): typeof FormNodeEditTypes { + return FormNodeEditTypes; + } + + get axles(): FormArray { + return this.form.get(['techRecord_axles']) as FormArray; + } + + getAxleForm(i: number): FormGroup { + return this.form.get(['techRecord_axles', i]) as FormGroup; + } + + getAxleBrakes(i: number): FormGroup { + return this.form.get(['techRecord_axles', i, 'brakes']) as FormGroup; + } + + stripName = (s: string): string => { + const splitString = s.split('_').pop() ?? ''; + return ( + splitString.charAt(0).toUpperCase() + + splitString + .slice(1) + .replace(/([A-Z])/g, ' $1') + .toLowerCase() + ); + }; } diff --git a/src/app/forms/custom-sections/tyres/tyres.component.spec.ts b/src/app/forms/custom-sections/tyres/tyres.component.spec.ts index 3af9a7b5a2..de9c189164 100644 --- a/src/app/forms/custom-sections/tyres/tyres.component.spec.ts +++ b/src/app/forms/custom-sections/tyres/tyres.component.spec.ts @@ -14,256 +14,292 @@ import { of, throwError } from 'rxjs'; import { TyresComponent } from './tyres.component'; const mockReferenceDataService = { - fetchReferenceDataByKey: jest.fn(), - loadReferenceData: jest.fn(), - getAll$: jest.fn().mockReturnValue(of([])), + fetchReferenceDataByKey: jest.fn(), + loadReferenceData: jest.fn(), + getAll$: jest.fn().mockReturnValue(of([])), }; const mockTechRecordService = { - getAxleFittingWeightValueFromLoadIndex: jest.fn(), + getAxleFittingWeightValueFromLoadIndex: jest.fn(), }; describe('TyresComponent', () => { - let component: TyresComponent; - let fixture: ComponentFixture; - let spy: jest.SpyInstance; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [RouterTestingModule, HttpClientTestingModule, DynamicFormsModule, StoreModule.forRoot({})], - declarations: [TyresComponent], - providers: [ - provideMockStore({ initialState: initialAppState }), - { provide: ReferenceDataService, useValue: mockReferenceDataService }, - { provide: TechnicalRecordService, useValue: mockTechRecordService }, - ], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(TyresComponent); - component = fixture.componentInstance; - component.vehicleTechRecord = mockVehicleTechnicalRecord('psv'); - component.vehicleTechRecord.techRecord_axles = [ - { - axleNumber: 1, - tyres_tyreSize: '295/80-22.5', - tyres_speedCategorySymbol: 'p', - tyres_fitmentCode: 'double', - tyres_dataTrAxles: 0, - tyres_plyRating: 'A', - tyres_tyreCode: 456, - parkingBrakeMrk: false, - - weights_kerbWeight: 1, - weights_ladenWeight: 2, - weights_gbWeight: 3, - // TODO: V3 2 eecweights in type package, which is this? - // weights_eecWeight: 4, - weights_designWeight: 5, - }, - { - axleNumber: 2, - parkingBrakeMrk: true, - - tyres_tyreSize: '295/80-22.5', - tyres_speedCategorySymbol: 'p', - tyres_fitmentCode: 'double', - tyres_dataTrAxles: 0, - tyres_plyRating: 'A', - tyres_tyreCode: 456, - - weights_kerbWeight: 1, - weights_ladenWeight: 2, - weights_gbWeight: 3, - // weights_eecWeight: 4, - weights_designWeight: 5, - }, - { - axleNumber: 3, - parkingBrakeMrk: true, - - tyres_tyreSize: '295/80-22.5', - tyres_speedCategorySymbol: 'p', - tyres_fitmentCode: 'double', - tyres_dataTrAxles: 0, - tyres_plyRating: 'A', - tyres_tyreCode: 456, - - weights_kerbWeight: 1, - weights_ladenWeight: 2, - weights_gbWeight: 3, - // weights_eecWeight: 4, - weights_designWeight: 5, - }, - ]; - - fixture.detectChanges(); - spy = jest.spyOn(component, 'addTyreToTechRecord'); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('checkAxleWeights', () => { - const currentAxle = [{ - weights_gbWeight: 1650, axleNumber: 1, tyres_dataTrAxles: 100, tyres_fitmentCode: 'single', tyres_tyreCode: '123', - }]; - const previousAxle = [{ - weights_gbWeight: 1649, axleNumber: 1, tyres_dataTrAxles: 100, tyres_fitmentCode: 'single', tyres_tyreCode: '123', - }]; - let simpleChanges: SimpleChanges; - beforeEach(() => { - simpleChanges = { - vehicleTechRecord: { currentValue: { techRecord_axles: currentAxle }, previousValue: { techRecord_axles: previousAxle }, firstChange: false }, - } as unknown as SimpleChanges; - component.isEditing = true; - }); - it('should return if isEditing is false', () => { - component.isEditing = false; - component.checkAxleWeights(simpleChanges); - expect(mockTechRecordService.getAxleFittingWeightValueFromLoadIndex).not.toHaveBeenCalled(); - }); - it('should call getAxleFittingWeightValueFromLoadIndex', () => { - component.checkAxleWeights(simpleChanges); - expect(mockTechRecordService.getAxleFittingWeightValueFromLoadIndex).toHaveBeenCalled(); - }); - it('should add an invalid axle to the invalidAxles array', () => { - mockTechRecordService.getAxleFittingWeightValueFromLoadIndex.mockReturnValue(1649); - component.checkAxleWeights(simpleChanges); - expect(component.invalidAxles).toContain(currentAxle[0].axleNumber); - }); - it('should not add a valid axle to the invalidAxles array', () => { - mockTechRecordService.getAxleFittingWeightValueFromLoadIndex.mockReturnValue(1651); - component.checkAxleWeights(simpleChanges); - expect(component.invalidAxles).not.toContain(currentAxle[0].axleNumber); - }); - }); - // TODO V3 PSV - describe('checkFitmentCodeHasChanged', () => { - it('should return false when there has been no change', () => { - const currentAxle = [{ tyres_fitmentCode: 'single', tyres_tyreCode: '123' }]; - const previousAxle = [{ tyres_fitmentCode: 'single', tyres_tyreCode: '123' }]; - - const simpleChanges = { - vehicleTechRecord: { currentValue: { techRecord_axles: currentAxle }, previousValue: { techRecord_axles: previousAxle }, firstChange: false }, - }; - - expect(component.checkFitmentCodeHasChanged(simpleChanges as unknown as SimpleChanges)).toBe(false); - }); - - it('should return true when there has been a change', () => { - jest.spyOn(component, 'getTyresRefData').mockImplementation(() => null); - const currentAxle = [{ tyres_fitmentCode: 'single', tyres_tyreCode: '123' }]; - const previousAxle = [{ tyres_fitmentCode: 'double', tyres_tyreCode: '123' }]; - - const simpleChanges = { - vehicleTechRecord: { currentValue: { techRecord_axles: currentAxle }, previousValue: { techRecord_axles: previousAxle }, firstChange: false }, - }; - - expect(component.checkFitmentCodeHasChanged(simpleChanges as unknown as SimpleChanges)).toBe(true); - }); - - it('should return false when there has been no change with multiple objects', () => { - const currentAxle = [ - { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, - { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, - ]; - const previousAxle = [ - { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, - { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, - ]; - - const simpleChanges = { - vehicleTechRecord: { currentValue: { techRecord_axles: currentAxle }, previousValue: { techRecord_axles: previousAxle }, firstChange: false }, - }; - - expect(component.checkFitmentCodeHasChanged(simpleChanges as unknown as SimpleChanges)).toBe(false); - }); - - it('should return true when there has been a change with multiple objects', () => { - jest.spyOn(component, 'getTyresRefData').mockImplementation(() => null); - const currentAxle = [ - { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, - { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, - ]; - const previousAxle = [ - { tyres_fitmentCode: 'double', tyres_tyreCode: '123' }, - { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, - ]; - - const simpleChanges = { - vehicleTechRecord: { currentValue: { techRecord_axles: currentAxle }, previousValue: { techRecord_axles: previousAxle }, firstChange: false }, - }; - - expect(component.checkFitmentCodeHasChanged(simpleChanges as unknown as SimpleChanges)).toBe(true); - }); - - it('should return false when this is a first change', () => { - const currentAxle = [ - { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, - { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, - ]; - const previousAxle = [ - { tyres_fitmentCode: 'double', tyres_tyreCode: '123' }, - { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, - ]; - - const simpleChanges = { - vehicleTechRecord: { currentValue: { techRecord_axles: currentAxle }, previousValue: { techRecord_axles: previousAxle }, firstChange: true }, - }; - - expect(component.checkFitmentCodeHasChanged(simpleChanges as unknown as SimpleChanges)).toBe(false); - }); - }); - - describe('getTyresRefData', () => { - it('should call add tyre to tech record with correct values', () => { - mockReferenceDataService.fetchReferenceDataByKey.mockImplementationOnce(() => { - return of({ - code: '101', - loadIndexSingleLoad: '123', - tyreSize: '123L:123', - dateTimeStamp: 'date', - userId: 'user', - loadIndexTwinLoad: '126', - plyRating: '12', - }); - }); - component.getTyresRefData(1); - - expect(spy).toHaveBeenCalledTimes(1); - }); - - it('should call add tyre to tech record with correct values when failure', () => { - mockReferenceDataService.fetchReferenceDataByKey.mockReturnValue(throwError(() => 'error')); - - component.getTyresRefData(1); - - expect(component.isError).toBe(true); - expect(component.errorMessage).toBe('Cannot find data of this tyre on axle 1'); - expect(spy).toHaveBeenCalledTimes(1); - }); - }); - - describe('addTyreToTechRecord', () => { - it('should update the tech record with the new tyre', () => { - const tyre = { - tyreSize: '123', - dataTrAxles: 123, - plyRating: '12', - tyreCode: 101, - }; - - component.addTyreToTechRecord(tyre, 1); - - const axles = component.vehicleTechRecord.techRecord_axles as Axles; - - expect(axles[0]?.tyres_tyreSize).toBe(tyre.tyreSize); - expect(axles[0]?.tyres_dataTrAxles).toBe(tyre.dataTrAxles); - expect(axles[0]?.tyres_plyRating).toBe(tyre.plyRating); - expect(axles[0]?.tyres_tyreCode).toBe(tyre.tyreCode); - }); - }); + let component: TyresComponent; + let fixture: ComponentFixture; + let spy: jest.SpyInstance; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [RouterTestingModule, HttpClientTestingModule, DynamicFormsModule, StoreModule.forRoot({})], + declarations: [TyresComponent], + providers: [ + provideMockStore({ initialState: initialAppState }), + { provide: ReferenceDataService, useValue: mockReferenceDataService }, + { provide: TechnicalRecordService, useValue: mockTechRecordService }, + ], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(TyresComponent); + component = fixture.componentInstance; + component.vehicleTechRecord = mockVehicleTechnicalRecord('psv'); + component.vehicleTechRecord.techRecord_axles = [ + { + axleNumber: 1, + tyres_tyreSize: '295/80-22.5', + tyres_speedCategorySymbol: 'p', + tyres_fitmentCode: 'double', + tyres_dataTrAxles: 0, + tyres_plyRating: 'A', + tyres_tyreCode: 456, + parkingBrakeMrk: false, + + weights_kerbWeight: 1, + weights_ladenWeight: 2, + weights_gbWeight: 3, + // TODO: V3 2 eecweights in type package, which is this? + // weights_eecWeight: 4, + weights_designWeight: 5, + }, + { + axleNumber: 2, + parkingBrakeMrk: true, + + tyres_tyreSize: '295/80-22.5', + tyres_speedCategorySymbol: 'p', + tyres_fitmentCode: 'double', + tyres_dataTrAxles: 0, + tyres_plyRating: 'A', + tyres_tyreCode: 456, + + weights_kerbWeight: 1, + weights_ladenWeight: 2, + weights_gbWeight: 3, + // weights_eecWeight: 4, + weights_designWeight: 5, + }, + { + axleNumber: 3, + parkingBrakeMrk: true, + + tyres_tyreSize: '295/80-22.5', + tyres_speedCategorySymbol: 'p', + tyres_fitmentCode: 'double', + tyres_dataTrAxles: 0, + tyres_plyRating: 'A', + tyres_tyreCode: 456, + + weights_kerbWeight: 1, + weights_ladenWeight: 2, + weights_gbWeight: 3, + // weights_eecWeight: 4, + weights_designWeight: 5, + }, + ]; + + fixture.detectChanges(); + spy = jest.spyOn(component, 'addTyreToTechRecord'); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('checkAxleWeights', () => { + const currentAxle = [ + { + weights_gbWeight: 1650, + axleNumber: 1, + tyres_dataTrAxles: 100, + tyres_fitmentCode: 'single', + tyres_tyreCode: '123', + }, + ]; + const previousAxle = [ + { + weights_gbWeight: 1649, + axleNumber: 1, + tyres_dataTrAxles: 100, + tyres_fitmentCode: 'single', + tyres_tyreCode: '123', + }, + ]; + let simpleChanges: SimpleChanges; + beforeEach(() => { + simpleChanges = { + vehicleTechRecord: { + currentValue: { techRecord_axles: currentAxle }, + previousValue: { techRecord_axles: previousAxle }, + firstChange: false, + }, + } as unknown as SimpleChanges; + component.isEditing = true; + }); + it('should return if isEditing is false', () => { + component.isEditing = false; + component.checkAxleWeights(simpleChanges); + expect(mockTechRecordService.getAxleFittingWeightValueFromLoadIndex).not.toHaveBeenCalled(); + }); + it('should call getAxleFittingWeightValueFromLoadIndex', () => { + component.checkAxleWeights(simpleChanges); + expect(mockTechRecordService.getAxleFittingWeightValueFromLoadIndex).toHaveBeenCalled(); + }); + it('should add an invalid axle to the invalidAxles array', () => { + mockTechRecordService.getAxleFittingWeightValueFromLoadIndex.mockReturnValue(1649); + component.checkAxleWeights(simpleChanges); + expect(component.invalidAxles).toContain(currentAxle[0].axleNumber); + }); + it('should not add a valid axle to the invalidAxles array', () => { + mockTechRecordService.getAxleFittingWeightValueFromLoadIndex.mockReturnValue(1651); + component.checkAxleWeights(simpleChanges); + expect(component.invalidAxles).not.toContain(currentAxle[0].axleNumber); + }); + }); + // TODO V3 PSV + describe('checkFitmentCodeHasChanged', () => { + it('should return false when there has been no change', () => { + const currentAxle = [{ tyres_fitmentCode: 'single', tyres_tyreCode: '123' }]; + const previousAxle = [{ tyres_fitmentCode: 'single', tyres_tyreCode: '123' }]; + + const simpleChanges = { + vehicleTechRecord: { + currentValue: { techRecord_axles: currentAxle }, + previousValue: { techRecord_axles: previousAxle }, + firstChange: false, + }, + }; + + expect(component.checkFitmentCodeHasChanged(simpleChanges as unknown as SimpleChanges)).toBe(false); + }); + + it('should return true when there has been a change', () => { + jest.spyOn(component, 'getTyresRefData').mockImplementation(() => null); + const currentAxle = [{ tyres_fitmentCode: 'single', tyres_tyreCode: '123' }]; + const previousAxle = [{ tyres_fitmentCode: 'double', tyres_tyreCode: '123' }]; + + const simpleChanges = { + vehicleTechRecord: { + currentValue: { techRecord_axles: currentAxle }, + previousValue: { techRecord_axles: previousAxle }, + firstChange: false, + }, + }; + + expect(component.checkFitmentCodeHasChanged(simpleChanges as unknown as SimpleChanges)).toBe(true); + }); + + it('should return false when there has been no change with multiple objects', () => { + const currentAxle = [ + { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, + { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, + ]; + const previousAxle = [ + { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, + { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, + ]; + + const simpleChanges = { + vehicleTechRecord: { + currentValue: { techRecord_axles: currentAxle }, + previousValue: { techRecord_axles: previousAxle }, + firstChange: false, + }, + }; + + expect(component.checkFitmentCodeHasChanged(simpleChanges as unknown as SimpleChanges)).toBe(false); + }); + + it('should return true when there has been a change with multiple objects', () => { + jest.spyOn(component, 'getTyresRefData').mockImplementation(() => null); + const currentAxle = [ + { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, + { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, + ]; + const previousAxle = [ + { tyres_fitmentCode: 'double', tyres_tyreCode: '123' }, + { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, + ]; + + const simpleChanges = { + vehicleTechRecord: { + currentValue: { techRecord_axles: currentAxle }, + previousValue: { techRecord_axles: previousAxle }, + firstChange: false, + }, + }; + + expect(component.checkFitmentCodeHasChanged(simpleChanges as unknown as SimpleChanges)).toBe(true); + }); + + it('should return false when this is a first change', () => { + const currentAxle = [ + { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, + { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, + ]; + const previousAxle = [ + { tyres_fitmentCode: 'double', tyres_tyreCode: '123' }, + { tyres_fitmentCode: 'single', tyres_tyreCode: '123' }, + ]; + + const simpleChanges = { + vehicleTechRecord: { + currentValue: { techRecord_axles: currentAxle }, + previousValue: { techRecord_axles: previousAxle }, + firstChange: true, + }, + }; + + expect(component.checkFitmentCodeHasChanged(simpleChanges as unknown as SimpleChanges)).toBe(false); + }); + }); + + describe('getTyresRefData', () => { + it('should call add tyre to tech record with correct values', () => { + mockReferenceDataService.fetchReferenceDataByKey.mockImplementationOnce(() => { + return of({ + code: '101', + loadIndexSingleLoad: '123', + tyreSize: '123L:123', + dateTimeStamp: 'date', + userId: 'user', + loadIndexTwinLoad: '126', + plyRating: '12', + }); + }); + component.getTyresRefData(1); + + expect(spy).toHaveBeenCalledTimes(1); + }); + + it('should call add tyre to tech record with correct values when failure', () => { + mockReferenceDataService.fetchReferenceDataByKey.mockReturnValue(throwError(() => 'error')); + + component.getTyresRefData(1); + + expect(component.isError).toBe(true); + expect(component.errorMessage).toBe('Cannot find data of this tyre on axle 1'); + expect(spy).toHaveBeenCalledTimes(1); + }); + }); + + describe('addTyreToTechRecord', () => { + it('should update the tech record with the new tyre', () => { + const tyre = { + tyreSize: '123', + dataTrAxles: 123, + plyRating: '12', + tyreCode: 101, + }; + + component.addTyreToTechRecord(tyre, 1); + + const axles = component.vehicleTechRecord.techRecord_axles as Axles; + + expect(axles[0]?.tyres_tyreSize).toBe(tyre.tyreSize); + expect(axles[0]?.tyres_dataTrAxles).toBe(tyre.dataTrAxles); + expect(axles[0]?.tyres_plyRating).toBe(tyre.plyRating); + expect(axles[0]?.tyres_tyreCode).toBe(tyre.tyreCode); + }); + }); }); diff --git a/src/app/forms/custom-sections/tyres/tyres.component.ts b/src/app/forms/custom-sections/tyres/tyres.component.ts index bef4ac5676..03c7108d13 100644 --- a/src/app/forms/custom-sections/tyres/tyres.component.ts +++ b/src/app/forms/custom-sections/tyres/tyres.component.ts @@ -1,7 +1,5 @@ import { ViewportScroller } from '@angular/common'; -import { - Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, -} from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { TyreUseCode as HgvTyreUseCode } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/tyreUseCodeHgv.enum.js'; import { TyreUseCode as TrlTyreUseCode } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/tyreUseCodeTrl.enum.js'; @@ -9,7 +7,11 @@ import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/ import { MultiOptions } from '@forms/models/options.model'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; import { - CustomFormArray, CustomFormGroup, FormNode, FormNodeEditTypes, FormNodeWidth, + CustomFormArray, + CustomFormGroup, + FormNode, + FormNodeEditTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; import { tyresTemplateHgv } from '@forms/templates/hgv/hgv-tyres.template'; import { PsvTyresTemplate } from '@forms/templates/psv/psv-tyres.template'; @@ -17,7 +19,13 @@ import { tyresTemplateTrl } from '@forms/templates/trl/trl-tyres.template'; import { getOptionsFromEnum, getOptionsFromEnumOneChar } from '@forms/utils/enum-map'; import { ReferenceDataResourceType, ReferenceDataTyre, ReferenceDataTyreLoadIndex } from '@models/reference-data.model'; import { - Axle, FitmentCode, ReasonForEditing, SpeedCategorySymbol, Tyre, Tyres, VehicleTypes, + Axle, + FitmentCode, + ReasonForEditing, + SpeedCategorySymbol, + Tyre, + Tyres, + VehicleTypes, } from '@models/vehicle-tech-record.model'; import { Store } from '@ngrx/store'; import { ReferenceDataService } from '@services/reference-data/reference-data.service'; @@ -26,280 +34,287 @@ import { selectAllReferenceDataByResourceType } from '@store/reference-data'; import { addAxle, removeAxle, updateScrollPosition } from '@store/technical-records'; import { TechnicalRecordServiceState } from '@store/technical-records/reducers/technical-record-service.reducer'; import { cloneDeep } from 'lodash'; -import { - Observable, - ReplaySubject, - filter, - takeUntil, -} from 'rxjs'; +import { Observable, ReplaySubject, filter, takeUntil } from 'rxjs'; @Component({ - selector: 'app-tyres', - templateUrl: './tyres.component.html', - styleUrls: ['./tyres.component.scss'], + selector: 'app-tyres', + templateUrl: './tyres.component.html', + styleUrls: ['./tyres.component.scss'], }) export class TyresComponent implements OnInit, OnDestroy, OnChanges { - @Input() vehicleTechRecord!: TechRecordType<'hgv' | 'psv' | 'trl'>; - @Input() isEditing = false; - - @Output() formChange = new EventEmitter(); - - private destroy$ = new ReplaySubject(1); - - public isError = false; - public errorMessage?: string; - public form!: CustomFormGroup; - private editingReason?: ReasonForEditing; - private loadIndexValues: ReferenceDataTyreLoadIndex[] | null = []; - - tyresReferenceData: ReferenceDataTyre[] = []; - invalidAxles: Array = []; - - constructor( - private dynamicFormsService: DynamicFormService, - private route: ActivatedRoute, - private router: Router, - private store: Store, - private viewportScroller: ViewportScroller, - private referenceDataService: ReferenceDataService, - private technicalRecordService: TechnicalRecordService, - ) { - this.editingReason = this.route.snapshot.data['reason']; - } - - ngOnInit(): void { - this.form = this.dynamicFormsService.createForm(this.template as FormNode, this.vehicleTechRecord) as CustomFormGroup; - this.form.cleanValueChanges.pipe(takeUntil(this.destroy$)).subscribe((event) => { - if (event && !Array.isArray(event) && event['axles']) { - event['axles'] = (event['axles'] as Axle[]).filter((axle) => !!axle?.axleNumber); - } - this.formChange.emit(event); - }); - - this.store.select(selectAllReferenceDataByResourceType(ReferenceDataResourceType.Tyres)) - .pipe(takeUntil(this.destroy$), filter(Boolean)).subscribe(((data) => { - this.tyresReferenceData = data as ReferenceDataTyre[]; - })); - - this.loadIndex$.pipe(takeUntil(this.destroy$)).subscribe((value): void => { - this.loadIndexValues = value; - }); - } - - ngOnChanges(simpleChanges: SimpleChanges): void { - const fitmentUpdated = this.checkFitmentCodeHasChanged(simpleChanges); - this.checkAxleWeights(simpleChanges); - if (!fitmentUpdated) { - this.form?.patchValue(this.vehicleTechRecord, { emitEvent: false }); - } - } - - ngOnDestroy(): void { - this.destroy$.next(true); - this.destroy$.unsubscribe(); - } - - get template(): FormNode | undefined { - switch (this.vehicleTechRecord.techRecord_vehicleType) { - case VehicleTypes.PSV: - return PsvTyresTemplate; - case VehicleTypes.HGV: - return tyresTemplateHgv; - case VehicleTypes.TRL: - return tyresTemplateTrl; - default: - return undefined; - } - } - - get isPsv(): boolean { - return this.vehicleTechRecord.techRecord_vehicleType === VehicleTypes.PSV; - } - - get isTrl(): boolean { - return this.vehicleTechRecord.techRecord_vehicleType === VehicleTypes.TRL; - } - - get types(): typeof FormNodeEditTypes { - return FormNodeEditTypes; - } - - get widths(): typeof FormNodeWidth { - return FormNodeWidth; - } - - get speedCategorySymbol(): MultiOptions { - return getOptionsFromEnum(SpeedCategorySymbol); - } - - get fitmentCode(): MultiOptions { - return getOptionsFromEnumOneChar(FitmentCode); - } - - get axles(): CustomFormArray { - return this.form.get(['techRecord_axles']) as CustomFormArray; - } - - get requiredPlates(): boolean { - return this.vehicleTechRecord.techRecord_vehicleType !== VehicleTypes.PSV && this.isEditing === true; - } - - getAxleTyres(i: number): CustomFormGroup { - return this.axles.get([i]) as CustomFormGroup; - } - - get loadIndex$(): Observable { - return this.referenceDataService.getAll$(ReferenceDataResourceType.TyreLoadIndex) as Observable; - } - - checkAxleWeights(simpleChanges: SimpleChanges) { - const { vehicleTechRecord } = simpleChanges; - this.invalidAxles = []; - if ( - !this.isEditing - || !vehicleTechRecord.currentValue.techRecord_axles - || (vehicleTechRecord.previousValue - && !vehicleTechRecord.previousValue.techRecord_axles - && (vehicleTechRecord.currentValue.techRecord_axles === vehicleTechRecord.previousValue.techRecord_axles))) { - return; - } - vehicleTechRecord.currentValue.techRecord_axles.forEach((axle: Axle) => { - if (axle.tyres_dataTrAxles && axle.weights_gbWeight && axle.axleNumber) { - const weightValue = this.technicalRecordService.getAxleFittingWeightValueFromLoadIndex( - axle.tyres_dataTrAxles.toString(), - axle.tyres_fitmentCode, - this.loadIndexValues, - ); - if (weightValue && axle.weights_gbWeight > weightValue) { - this.invalidAxles.push(axle.axleNumber); - } - } - }); - } - - checkFitmentCodeHasChanged(simpleChanges: SimpleChanges): boolean { - const { vehicleTechRecord } = simpleChanges; - if (vehicleTechRecord.firstChange !== undefined && vehicleTechRecord.firstChange === false) { - const currentAxles = vehicleTechRecord.currentValue.techRecord_axles; - const previousAxles = vehicleTechRecord.previousValue.techRecord_axles; - - if (!previousAxles) return false; - - // eslint-disable-next-line no-restricted-syntax - for (const [index, axle] of currentAxles.entries()) { - if ( - axle?.tyres_fitmentCode !== undefined - && previousAxles[`${index}`] - && previousAxles[`${index}`].tyres_fitmentCode !== undefined - && axle.tyres_fitmentCode !== previousAxles[`${index}`].tyres_fitmentCode - && axle.tyres_tyreCode === previousAxles[`${index}`].tyres_tyreCode - ) { - - this.getTyresRefData(axle.axleNumber); - return true; - } - } - } - - return false; - } - - handleNoAxleInfo(axleNumber: number) { - this.errorMessage = `Cannot find data of this tyre on axle ${axleNumber}`; - this.isError = true; - const newTyre = new Tyre({ - tyreCode: null, - tyreSize: null, - plyRating: null, - dataTrAxles: null, - }); - - this.addTyreToTechRecord(newTyre, axleNumber); - } - - getTyresRefData(axleNumber: number): void { - this.errorMessage = undefined; - - const { techRecord_axles: axles } = this.vehicleTechRecord; - if (axles == null) return; - - const axle = axles[axleNumber - 1]; - if (axle) { - const { tyres_tyreCode: code } = axle; - const tyreReferenceData = this.tyresReferenceData.find((tyre) => tyre.code === String(code)); - if (tyreReferenceData) { - const { tyres_fitmentCode: fit } = axle; - const indexLoad = fit === FitmentCode.SINGLE - ? parseInt(String(tyreReferenceData.loadIndexSingleLoad), 10) - : parseInt(String(tyreReferenceData.loadIndexTwinLoad), 10); - - const newTyre = new Tyre({ - tyreCode: code, - tyreSize: tyreReferenceData.tyreSize, - plyRating: tyreReferenceData.plyRating, - dataTrAxles: indexLoad, - }); - - this.addTyreToTechRecord(newTyre, axleNumber); - - return; - } - } - - this.handleNoAxleInfo(axleNumber); - } - - getTyreSearchPage(axleNumber: number) { - const route = this.editingReason ? `../${this.editingReason}/tyre-search/${axleNumber}` : `./tyre-search/${axleNumber}`; - - this.store.dispatch(updateScrollPosition({ position: this.viewportScroller.getScrollPosition() })); - - void this.router.navigate([route], { relativeTo: this.route, state: this.vehicleTechRecord }); - } - - addTyreToTechRecord(tyre: Tyres, axleNumber: number): void { - this.vehicleTechRecord = cloneDeep(this.vehicleTechRecord); - const axleIndex = this.vehicleTechRecord.techRecord_axles?.findIndex((ax) => ax.axleNumber === axleNumber); - - if (axleIndex === undefined || axleIndex === -1) { - return; - } - const axle = this.vehicleTechRecord.techRecord_axles?.[`${axleIndex}`]; - if (axle) { - axle.tyres_tyreCode = tyre.tyreCode; - axle.tyres_tyreSize = tyre.tyreSize; - axle.tyres_plyRating = tyre.plyRating; - axle.tyres_dataTrAxles = tyre.dataTrAxles; - this.form.patchValue(this.vehicleTechRecord); - } - } - - addAxle(): void { - if (!this.vehicleTechRecord.techRecord_axles || this.vehicleTechRecord.techRecord_axles.length < 10) { - this.isError = false; - this.store.dispatch(addAxle()); - } else { - this.isError = true; - this.errorMessage = `Cannot have more than ${10} axles`; - } - } - - removeAxle(index: number): void { - const minLength = this.isTrl ? 1 : 2; - const axles = this.vehicleTechRecord.techRecord_axles; - - if (axles && axles.length > minLength) { - this.isError = false; - this.store.dispatch(removeAxle({ index })); - } else { - this.isError = true; - this.errorMessage = `Cannot have less than ${minLength} axles`; - } - } - - protected readonly getOptionsFromEnum = getOptionsFromEnum; - - get tyreUseCode() { - return getOptionsFromEnum(this.vehicleTechRecord.techRecord_vehicleType === 'hgv' ? HgvTyreUseCode : TrlTyreUseCode); - } + @Input() vehicleTechRecord!: TechRecordType<'hgv' | 'psv' | 'trl'>; + @Input() isEditing = false; + + @Output() formChange = new EventEmitter(); + + private destroy$ = new ReplaySubject(1); + + public isError = false; + public errorMessage?: string; + public form!: CustomFormGroup; + private editingReason?: ReasonForEditing; + private loadIndexValues: ReferenceDataTyreLoadIndex[] | null = []; + + tyresReferenceData: ReferenceDataTyre[] = []; + invalidAxles: Array = []; + + constructor( + private dynamicFormsService: DynamicFormService, + private route: ActivatedRoute, + private router: Router, + private store: Store, + private viewportScroller: ViewportScroller, + private referenceDataService: ReferenceDataService, + private technicalRecordService: TechnicalRecordService + ) { + this.editingReason = this.route.snapshot.data['reason']; + } + + ngOnInit(): void { + this.form = this.dynamicFormsService.createForm( + this.template as FormNode, + this.vehicleTechRecord + ) as CustomFormGroup; + this.form.cleanValueChanges.pipe(takeUntil(this.destroy$)).subscribe((event) => { + if (event && !Array.isArray(event) && event['axles']) { + event['axles'] = (event['axles'] as Axle[]).filter((axle) => !!axle?.axleNumber); + } + this.formChange.emit(event); + }); + + this.store + .select(selectAllReferenceDataByResourceType(ReferenceDataResourceType.Tyres)) + .pipe(takeUntil(this.destroy$), filter(Boolean)) + .subscribe((data) => { + this.tyresReferenceData = data as ReferenceDataTyre[]; + }); + + this.loadIndex$.pipe(takeUntil(this.destroy$)).subscribe((value): void => { + this.loadIndexValues = value; + }); + } + + ngOnChanges(simpleChanges: SimpleChanges): void { + const fitmentUpdated = this.checkFitmentCodeHasChanged(simpleChanges); + this.checkAxleWeights(simpleChanges); + if (!fitmentUpdated) { + this.form?.patchValue(this.vehicleTechRecord, { emitEvent: false }); + } + } + + ngOnDestroy(): void { + this.destroy$.next(true); + this.destroy$.unsubscribe(); + } + + get template(): FormNode | undefined { + switch (this.vehicleTechRecord.techRecord_vehicleType) { + case VehicleTypes.PSV: + return PsvTyresTemplate; + case VehicleTypes.HGV: + return tyresTemplateHgv; + case VehicleTypes.TRL: + return tyresTemplateTrl; + default: + return undefined; + } + } + + get isPsv(): boolean { + return this.vehicleTechRecord.techRecord_vehicleType === VehicleTypes.PSV; + } + + get isTrl(): boolean { + return this.vehicleTechRecord.techRecord_vehicleType === VehicleTypes.TRL; + } + + get types(): typeof FormNodeEditTypes { + return FormNodeEditTypes; + } + + get widths(): typeof FormNodeWidth { + return FormNodeWidth; + } + + get speedCategorySymbol(): MultiOptions { + return getOptionsFromEnum(SpeedCategorySymbol); + } + + get fitmentCode(): MultiOptions { + return getOptionsFromEnumOneChar(FitmentCode); + } + + get axles(): CustomFormArray { + return this.form.get(['techRecord_axles']) as CustomFormArray; + } + + get requiredPlates(): boolean { + return this.vehicleTechRecord.techRecord_vehicleType !== VehicleTypes.PSV && this.isEditing === true; + } + + getAxleTyres(i: number): CustomFormGroup { + return this.axles.get([i]) as CustomFormGroup; + } + + get loadIndex$(): Observable { + return this.referenceDataService.getAll$(ReferenceDataResourceType.TyreLoadIndex) as Observable< + ReferenceDataTyreLoadIndex[] + >; + } + + checkAxleWeights(simpleChanges: SimpleChanges) { + const { vehicleTechRecord } = simpleChanges; + this.invalidAxles = []; + if ( + !this.isEditing || + !vehicleTechRecord.currentValue.techRecord_axles || + (vehicleTechRecord.previousValue && + !vehicleTechRecord.previousValue.techRecord_axles && + vehicleTechRecord.currentValue.techRecord_axles === vehicleTechRecord.previousValue.techRecord_axles) + ) { + return; + } + vehicleTechRecord.currentValue.techRecord_axles.forEach((axle: Axle) => { + if (axle.tyres_dataTrAxles && axle.weights_gbWeight && axle.axleNumber) { + const weightValue = this.technicalRecordService.getAxleFittingWeightValueFromLoadIndex( + axle.tyres_dataTrAxles.toString(), + axle.tyres_fitmentCode, + this.loadIndexValues + ); + if (weightValue && axle.weights_gbWeight > weightValue) { + this.invalidAxles.push(axle.axleNumber); + } + } + }); + } + + checkFitmentCodeHasChanged(simpleChanges: SimpleChanges): boolean { + const { vehicleTechRecord } = simpleChanges; + if (vehicleTechRecord.firstChange !== undefined && vehicleTechRecord.firstChange === false) { + const currentAxles = vehicleTechRecord.currentValue.techRecord_axles; + const previousAxles = vehicleTechRecord.previousValue.techRecord_axles; + + if (!previousAxles) return false; + + // eslint-disable-next-line no-restricted-syntax + for (const [index, axle] of currentAxles.entries()) { + if ( + axle?.tyres_fitmentCode !== undefined && + previousAxles[`${index}`] && + previousAxles[`${index}`].tyres_fitmentCode !== undefined && + axle.tyres_fitmentCode !== previousAxles[`${index}`].tyres_fitmentCode && + axle.tyres_tyreCode === previousAxles[`${index}`].tyres_tyreCode + ) { + this.getTyresRefData(axle.axleNumber); + return true; + } + } + } + + return false; + } + + handleNoAxleInfo(axleNumber: number) { + this.errorMessage = `Cannot find data of this tyre on axle ${axleNumber}`; + this.isError = true; + const newTyre = new Tyre({ + tyreCode: null, + tyreSize: null, + plyRating: null, + dataTrAxles: null, + }); + + this.addTyreToTechRecord(newTyre, axleNumber); + } + + getTyresRefData(axleNumber: number): void { + this.errorMessage = undefined; + + const { techRecord_axles: axles } = this.vehicleTechRecord; + if (axles == null) return; + + const axle = axles[axleNumber - 1]; + if (axle) { + const { tyres_tyreCode: code } = axle; + const tyreReferenceData = this.tyresReferenceData.find((tyre) => tyre.code === String(code)); + if (tyreReferenceData) { + const { tyres_fitmentCode: fit } = axle; + const indexLoad = + fit === FitmentCode.SINGLE + ? Number.parseInt(String(tyreReferenceData.loadIndexSingleLoad), 10) + : Number.parseInt(String(tyreReferenceData.loadIndexTwinLoad), 10); + + const newTyre = new Tyre({ + tyreCode: code, + tyreSize: tyreReferenceData.tyreSize, + plyRating: tyreReferenceData.plyRating, + dataTrAxles: indexLoad, + }); + + this.addTyreToTechRecord(newTyre, axleNumber); + + return; + } + } + + this.handleNoAxleInfo(axleNumber); + } + + getTyreSearchPage(axleNumber: number) { + const route = this.editingReason + ? `../${this.editingReason}/tyre-search/${axleNumber}` + : `./tyre-search/${axleNumber}`; + + this.store.dispatch(updateScrollPosition({ position: this.viewportScroller.getScrollPosition() })); + + void this.router.navigate([route], { relativeTo: this.route, state: this.vehicleTechRecord }); + } + + addTyreToTechRecord(tyre: Tyres, axleNumber: number): void { + this.vehicleTechRecord = cloneDeep(this.vehicleTechRecord); + const axleIndex = this.vehicleTechRecord.techRecord_axles?.findIndex((ax) => ax.axleNumber === axleNumber); + + if (axleIndex === undefined || axleIndex === -1) { + return; + } + const axle = this.vehicleTechRecord.techRecord_axles?.[`${axleIndex}`]; + if (axle) { + axle.tyres_tyreCode = tyre.tyreCode; + axle.tyres_tyreSize = tyre.tyreSize; + axle.tyres_plyRating = tyre.plyRating; + axle.tyres_dataTrAxles = tyre.dataTrAxles; + this.form.patchValue(this.vehicleTechRecord); + } + } + + addAxle(): void { + if (!this.vehicleTechRecord.techRecord_axles || this.vehicleTechRecord.techRecord_axles.length < 10) { + this.isError = false; + this.store.dispatch(addAxle()); + } else { + this.isError = true; + this.errorMessage = `Cannot have more than ${10} axles`; + } + } + + removeAxle(index: number): void { + const minLength = this.isTrl ? 1 : 2; + const axles = this.vehicleTechRecord.techRecord_axles; + + if (axles && axles.length > minLength) { + this.isError = false; + this.store.dispatch(removeAxle({ index })); + } else { + this.isError = true; + this.errorMessage = `Cannot have less than ${minLength} axles`; + } + } + + protected readonly getOptionsFromEnum = getOptionsFromEnum; + + get tyreUseCode() { + return getOptionsFromEnum( + this.vehicleTechRecord.techRecord_vehicleType === 'hgv' ? HgvTyreUseCode : TrlTyreUseCode + ); + } } diff --git a/src/app/forms/custom-sections/weights/weights.component.spec.ts b/src/app/forms/custom-sections/weights/weights.component.spec.ts index 19a37cabb0..57061faf3d 100644 --- a/src/app/forms/custom-sections/weights/weights.component.spec.ts +++ b/src/app/forms/custom-sections/weights/weights.component.spec.ts @@ -11,146 +11,146 @@ import { NumberInputComponent } from '../../components/number-input/number-input import { WeightsComponent } from './weights.component'; describe('WeightsComponent', () => { - let component: WeightsComponent; - let fixture: ComponentFixture; - let store: MockStore; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [DynamicFormsModule, StoreModule.forRoot({}), HttpClientTestingModule, RouterTestingModule], - declarations: [NumberInputComponent, WeightsComponent], - providers: [provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(WeightsComponent); - store = TestBed.inject(MockStore); - component = fixture.componentInstance; - component.vehicleTechRecord = mockVehicleTechnicalRecord('trl') as TechRecordType<'trl'>; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('calculateGrossLadenWeight', () => { - it('should calculate the gross laden weight correctly for PSV vehicles made before 1988', () => { - component.vehicleTechRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>; - component.vehicleTechRecord.techRecord_seatsUpperDeck = 10; - component.vehicleTechRecord.techRecord_seatsLowerDeck = 10; - component.vehicleTechRecord.techRecord_manufactureYear = 1987; - component.vehicleTechRecord.techRecord_standingCapacity = 10; - component.vehicleTechRecord.techRecord_grossKerbWeight = 1000; - component.ngOnInit(); - - expect(component.calculateGrossLadenWeight()).toBe(2969); - }); - - it('should calculate the gross laden weight correctly for PSV vehicles made during/after 1988', () => { - component.vehicleTechRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>; - component.vehicleTechRecord.techRecord_seatsUpperDeck = 10; - component.vehicleTechRecord.techRecord_seatsLowerDeck = 10; - component.vehicleTechRecord.techRecord_manufactureYear = 1988; - component.vehicleTechRecord.techRecord_standingCapacity = 10; - component.vehicleTechRecord.techRecord_grossKerbWeight = 1000; - component.ngOnInit(); - - expect(component.calculateGrossLadenWeight()).toBe(3015); - }); - }); - - describe('getAxleForm', () => { - it('should return the axle form group for the axle at the specified index', () => { - component.addAxle(); - component.addAxle(); - - expect(component.getAxleForm(0)).toBeDefined(); - }); - }); - - describe('addAxle', () => { - it('should dispatch the addAxle action if the tech record has less than 10 axles associated with it', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.vehicleTechRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>; - component.vehicleTechRecord.techRecord_noOfAxles = 9; - component.vehicleTechRecord.techRecord_axles = new Array(9).fill({}); - component.ngOnInit(); - - component.addAxle(); - expect(dispatchSpy).toHaveBeenCalledWith({ - type: '[Technical Record Service] addAxle', - }); - }); - - it('should set isError to true, and errorMessage to a suitable string, if adding would result in more than 10 axles', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.vehicleTechRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>; - component.vehicleTechRecord.techRecord_noOfAxles = 10; - component.vehicleTechRecord.techRecord_axles = new Array(10).fill({}); - component.ngOnInit(); - - component.addAxle(); - expect(dispatchSpy).toHaveBeenCalledTimes(0); - expect(component.isError).toBe(true); - expect(component.errorMessage).toBe('Cannot have more than 10 axles'); - }); - }); - - describe('removeAxle', () => { - it('should dispatch the remove axle action if the vehicle is a TRL with more than 1 axle', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.vehicleTechRecord = mockVehicleTechnicalRecord('trl') as TechRecordType<'trl'>; - component.vehicleTechRecord.techRecord_noOfAxles = 2; - component.vehicleTechRecord.techRecord_axles = new Array(2).fill({}); - component.ngOnInit(); - - component.removeAxle(1); - expect(dispatchSpy).toHaveBeenCalledWith({ - index: 1, - type: '[Technical Record Service] removeAxle', - }); - }); - - it('should dispatch the remove axle action if the vehicle is not a TRL, but has more than 2 axles', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.vehicleTechRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>; - component.vehicleTechRecord.techRecord_noOfAxles = 3; - component.vehicleTechRecord.techRecord_axles = new Array(3).fill({}); - component.ngOnInit(); - - component.removeAxle(1); - expect(dispatchSpy).toHaveBeenCalledWith({ - index: 1, - type: '[Technical Record Service] removeAxle', - }); - }); - - it('should set isError to true and display an appropriate error message if the vehicle is a TRL and has 1 or fewer axles', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.vehicleTechRecord = mockVehicleTechnicalRecord('trl') as TechRecordType<'trl'>; - component.vehicleTechRecord.techRecord_noOfAxles = 1; - component.vehicleTechRecord.techRecord_axles = new Array(1).fill({}); - component.ngOnInit(); - - component.removeAxle(0); - expect(dispatchSpy).toHaveBeenCalledTimes(0); - expect(component.isError).toBe(true); - expect(component.errorMessage).toBe('Cannot have less than 1 axles'); - }); - - it('should set isError to true and display an appropriate error message if the vehicle is not a TRL and has 2 or fewer axles', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.vehicleTechRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>; - component.vehicleTechRecord.techRecord_noOfAxles = 2; - component.vehicleTechRecord.techRecord_axles = new Array(2).fill({}); - component.ngOnInit(); - - component.removeAxle(1); - expect(dispatchSpy).toHaveBeenCalledTimes(0); - expect(component.isError).toBe(true); - expect(component.errorMessage).toBe('Cannot have less than 2 axles'); - }); - }); + let component: WeightsComponent; + let fixture: ComponentFixture; + let store: MockStore; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [DynamicFormsModule, StoreModule.forRoot({}), HttpClientTestingModule, RouterTestingModule], + declarations: [NumberInputComponent, WeightsComponent], + providers: [provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(WeightsComponent); + store = TestBed.inject(MockStore); + component = fixture.componentInstance; + component.vehicleTechRecord = mockVehicleTechnicalRecord('trl') as TechRecordType<'trl'>; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('calculateGrossLadenWeight', () => { + it('should calculate the gross laden weight correctly for PSV vehicles made before 1988', () => { + component.vehicleTechRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>; + component.vehicleTechRecord.techRecord_seatsUpperDeck = 10; + component.vehicleTechRecord.techRecord_seatsLowerDeck = 10; + component.vehicleTechRecord.techRecord_manufactureYear = 1987; + component.vehicleTechRecord.techRecord_standingCapacity = 10; + component.vehicleTechRecord.techRecord_grossKerbWeight = 1000; + component.ngOnInit(); + + expect(component.calculateGrossLadenWeight()).toBe(2969); + }); + + it('should calculate the gross laden weight correctly for PSV vehicles made during/after 1988', () => { + component.vehicleTechRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>; + component.vehicleTechRecord.techRecord_seatsUpperDeck = 10; + component.vehicleTechRecord.techRecord_seatsLowerDeck = 10; + component.vehicleTechRecord.techRecord_manufactureYear = 1988; + component.vehicleTechRecord.techRecord_standingCapacity = 10; + component.vehicleTechRecord.techRecord_grossKerbWeight = 1000; + component.ngOnInit(); + + expect(component.calculateGrossLadenWeight()).toBe(3015); + }); + }); + + describe('getAxleForm', () => { + it('should return the axle form group for the axle at the specified index', () => { + component.addAxle(); + component.addAxle(); + + expect(component.getAxleForm(0)).toBeDefined(); + }); + }); + + describe('addAxle', () => { + it('should dispatch the addAxle action if the tech record has less than 10 axles associated with it', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.vehicleTechRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>; + component.vehicleTechRecord.techRecord_noOfAxles = 9; + component.vehicleTechRecord.techRecord_axles = new Array(9).fill({}); + component.ngOnInit(); + + component.addAxle(); + expect(dispatchSpy).toHaveBeenCalledWith({ + type: '[Technical Record Service] addAxle', + }); + }); + + it('should set isError to true, and errorMessage to a suitable string, if adding would result in more than 10 axles', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.vehicleTechRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>; + component.vehicleTechRecord.techRecord_noOfAxles = 10; + component.vehicleTechRecord.techRecord_axles = new Array(10).fill({}); + component.ngOnInit(); + + component.addAxle(); + expect(dispatchSpy).toHaveBeenCalledTimes(0); + expect(component.isError).toBe(true); + expect(component.errorMessage).toBe('Cannot have more than 10 axles'); + }); + }); + + describe('removeAxle', () => { + it('should dispatch the remove axle action if the vehicle is a TRL with more than 1 axle', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.vehicleTechRecord = mockVehicleTechnicalRecord('trl') as TechRecordType<'trl'>; + component.vehicleTechRecord.techRecord_noOfAxles = 2; + component.vehicleTechRecord.techRecord_axles = new Array(2).fill({}); + component.ngOnInit(); + + component.removeAxle(1); + expect(dispatchSpy).toHaveBeenCalledWith({ + index: 1, + type: '[Technical Record Service] removeAxle', + }); + }); + + it('should dispatch the remove axle action if the vehicle is not a TRL, but has more than 2 axles', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.vehicleTechRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>; + component.vehicleTechRecord.techRecord_noOfAxles = 3; + component.vehicleTechRecord.techRecord_axles = new Array(3).fill({}); + component.ngOnInit(); + + component.removeAxle(1); + expect(dispatchSpy).toHaveBeenCalledWith({ + index: 1, + type: '[Technical Record Service] removeAxle', + }); + }); + + it('should set isError to true and display an appropriate error message if the vehicle is a TRL and has 1 or fewer axles', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.vehicleTechRecord = mockVehicleTechnicalRecord('trl') as TechRecordType<'trl'>; + component.vehicleTechRecord.techRecord_noOfAxles = 1; + component.vehicleTechRecord.techRecord_axles = new Array(1).fill({}); + component.ngOnInit(); + + component.removeAxle(0); + expect(dispatchSpy).toHaveBeenCalledTimes(0); + expect(component.isError).toBe(true); + expect(component.errorMessage).toBe('Cannot have less than 1 axles'); + }); + + it('should set isError to true and display an appropriate error message if the vehicle is not a TRL and has 2 or fewer axles', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + component.vehicleTechRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>; + component.vehicleTechRecord.techRecord_noOfAxles = 2; + component.vehicleTechRecord.techRecord_axles = new Array(2).fill({}); + component.ngOnInit(); + + component.removeAxle(1); + expect(dispatchSpy).toHaveBeenCalledTimes(0); + expect(component.isError).toBe(true); + expect(component.errorMessage).toBe('Cannot have less than 2 axles'); + }); + }); }); diff --git a/src/app/forms/custom-sections/weights/weights.component.ts b/src/app/forms/custom-sections/weights/weights.component.ts index 06b54806c4..954b552da8 100644 --- a/src/app/forms/custom-sections/weights/weights.component.ts +++ b/src/app/forms/custom-sections/weights/weights.component.ts @@ -1,12 +1,8 @@ /* eslint-disable no-underscore-dangle */ -import { - Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, -} from '@angular/core'; +import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; -import { - CustomFormArray, CustomFormGroup, FormNode, FormNodeEditTypes, -} from '@forms/services/dynamic-form.types'; +import { CustomFormArray, CustomFormGroup, FormNode, FormNodeEditTypes } from '@forms/services/dynamic-form.types'; import { HgvWeight } from '@forms/templates/hgv/hgv-weight.template'; import { PsvWeightsTemplate } from '@forms/templates/psv/psv-weight.template'; import { TrlWeight } from '@forms/templates/trl/trl-weight.template'; @@ -17,190 +13,210 @@ import { TechnicalRecordServiceState } from '@store/technical-records/reducers/t import { Subscription } from 'rxjs'; @Component({ - selector: 'app-weights[vehicleTechRecord]', - templateUrl: './weights.component.html', - styleUrls: ['./weights.component.scss'], + selector: 'app-weights[vehicleTechRecord]', + templateUrl: './weights.component.html', + styleUrls: ['./weights.component.scss'], }) export class WeightsComponent implements OnInit, OnDestroy, OnChanges { - @Input() vehicleTechRecord!: TechRecordType<'psv'> | TechRecordType<'trl'> | TechRecordType<'hgv'>; - @Input() isEditing = false; - @Output() formChange = new EventEmitter(); - - public form!: CustomFormGroup; - private _formSubscription = new Subscription(); - public isError = false; - public errorMessage?: string; - - constructor(public dynamicFormsService: DynamicFormService, private store: Store) {} - - ngOnInit(): void { - this.initializeForm(); - this.subscribeToFieldsForGrossLadenWeightRecalculation(); - this.subscribeToFormChanges(); - } - - ngOnChanges(changes: SimpleChanges): void { - this.handleVehicleTechRecordChange(changes); - } - - ngOnDestroy(): void { - this._formSubscription.unsubscribe(); - } - - get template(): FormNode { - switch (this.vehicleTechRecord.techRecord_vehicleType) { - case VehicleTypes.PSV: - return PsvWeightsTemplate; - case VehicleTypes.HGV: - return HgvWeight; - case VehicleTypes.TRL: - return TrlWeight; - default: - throw Error('Incorrect vehicle type!'); - } - } - - get isPsv(): boolean { - return this.vehicleTechRecord.techRecord_vehicleType === VehicleTypes.PSV; - } - - get isHgv(): boolean { - return this.vehicleTechRecord.techRecord_vehicleType === VehicleTypes.HGV; - } - - get isTrl(): boolean { - return this.vehicleTechRecord.techRecord_vehicleType === VehicleTypes.TRL; - } - - get requiredPlates(): boolean { - return !this.isPsv && this.isEditing; - } - - get types(): typeof FormNodeEditTypes { - return FormNodeEditTypes; - } - - get axles(): CustomFormArray { - return this.form.get(['techRecord_axles']) as CustomFormArray; - } - - private initializeForm(): void { - this.form = this.dynamicFormsService.createForm(this.template, this.vehicleTechRecord) as CustomFormGroup; - } - - private subscribeToFieldsForGrossLadenWeightRecalculation(): void { - const fields = [ - 'techRecord_seatsUpperDeck', - 'techRecord_seatsLowerDeck', - 'techRecord_manufactureYear', - 'techRecord_grossKerbWeight', - 'techRecord_standingCapacity', - ]; - - fields.forEach((field) => { - this.form.get(field)?.valueChanges.subscribe(() => { - if (this.form.value.techRecord_manufactureYear) { - const newGrossLadenWeight = this.calculateGrossLadenWeight(); - this.form.patchValue({ techRecord_grossLadenWeight: newGrossLadenWeight }, { emitEvent: false }); - } - }); - }); - } - - private handleVehicleTechRecordChange(changes: SimpleChanges): void { - const { vehicleTechRecord } = changes; - if (this.form && vehicleTechRecord) { - const { currentValue, previousValue } = vehicleTechRecord; - - const fieldsChanged = [ - 'techRecord_seatsUpperDeck', - 'techRecord_seatsLowerDeck', - 'techRecord_manufactureYear', - 'techRecord_grossKerbWeight', - 'techRecord_standingCapacity', - ].some((field) => currentValue[`${field}`] !== previousValue[`${field}`]); - - if (fieldsChanged && currentValue.techRecord_manufactureYear && this.vehicleTechRecord.techRecord_vehicleType === 'psv') { - this.vehicleTechRecord.techRecord_grossLadenWeight = this.calculateGrossLadenWeight(); - } - - this.form.patchValue(this.vehicleTechRecord, { emitEvent: false }); - } - } - - private subscribeToFormChanges(): void { - this._formSubscription.add( - this.form.valueChanges.subscribe((event) => { - if (event?.techRecord_grossLadenWeight) { - (this.vehicleTechRecord as TechRecordType<'psv'>).techRecord_grossLadenWeight = event.techRecord_grossLadenWeight; - this.form.patchValue({ techRecord_grossLadenWeight: event.techRecord_grossLadenWeight }, { emitEvent: false }); - this.formChange.emit(event); - updateBrakeForces({ grossLadenWeight: event.techRecord_grossLadenWeight, grossKerbWeight: event.techRecord_grossKerbWeight }); - return; - } - this.handleFormChanges(event); - }), - ); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - private handleFormChanges(event: any): void { - if (this.isPsv && this.determineRecalculationNeeded(event) && this.form.value.techRecord_manufactureYear) { - event.techRecord_grossLadenWeight = this.calculateGrossLadenWeight(); - this.form.get('techRecord_grossLadenWeight')?.setValue(event.techRecord_grossLadenWeight, { emitEvent: false }); - } - - this.formChange.emit(event); - if (event?.techRecord_grossLadenWeight || event?.techRecord_grossKerbWeight) { - this.store.dispatch( - updateBrakeForces({ grossLadenWeight: event.techRecord_grossLadenWeight, grossKerbWeight: event.techRecord_grossKerbWeight }), - ); - } - } - - private determineRecalculationNeeded(event: Record): boolean { - return ['techRecord_seatsUpperDeck', 'techRecord_seatsLowerDeck', 'techRecord_manufactureYear', 'techRecord_grossKerbWeight'].some( - (field) => event[`${field}`] !== undefined, - ); - } - - calculateGrossLadenWeight(): number { - const psvRecord = this.vehicleTechRecord as TechRecordType<'psv'>; - const techRecord_seatsUpperDeck = psvRecord?.techRecord_seatsUpperDeck ?? 0; - const techRecord_seatsLowerDeck = psvRecord?.techRecord_seatsLowerDeck ?? 0; - const techRecord_manufactureYear = psvRecord?.techRecord_manufactureYear ?? 0; - const techRecord_grossKerbWeight = psvRecord?.techRecord_grossKerbWeight ?? 0; - const techRecord_standingCapacity = psvRecord?.techRecord_standingCapacity ?? 0; - const kgAllowedPerPerson = techRecord_manufactureYear >= 1988 ? 65 : 63.5; - - const totalPassengers = techRecord_seatsUpperDeck + techRecord_seatsLowerDeck + techRecord_standingCapacity + 1; // Add 1 for the driver - return Math.ceil(totalPassengers * kgAllowedPerPerson + techRecord_grossKerbWeight); - } - - getAxleForm(i: number): CustomFormGroup { - return this.axles.get([i]) as CustomFormGroup; - } - - addAxle(): void { - if (!this.vehicleTechRecord.techRecord_axles || this.vehicleTechRecord.techRecord_axles.length < 10) { - this.isError = false; - this.store.dispatch(addAxle()); - } else { - this.isError = true; - this.errorMessage = `Cannot have more than ${10} axles`; - } - } - - removeAxle(index: number): void { - const minLength = this.isTrl ? 1 : 2; - const axles = this.vehicleTechRecord.techRecord_axles; - - if (axles && axles.length > minLength) { - this.isError = false; - this.store.dispatch(removeAxle({ index })); - } else { - this.isError = true; - this.errorMessage = `Cannot have less than ${minLength} axles`; - } - } + @Input() vehicleTechRecord!: TechRecordType<'psv'> | TechRecordType<'trl'> | TechRecordType<'hgv'>; + @Input() isEditing = false; + @Output() formChange = new EventEmitter(); + + public form!: CustomFormGroup; + private _formSubscription = new Subscription(); + public isError = false; + public errorMessage?: string; + + constructor( + public dynamicFormsService: DynamicFormService, + private store: Store + ) {} + + ngOnInit(): void { + this.initializeForm(); + this.subscribeToFieldsForGrossLadenWeightRecalculation(); + this.subscribeToFormChanges(); + } + + ngOnChanges(changes: SimpleChanges): void { + this.handleVehicleTechRecordChange(changes); + } + + ngOnDestroy(): void { + this._formSubscription.unsubscribe(); + } + + get template(): FormNode { + switch (this.vehicleTechRecord.techRecord_vehicleType) { + case VehicleTypes.PSV: + return PsvWeightsTemplate; + case VehicleTypes.HGV: + return HgvWeight; + case VehicleTypes.TRL: + return TrlWeight; + default: + throw Error('Incorrect vehicle type!'); + } + } + + get isPsv(): boolean { + return this.vehicleTechRecord.techRecord_vehicleType === VehicleTypes.PSV; + } + + get isHgv(): boolean { + return this.vehicleTechRecord.techRecord_vehicleType === VehicleTypes.HGV; + } + + get isTrl(): boolean { + return this.vehicleTechRecord.techRecord_vehicleType === VehicleTypes.TRL; + } + + get requiredPlates(): boolean { + return !this.isPsv && this.isEditing; + } + + get types(): typeof FormNodeEditTypes { + return FormNodeEditTypes; + } + + get axles(): CustomFormArray { + return this.form.get(['techRecord_axles']) as CustomFormArray; + } + + private initializeForm(): void { + this.form = this.dynamicFormsService.createForm(this.template, this.vehicleTechRecord) as CustomFormGroup; + } + + private subscribeToFieldsForGrossLadenWeightRecalculation(): void { + const fields = [ + 'techRecord_seatsUpperDeck', + 'techRecord_seatsLowerDeck', + 'techRecord_manufactureYear', + 'techRecord_grossKerbWeight', + 'techRecord_standingCapacity', + ]; + + fields.forEach((field) => { + this.form.get(field)?.valueChanges.subscribe(() => { + if (this.form.value.techRecord_manufactureYear) { + const newGrossLadenWeight = this.calculateGrossLadenWeight(); + this.form.patchValue({ techRecord_grossLadenWeight: newGrossLadenWeight }, { emitEvent: false }); + } + }); + }); + } + + private handleVehicleTechRecordChange(changes: SimpleChanges): void { + const { vehicleTechRecord } = changes; + if (this.form && vehicleTechRecord) { + const { currentValue, previousValue } = vehicleTechRecord; + + const fieldsChanged = [ + 'techRecord_seatsUpperDeck', + 'techRecord_seatsLowerDeck', + 'techRecord_manufactureYear', + 'techRecord_grossKerbWeight', + 'techRecord_standingCapacity', + ].some((field) => currentValue[`${field}`] !== previousValue[`${field}`]); + + if ( + fieldsChanged && + currentValue.techRecord_manufactureYear && + this.vehicleTechRecord.techRecord_vehicleType === 'psv' + ) { + this.vehicleTechRecord.techRecord_grossLadenWeight = this.calculateGrossLadenWeight(); + } + + this.form.patchValue(this.vehicleTechRecord, { emitEvent: false }); + } + } + + private subscribeToFormChanges(): void { + this._formSubscription.add( + this.form.valueChanges.subscribe((event) => { + if (event?.techRecord_grossLadenWeight) { + (this.vehicleTechRecord as TechRecordType<'psv'>).techRecord_grossLadenWeight = + event.techRecord_grossLadenWeight; + this.form.patchValue( + { techRecord_grossLadenWeight: event.techRecord_grossLadenWeight }, + { emitEvent: false } + ); + this.formChange.emit(event); + updateBrakeForces({ + grossLadenWeight: event.techRecord_grossLadenWeight, + grossKerbWeight: event.techRecord_grossKerbWeight, + }); + return; + } + this.handleFormChanges(event); + }) + ); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private handleFormChanges(event: any): void { + if (this.isPsv && this.determineRecalculationNeeded(event) && this.form.value.techRecord_manufactureYear) { + event.techRecord_grossLadenWeight = this.calculateGrossLadenWeight(); + this.form.get('techRecord_grossLadenWeight')?.setValue(event.techRecord_grossLadenWeight, { emitEvent: false }); + } + + this.formChange.emit(event); + if (event?.techRecord_grossLadenWeight || event?.techRecord_grossKerbWeight) { + this.store.dispatch( + updateBrakeForces({ + grossLadenWeight: event.techRecord_grossLadenWeight, + grossKerbWeight: event.techRecord_grossKerbWeight, + }) + ); + } + } + + private determineRecalculationNeeded(event: Record): boolean { + return [ + 'techRecord_seatsUpperDeck', + 'techRecord_seatsLowerDeck', + 'techRecord_manufactureYear', + 'techRecord_grossKerbWeight', + ].some((field) => event[`${field}`] !== undefined); + } + + calculateGrossLadenWeight(): number { + const psvRecord = this.vehicleTechRecord as TechRecordType<'psv'>; + const techRecord_seatsUpperDeck = psvRecord?.techRecord_seatsUpperDeck ?? 0; + const techRecord_seatsLowerDeck = psvRecord?.techRecord_seatsLowerDeck ?? 0; + const techRecord_manufactureYear = psvRecord?.techRecord_manufactureYear ?? 0; + const techRecord_grossKerbWeight = psvRecord?.techRecord_grossKerbWeight ?? 0; + const techRecord_standingCapacity = psvRecord?.techRecord_standingCapacity ?? 0; + const kgAllowedPerPerson = techRecord_manufactureYear >= 1988 ? 65 : 63.5; + + const totalPassengers = techRecord_seatsUpperDeck + techRecord_seatsLowerDeck + techRecord_standingCapacity + 1; // Add 1 for the driver + return Math.ceil(totalPassengers * kgAllowedPerPerson + techRecord_grossKerbWeight); + } + + getAxleForm(i: number): CustomFormGroup { + return this.axles.get([i]) as CustomFormGroup; + } + + addAxle(): void { + if (!this.vehicleTechRecord.techRecord_axles || this.vehicleTechRecord.techRecord_axles.length < 10) { + this.isError = false; + this.store.dispatch(addAxle()); + } else { + this.isError = true; + this.errorMessage = `Cannot have more than ${10} axles`; + } + } + + removeAxle(index: number): void { + const minLength = this.isTrl ? 1 : 2; + const axles = this.vehicleTechRecord.techRecord_axles; + + if (axles && axles.length > minLength) { + this.isError = false; + this.store.dispatch(removeAxle({ index })); + } else { + this.isError = true; + this.errorMessage = `Cannot have less than ${minLength} axles`; + } + } } diff --git a/src/app/forms/directives/app-no-space.directive.spec.ts b/src/app/forms/directives/app-no-space.directive.spec.ts index 54a6bdc5ff..7061a3bde2 100644 --- a/src/app/forms/directives/app-no-space.directive.spec.ts +++ b/src/app/forms/directives/app-no-space.directive.spec.ts @@ -1,133 +1,131 @@ import { Component } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - FormControl, FormGroup, FormsModule, ReactiveFormsModule, -} from '@angular/forms'; +import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { NoSpaceDirective } from './app-no-space.directive'; @Component({ - template: `
+ template: `
`, }) class TestComponent { - form = new FormGroup({ - foo: new FormControl(), - }); + form = new FormGroup({ + foo: new FormControl(), + }); } describe('NoSpaceDirective', () => { - let fixture: ComponentFixture; - let input1: HTMLInputElement; - let input2: HTMLInputElement; - let component: TestComponent; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [FormsModule, ReactiveFormsModule], - declarations: [NoSpaceDirective, TestComponent], - }).compileComponents(); - - fixture = TestBed.createComponent(TestComponent); - fixture.detectChanges(); - - input1 = fixture.debugElement.query(By.css('#bar')).nativeElement; - input2 = fixture.debugElement.query(By.css('#baz')).nativeElement; - component = fixture.componentInstance; - }); - - it('should create an instance', () => { - expect(input1).toBeTruthy(); - expect(input2).toBeTruthy(); - }); - - it('should prevent default event behaviour if a prohibited key is pressed', () => { - const $event = new KeyboardEvent('keydown', { key: 'Space', cancelable: true }); - - expect(input1.dispatchEvent($event)).toBe(false); - expect($event.defaultPrevented).toBe(true); - - expect(input2.dispatchEvent($event)).toBe(false); - expect($event.defaultPrevented).toBe(true); - }); - - it('should not prevent default event behaviour if a prohibited key is pressed', () => { - const $event = new KeyboardEvent('keydown', { key: 'a', cancelable: true }); - - expect(input1.dispatchEvent($event)).toBe(true); - expect($event.defaultPrevented).toBe(false); - - expect(input2.dispatchEvent($event)).toBe(true); - expect($event.defaultPrevented).toBe(false); - }); - - describe('should remove all whitespaces on focusout', () => { - it('with form', () => { - input1.value = 'this has spaces '; - input1.dispatchEvent(new Event('focusout')); - - expect(input1.value).toBe('thishasspaces'); - expect(component.form.get('foo')?.value).toBe('thishasspaces'); - }); - - it('without form', () => { - input2.value = 'this has spaces '; - input2.dispatchEvent(new Event('focusout')); - - expect(input2.value).toBe('thishasspaces'); - }); - - describe('it should dispatch the appropriate number of input events', () => { - it('if the value has changed', () => { - const dispatchEventSpy = jest.spyOn(input1, 'dispatchEvent'); - input1.value = 'this has spaces '; - input1.dispatchEvent(new Event('focusout')); - - expect(dispatchEventSpy).toHaveBeenCalledTimes(2); - }); - - it('if the value has not changed', () => { - const dispatchEventSpy = jest.spyOn(input1, 'dispatchEvent'); - input1.value = 'thishasspaces'; - input1.dispatchEvent(new Event('focusout')); - - expect(dispatchEventSpy).toHaveBeenCalledTimes(1); - }); - }); - }); - - describe('should remove all whitespaces on input', () => { - it('with form', () => { - input1.value = 'this has spaces '; - input1.dispatchEvent(new Event('input')); - - expect(input1.value).toBe('thishasspaces'); - expect(component.form.get('foo')?.value).toBe('thishasspaces'); - }); - - it('without form', () => { - input2.value = 'this has spaces '; - input2.dispatchEvent(new Event('input')); - - expect(input2.value).toBe('thishasspaces'); - }); - - describe('it should dispatch the appropriate number of input events', () => { - it('if the value has changed', () => { - const dispatchEventSpy = jest.spyOn(input1, 'dispatchEvent'); - input1.value = 'this has spaces '; - input1.dispatchEvent(new Event('input')); - - expect(dispatchEventSpy).toHaveBeenCalledTimes(2); - }); - - it('if the value has not changed', () => { - const dispatchEventSpy = jest.spyOn(input1, 'dispatchEvent'); - input1.value = 'thishasspaces'; - input1.dispatchEvent(new Event('input')); - - expect(dispatchEventSpy).toHaveBeenCalledTimes(1); - }); - }); - }); + let fixture: ComponentFixture; + let input1: HTMLInputElement; + let input2: HTMLInputElement; + let component: TestComponent; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [FormsModule, ReactiveFormsModule], + declarations: [NoSpaceDirective, TestComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + + input1 = fixture.debugElement.query(By.css('#bar')).nativeElement; + input2 = fixture.debugElement.query(By.css('#baz')).nativeElement; + component = fixture.componentInstance; + }); + + it('should create an instance', () => { + expect(input1).toBeTruthy(); + expect(input2).toBeTruthy(); + }); + + it('should prevent default event behaviour if a prohibited key is pressed', () => { + const $event = new KeyboardEvent('keydown', { key: 'Space', cancelable: true }); + + expect(input1.dispatchEvent($event)).toBe(false); + expect($event.defaultPrevented).toBe(true); + + expect(input2.dispatchEvent($event)).toBe(false); + expect($event.defaultPrevented).toBe(true); + }); + + it('should not prevent default event behaviour if a prohibited key is pressed', () => { + const $event = new KeyboardEvent('keydown', { key: 'a', cancelable: true }); + + expect(input1.dispatchEvent($event)).toBe(true); + expect($event.defaultPrevented).toBe(false); + + expect(input2.dispatchEvent($event)).toBe(true); + expect($event.defaultPrevented).toBe(false); + }); + + describe('should remove all whitespaces on focusout', () => { + it('with form', () => { + input1.value = 'this has spaces '; + input1.dispatchEvent(new Event('focusout')); + + expect(input1.value).toBe('thishasspaces'); + expect(component.form.get('foo')?.value).toBe('thishasspaces'); + }); + + it('without form', () => { + input2.value = 'this has spaces '; + input2.dispatchEvent(new Event('focusout')); + + expect(input2.value).toBe('thishasspaces'); + }); + + describe('it should dispatch the appropriate number of input events', () => { + it('if the value has changed', () => { + const dispatchEventSpy = jest.spyOn(input1, 'dispatchEvent'); + input1.value = 'this has spaces '; + input1.dispatchEvent(new Event('focusout')); + + expect(dispatchEventSpy).toHaveBeenCalledTimes(2); + }); + + it('if the value has not changed', () => { + const dispatchEventSpy = jest.spyOn(input1, 'dispatchEvent'); + input1.value = 'thishasspaces'; + input1.dispatchEvent(new Event('focusout')); + + expect(dispatchEventSpy).toHaveBeenCalledTimes(1); + }); + }); + }); + + describe('should remove all whitespaces on input', () => { + it('with form', () => { + input1.value = 'this has spaces '; + input1.dispatchEvent(new Event('input')); + + expect(input1.value).toBe('thishasspaces'); + expect(component.form.get('foo')?.value).toBe('thishasspaces'); + }); + + it('without form', () => { + input2.value = 'this has spaces '; + input2.dispatchEvent(new Event('input')); + + expect(input2.value).toBe('thishasspaces'); + }); + + describe('it should dispatch the appropriate number of input events', () => { + it('if the value has changed', () => { + const dispatchEventSpy = jest.spyOn(input1, 'dispatchEvent'); + input1.value = 'this has spaces '; + input1.dispatchEvent(new Event('input')); + + expect(dispatchEventSpy).toHaveBeenCalledTimes(2); + }); + + it('if the value has not changed', () => { + const dispatchEventSpy = jest.spyOn(input1, 'dispatchEvent'); + input1.value = 'thishasspaces'; + input1.dispatchEvent(new Event('input')); + + expect(dispatchEventSpy).toHaveBeenCalledTimes(1); + }); + }); + }); }); diff --git a/src/app/forms/directives/app-no-space.directive.ts b/src/app/forms/directives/app-no-space.directive.ts index 632f119ceb..ee18b5ecdf 100644 --- a/src/app/forms/directives/app-no-space.directive.ts +++ b/src/app/forms/directives/app-no-space.directive.ts @@ -1,29 +1,29 @@ import { Directive, HostListener } from '@angular/core'; @Directive({ - selector: '[appNoSpace]', + selector: '[appNoSpace]', }) export class NoSpaceDirective { - @HostListener('keydown', ['$event']) - public onKeyDown(e: KeyboardEvent): void { - if (e.key === ' ' || e.key === 'Space') { - e.preventDefault(); - } - } + @HostListener('keydown', ['$event']) + public onKeyDown(e: KeyboardEvent): void { + if (e.key === ' ' || e.key === 'Space') { + e.preventDefault(); + } + } - @HostListener('focusout', ['$event.target']) - public onBlur(input: HTMLInputElement): void { - const oldValue = input.value; - input.value = input.value.replace(/\s/g, ''); + @HostListener('focusout', ['$event.target']) + public onBlur(input: HTMLInputElement): void { + const oldValue = input.value; + input.value = input.value.replace(/\s/g, ''); - if (input.value !== oldValue) input.dispatchEvent(new Event('input')); - } + if (input.value !== oldValue) input.dispatchEvent(new Event('input')); + } - @HostListener('input', ['$event.target']) - public onInput(input: HTMLInputElement): void { - const oldValue = input.value; - input.value = input.value.replace(/\s/g, ''); + @HostListener('input', ['$event.target']) + public onInput(input: HTMLInputElement): void { + const oldValue = input.value; + input.value = input.value.replace(/\s/g, ''); - if (input.value !== oldValue) input.dispatchEvent(new Event('input')); - } + if (input.value !== oldValue) input.dispatchEvent(new Event('input')); + } } diff --git a/src/app/forms/directives/app-number-only.directive.spec.ts b/src/app/forms/directives/app-number-only.directive.spec.ts index 8b18941f55..8fea9835c6 100644 --- a/src/app/forms/directives/app-number-only.directive.spec.ts +++ b/src/app/forms/directives/app-number-only.directive.spec.ts @@ -4,35 +4,35 @@ import { By } from '@angular/platform-browser'; import { NumberOnlyDirective } from './app-number-only.directive'; @Component({ - template: ' ', + template: ' ', }) class TestComponent {} describe('NumberOnlyDirective', () => { - let fixture: ComponentFixture; - let input: HTMLInputElement; + let fixture: ComponentFixture; + let input: HTMLInputElement; - beforeEach(() => { - fixture = TestBed.configureTestingModule({ - declarations: [NumberOnlyDirective, TestComponent], - }).createComponent(TestComponent); - fixture.detectChanges(); + beforeEach(() => { + fixture = TestBed.configureTestingModule({ + declarations: [NumberOnlyDirective, TestComponent], + }).createComponent(TestComponent); + fixture.detectChanges(); - input = fixture.debugElement.query(By.directive(NumberOnlyDirective)).nativeElement; - }); - it('should create an instance', () => { - expect(input).toBeTruthy(); - }); + input = fixture.debugElement.query(By.directive(NumberOnlyDirective)).nativeElement; + }); + it('should create an instance', () => { + expect(input).toBeTruthy(); + }); - it('should prevent default event behaviour if a prohibited key is pressed', () => { - const $event = new KeyboardEvent('keydown', { key: 'e', cancelable: true }); - expect(input.dispatchEvent($event)).toBe(false); - expect($event.defaultPrevented).toBe(true); - }); + it('should prevent default event behaviour if a prohibited key is pressed', () => { + const $event = new KeyboardEvent('keydown', { key: 'e', cancelable: true }); + expect(input.dispatchEvent($event)).toBe(false); + expect($event.defaultPrevented).toBe(true); + }); - it('should not prevent default event behaviour if a prohibited key is pressed', () => { - const $event = new KeyboardEvent('keydown', { key: '6', cancelable: true }); - expect(input.dispatchEvent($event)).toBe(true); - expect($event.defaultPrevented).toBe(false); - }); + it('should not prevent default event behaviour if a prohibited key is pressed', () => { + const $event = new KeyboardEvent('keydown', { key: '6', cancelable: true }); + expect(input.dispatchEvent($event)).toBe(true); + expect($event.defaultPrevented).toBe(false); + }); }); diff --git a/src/app/forms/directives/app-number-only.directive.ts b/src/app/forms/directives/app-number-only.directive.ts index 35d8b0421c..a41a5dd491 100644 --- a/src/app/forms/directives/app-number-only.directive.ts +++ b/src/app/forms/directives/app-number-only.directive.ts @@ -1,34 +1,47 @@ import { Directive, ElementRef, HostListener } from '@angular/core'; @Directive({ - selector: '[appNumberOnly]', + selector: '[appNumberOnly]', }) export class NumberOnlyDirective { - inputElement: HTMLInputElement; + inputElement: HTMLInputElement; - private navigationKeys = ['Backspace', 'Delete', 'Tab', 'Escape', 'Enter', 'Home', 'End', 'ArrowLeft', 'ArrowRight', 'Clear', 'Copy', 'Paste']; + private navigationKeys = [ + 'Backspace', + 'Delete', + 'Tab', + 'Escape', + 'Enter', + 'Home', + 'End', + 'ArrowLeft', + 'ArrowRight', + 'Clear', + 'Copy', + 'Paste', + ]; - constructor(private el: ElementRef) { - this.inputElement = el.nativeElement; - } + constructor(private el: ElementRef) { + this.inputElement = el.nativeElement; + } - @HostListener('keydown', ['$event']) - onKeyDown(e: KeyboardEvent) { - if ( - this.navigationKeys.indexOf(e.key) > -1 - || (e.key === 'a' && e.ctrlKey === true) - || (e.key === 'c' && e.ctrlKey === true) - || (e.key === 'v' && e.ctrlKey === true) - || (e.key === 'x' && e.ctrlKey === true) - || (e.key === 'a' && e.metaKey === true) - || (e.key === 'c' && e.metaKey === true) - || (e.key === 'v' && e.metaKey === true) - || (e.key === 'x' && e.metaKey === true) - ) { - return; - } - if (e.key === ' ' || Number.isNaN(Number(e.key))) { - e.preventDefault(); - } - } + @HostListener('keydown', ['$event']) + onKeyDown(e: KeyboardEvent) { + if ( + this.navigationKeys.indexOf(e.key) > -1 || + (e.key === 'a' && e.ctrlKey === true) || + (e.key === 'c' && e.ctrlKey === true) || + (e.key === 'v' && e.ctrlKey === true) || + (e.key === 'x' && e.ctrlKey === true) || + (e.key === 'a' && e.metaKey === true) || + (e.key === 'c' && e.metaKey === true) || + (e.key === 'v' && e.metaKey === true) || + (e.key === 'x' && e.metaKey === true) + ) { + return; + } + if (e.key === ' ' || Number.isNaN(Number(e.key))) { + e.preventDefault(); + } + } } diff --git a/src/app/forms/directives/app-to-uppercase.directive.spec.ts b/src/app/forms/directives/app-to-uppercase.directive.spec.ts index 4a9004c5db..71a7a05355 100644 --- a/src/app/forms/directives/app-to-uppercase.directive.spec.ts +++ b/src/app/forms/directives/app-to-uppercase.directive.spec.ts @@ -1,41 +1,39 @@ import { Component } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - FormControl, FormGroup, FormsModule, ReactiveFormsModule, -} from '@angular/forms'; +import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { ToUppercaseDirective } from './app-to-uppercase.directive'; @Component({ - template: '
', + template: '
', }) class TestComponent { - form = new FormGroup({ - foo: new FormControl(), - }); + form = new FormGroup({ + foo: new FormControl(), + }); } describe('ToUppercaseDirective', () => { - let fixture: ComponentFixture; - let input: HTMLInputElement; - let component: TestComponent; + let fixture: ComponentFixture; + let input: HTMLInputElement; + let component: TestComponent; - beforeEach(() => { - fixture = TestBed.configureTestingModule({ - imports: [FormsModule, ReactiveFormsModule], - declarations: [ToUppercaseDirective, TestComponent], - }).createComponent(TestComponent); - fixture.detectChanges(); + beforeEach(() => { + fixture = TestBed.configureTestingModule({ + imports: [FormsModule, ReactiveFormsModule], + declarations: [ToUppercaseDirective, TestComponent], + }).createComponent(TestComponent); + fixture.detectChanges(); - input = fixture.debugElement.query(By.directive(ToUppercaseDirective)).nativeElement; - component = fixture.componentInstance; - }); + input = fixture.debugElement.query(By.directive(ToUppercaseDirective)).nativeElement; + component = fixture.componentInstance; + }); - it('should make the text uppercase on input', () => { - input.value = 'lowercase'; - input.dispatchEvent(new Event('focusout')); + it('should make the text uppercase on input', () => { + input.value = 'lowercase'; + input.dispatchEvent(new Event('focusout')); - expect(input.value).toBe('LOWERCASE'); - expect(component.form.get('foo')?.value).toBe('LOWERCASE'); - }); + expect(input.value).toBe('LOWERCASE'); + expect(component.form.get('foo')?.value).toBe('LOWERCASE'); + }); }); diff --git a/src/app/forms/directives/app-to-uppercase.directive.ts b/src/app/forms/directives/app-to-uppercase.directive.ts index 1e438a86ee..73f16d2421 100644 --- a/src/app/forms/directives/app-to-uppercase.directive.ts +++ b/src/app/forms/directives/app-to-uppercase.directive.ts @@ -1,12 +1,12 @@ import { Directive, HostListener } from '@angular/core'; @Directive({ - selector: '[appToUppercase]', + selector: '[appToUppercase]', }) export class ToUppercaseDirective { - @HostListener('focusout', ['$event.target']) - public onBlur(input: HTMLInputElement): void { - input.value = input.value.toUpperCase(); - input.dispatchEvent(new Event('input')); - } + @HostListener('focusout', ['$event.target']) + public onBlur(input: HTMLInputElement): void { + input.value = input.value.toUpperCase(); + input.dispatchEvent(new Event('input')); + } } diff --git a/src/app/forms/directives/app-trim-whitespace.directive.spec.ts b/src/app/forms/directives/app-trim-whitespace.directive.spec.ts index d38b06beb1..62ccc51b40 100644 --- a/src/app/forms/directives/app-trim-whitespace.directive.spec.ts +++ b/src/app/forms/directives/app-trim-whitespace.directive.spec.ts @@ -1,108 +1,106 @@ import { Component } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - FormControl, FormGroup, FormsModule, ReactiveFormsModule, -} from '@angular/forms'; +import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { TrimWhitespaceDirective } from './app-trim-whitespace.directive'; @Component({ - template: `
+ template: `
`, }) class TestComponent { - form = new FormGroup({ - foo: new FormControl(), - }); + form = new FormGroup({ + foo: new FormControl(), + }); } describe('TrimWhitespaceDirective', () => { - let fixture: ComponentFixture; - let input1: HTMLInputElement; - let input2: HTMLInputElement; - let component: TestComponent; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [FormsModule, ReactiveFormsModule], - declarations: [TrimWhitespaceDirective, TestComponent], - }).compileComponents(); - - fixture = TestBed.createComponent(TestComponent); - fixture.detectChanges(); - - input1 = fixture.debugElement.query(By.css('#bar')).nativeElement; - input2 = fixture.debugElement.query(By.css('#baz')).nativeElement; - component = fixture.componentInstance; - }); - - describe('should trim whitespaces on focusout', () => { - it('with form', () => { - input1.value = 'this has spaces '; - input1.dispatchEvent(new Event('focusout')); - - expect(input1.value).toBe('this has spaces'); - expect(component.form.get('foo')?.value).toBe('this has spaces'); - }); - - it('without form', () => { - input2.value = 'this has spaces '; - input2.dispatchEvent(new Event('focusout')); - - expect(input2.value).toBe('this has spaces'); - }); - - describe('it should dispatch the appropriate number of events', () => { - it('if the value has changed', () => { - const dispatchEventSpy = jest.spyOn(input1, 'dispatchEvent'); - input1.value = 'this has spaces '; - input1.dispatchEvent(new Event('focusout')); - - expect(dispatchEventSpy).toHaveBeenCalledTimes(2); - }); - - it('if the value has not changed', () => { - const dispatchEventSpy = jest.spyOn(input1, 'dispatchEvent'); - input1.value = 'this has spaces'; - input1.dispatchEvent(new Event('focusout')); - - expect(dispatchEventSpy).toHaveBeenCalledTimes(1); - }); - }); - }); - - describe('should trim whitespaces on input', () => { - it('should trim the values and update the form', () => { - input1.value = 'this has spaces '; - input1.dispatchEvent(new Event('input')); - - expect(input1.value).toBe('this has spaces'); - expect(component.form.get('foo')?.value).toBe('this has spaces'); - }); - - it('without form', () => { - input2.value = 'this has spaces '; - input2.dispatchEvent(new Event('input')); - - expect(input2.value).toBe('this has spaces'); - }); - - describe('it should dispatch the appropriate number of input events', () => { - it('if the value has changed', () => { - const dispatchEventSpy = jest.spyOn(input1, 'dispatchEvent'); - input1.value = 'this has spaces '; - input1.dispatchEvent(new Event('input')); - - expect(dispatchEventSpy).toHaveBeenCalledTimes(2); - }); - - it('if the value has not changed', () => { - const dispatchEventSpy = jest.spyOn(input1, 'dispatchEvent'); - input1.value = 'this has spaces'; - input1.dispatchEvent(new Event('input')); - - expect(dispatchEventSpy).toHaveBeenCalledTimes(1); - }); - }); - }); + let fixture: ComponentFixture; + let input1: HTMLInputElement; + let input2: HTMLInputElement; + let component: TestComponent; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [FormsModule, ReactiveFormsModule], + declarations: [TrimWhitespaceDirective, TestComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + + input1 = fixture.debugElement.query(By.css('#bar')).nativeElement; + input2 = fixture.debugElement.query(By.css('#baz')).nativeElement; + component = fixture.componentInstance; + }); + + describe('should trim whitespaces on focusout', () => { + it('with form', () => { + input1.value = 'this has spaces '; + input1.dispatchEvent(new Event('focusout')); + + expect(input1.value).toBe('this has spaces'); + expect(component.form.get('foo')?.value).toBe('this has spaces'); + }); + + it('without form', () => { + input2.value = 'this has spaces '; + input2.dispatchEvent(new Event('focusout')); + + expect(input2.value).toBe('this has spaces'); + }); + + describe('it should dispatch the appropriate number of events', () => { + it('if the value has changed', () => { + const dispatchEventSpy = jest.spyOn(input1, 'dispatchEvent'); + input1.value = 'this has spaces '; + input1.dispatchEvent(new Event('focusout')); + + expect(dispatchEventSpy).toHaveBeenCalledTimes(2); + }); + + it('if the value has not changed', () => { + const dispatchEventSpy = jest.spyOn(input1, 'dispatchEvent'); + input1.value = 'this has spaces'; + input1.dispatchEvent(new Event('focusout')); + + expect(dispatchEventSpy).toHaveBeenCalledTimes(1); + }); + }); + }); + + describe('should trim whitespaces on input', () => { + it('should trim the values and update the form', () => { + input1.value = 'this has spaces '; + input1.dispatchEvent(new Event('input')); + + expect(input1.value).toBe('this has spaces'); + expect(component.form.get('foo')?.value).toBe('this has spaces'); + }); + + it('without form', () => { + input2.value = 'this has spaces '; + input2.dispatchEvent(new Event('input')); + + expect(input2.value).toBe('this has spaces'); + }); + + describe('it should dispatch the appropriate number of input events', () => { + it('if the value has changed', () => { + const dispatchEventSpy = jest.spyOn(input1, 'dispatchEvent'); + input1.value = 'this has spaces '; + input1.dispatchEvent(new Event('input')); + + expect(dispatchEventSpy).toHaveBeenCalledTimes(2); + }); + + it('if the value has not changed', () => { + const dispatchEventSpy = jest.spyOn(input1, 'dispatchEvent'); + input1.value = 'this has spaces'; + input1.dispatchEvent(new Event('input')); + + expect(dispatchEventSpy).toHaveBeenCalledTimes(1); + }); + }); + }); }); diff --git a/src/app/forms/directives/app-trim-whitespace.directive.ts b/src/app/forms/directives/app-trim-whitespace.directive.ts index 55e283fd32..6ee4c551e5 100644 --- a/src/app/forms/directives/app-trim-whitespace.directive.ts +++ b/src/app/forms/directives/app-trim-whitespace.directive.ts @@ -1,22 +1,22 @@ import { Directive, HostListener } from '@angular/core'; @Directive({ - selector: '[appTrimWhitespace]', + selector: '[appTrimWhitespace]', }) export class TrimWhitespaceDirective { - @HostListener('focusout', ['$event.target']) - public onBlur(input: HTMLInputElement): void { - const oldValue = input.value; - input.value = input.value.trim(); + @HostListener('focusout', ['$event.target']) + public onBlur(input: HTMLInputElement): void { + const oldValue = input.value; + input.value = input.value.trim(); - if (input.value !== oldValue) input.dispatchEvent(new Event('input')); - } + if (input.value !== oldValue) input.dispatchEvent(new Event('input')); + } - @HostListener('input', ['$event.target']) - public onInput(input: HTMLInputElement): void { - const oldValue = input.value; - input.value = input.value.trim(); + @HostListener('input', ['$event.target']) + public onInput(input: HTMLInputElement): void { + const oldValue = input.value; + input.value = input.value.trim(); - if (input.value !== oldValue) input.dispatchEvent(new Event('input')); - } + if (input.value !== oldValue) input.dispatchEvent(new Event('input')); + } } diff --git a/src/app/forms/directives/prefix.directive.spec.ts b/src/app/forms/directives/prefix.directive.spec.ts index dc78ae6999..0ba9243be7 100644 --- a/src/app/forms/directives/prefix.directive.spec.ts +++ b/src/app/forms/directives/prefix.directive.spec.ts @@ -3,27 +3,27 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { PrefixDirective } from './prefix.directive'; @Component({ - template: '', + template: '', }) class TestComponent {} describe('PrefixDirective', () => { - let fixture: ComponentFixture; - let component: TestComponent; + let fixture: ComponentFixture; + let component: TestComponent; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [PrefixDirective, TestComponent], - providers: [TemplateRef], - }).compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [PrefixDirective, TestComponent], + providers: [TemplateRef], + }).compileComponents(); - fixture = TestBed.createComponent(TestComponent); - fixture.detectChanges(); + fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); - component = fixture.componentInstance; - }); + component = fixture.componentInstance; + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/directives/prefix.directive.ts b/src/app/forms/directives/prefix.directive.ts index 8c326b6869..7b0bb5e3d2 100644 --- a/src/app/forms/directives/prefix.directive.ts +++ b/src/app/forms/directives/prefix.directive.ts @@ -1,8 +1,8 @@ import { Directive, TemplateRef } from '@angular/core'; @Directive({ - selector: '[appPrefix]', + selector: '[appPrefix]', }) export class PrefixDirective { - constructor(public templateRef: TemplateRef) {} + constructor(public templateRef: TemplateRef) {} } diff --git a/src/app/forms/directives/suffix.directive.spec.ts b/src/app/forms/directives/suffix.directive.spec.ts index beab7b4c77..a7d14644a7 100644 --- a/src/app/forms/directives/suffix.directive.spec.ts +++ b/src/app/forms/directives/suffix.directive.spec.ts @@ -3,27 +3,27 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { SuffixDirective } from './suffix.directive'; @Component({ - template: '', + template: '', }) class TestComponent {} describe('SuffixDirective', () => { - let fixture: ComponentFixture; - let component: TestComponent; + let fixture: ComponentFixture; + let component: TestComponent; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [SuffixDirective, TestComponent], - providers: [TemplateRef], - }).compileComponents(); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [SuffixDirective, TestComponent], + providers: [TemplateRef], + }).compileComponents(); - fixture = TestBed.createComponent(TestComponent); - fixture.detectChanges(); + fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); - component = fixture.componentInstance; - }); + component = fixture.componentInstance; + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/forms/directives/suffix.directive.ts b/src/app/forms/directives/suffix.directive.ts index d4e5b77934..46bc9ab097 100644 --- a/src/app/forms/directives/suffix.directive.ts +++ b/src/app/forms/directives/suffix.directive.ts @@ -1,8 +1,8 @@ import { Directive, TemplateRef } from '@angular/core'; @Directive({ - selector: '[appSuffix]', + selector: '[appSuffix]', }) export class SuffixDirective { - constructor(public templateRef: TemplateRef) {} + constructor(public templateRef: TemplateRef) {} } diff --git a/src/app/forms/dynamic-forms.module.ts b/src/app/forms/dynamic-forms.module.ts index a9aea0b22a..ad435ca704 100644 --- a/src/app/forms/dynamic-forms.module.ts +++ b/src/app/forms/dynamic-forms.module.ts @@ -4,12 +4,8 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; import { ApprovalTypeFocusNextDirective } from '@forms/components/approval-type/approval-type-focus-next.directive'; import { ApprovalTypeInputComponent } from '@forms/components/approval-type/approval-type.component'; -import { - AdrCertificateHistoryComponent, -} from '@forms/custom-sections/adr-certificate-history/adr-certificate-history.component'; -import { - AdrExaminerNotesHistoryEditComponent, -} from '@forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit'; +import { AdrCertificateHistoryComponent } from '@forms/custom-sections/adr-certificate-history/adr-certificate-history.component'; +import { AdrExaminerNotesHistoryEditComponent } from '@forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit'; import { ApprovalTypeComponent } from '@forms/custom-sections/approval-type/approval-type.component'; import { TruncatePipe } from '@shared/pipes/truncate/truncate.pipe'; import { SharedModule } from '@shared/shared.module'; @@ -38,25 +34,13 @@ import { ViewCombinationComponent } from './components/view-combination/view-com import { ViewListItemComponent } from './components/view-list-item/view-list-item.component'; import { AbandonDialogComponent } from './custom-sections/abandon-dialog/abandon-dialog.component'; import { AdrExaminerNotesHistoryViewComponent } from './custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component'; -import { - AdrNewCertificateRequiredViewComponent, -} from './custom-sections/adr-new-certificate-required-view/adr-new-certificate-required-view.component'; -import { - AdrTankDetailsInitialInspectionViewComponent, -} from './custom-sections/adr-tank-details-initial-inspection-view/adr-tank-details-initial-inspection-view.component'; +import { AdrNewCertificateRequiredViewComponent } from './custom-sections/adr-new-certificate-required-view/adr-new-certificate-required-view.component'; +import { AdrTankDetailsInitialInspectionViewComponent } from './custom-sections/adr-tank-details-initial-inspection-view/adr-tank-details-initial-inspection-view.component'; import { AdrTankDetailsM145ViewComponent } from './custom-sections/adr-tank-details-m145-view/adr-tank-details-m145-view.component'; -import { - AdrTankDetailsSubsequentInspectionsEditComponent, -} from './custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component'; -import { - AdrTankDetailsSubsequentInspectionsViewComponent, -} from './custom-sections/adr-tank-details-subsequent-inspections-view/adr-tank-details-subsequent-inspections-view.component'; -import { - AdrTankStatementUnNumberEditComponent, -} from './custom-sections/adr-tank-statement-un-number-edit/adr-tank-statement-un-number-edit.component'; -import { - AdrTankStatementUnNumberViewComponent, -} from './custom-sections/adr-tank-statement-un-number-view/adr-tank-statement-un-number-view.component'; +import { AdrTankDetailsSubsequentInspectionsEditComponent } from './custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component'; +import { AdrTankDetailsSubsequentInspectionsViewComponent } from './custom-sections/adr-tank-details-subsequent-inspections-view/adr-tank-details-subsequent-inspections-view.component'; +import { AdrTankStatementUnNumberEditComponent } from './custom-sections/adr-tank-statement-un-number-edit/adr-tank-statement-un-number-edit.component'; +import { AdrTankStatementUnNumberViewComponent } from './custom-sections/adr-tank-statement-un-number-view/adr-tank-statement-un-number-view.component'; import { AdrComponent } from './custom-sections/adr/adr.component'; import { BodyComponent } from './custom-sections/body/body.component'; import { CustomDefectComponent } from './custom-sections/custom-defect/custom-defect.component'; @@ -82,119 +66,119 @@ import { PrefixDirective } from './directives/prefix.directive'; import { SuffixDirective } from './directives/suffix.directive'; @NgModule({ - declarations: [ - BaseControlComponent, - TextInputComponent, - ViewListItemComponent, - DynamicFormGroupComponent, - ViewCombinationComponent, - CheckboxGroupComponent, - RadioGroupComponent, - DefectComponent, - DefectsComponent, - AutocompleteComponent, - NumberInputComponent, - TextAreaComponent, - NumberOnlyDirective, - ToUppercaseDirective, - NoSpaceDirective, - TrimWhitespaceDirective, - DateComponent, - SelectComponent, - DynamicFormFieldComponent, - FieldErrorMessageComponent, - DefectSelectComponent, - RequiredStandardSelectComponent, - FocusNextDirective, - TruncatePipe, - WeightsComponent, - LettersComponent, - PlatesComponent, - DimensionsComponent, - TrlBrakesComponent, - ReadOnlyComponent, - CustomDefectsComponent, - RequiredStandardComponent, - RequiredStandardsComponent, - CustomDefectComponent, - SwitchableInputComponent, - ReadOnlyComponent, - SuffixDirective, - AbandonDialogComponent, - BodyComponent, - TyresComponent, - PsvBrakesComponent, - PrefixDirective, - SuggestiveInputComponent, - CheckboxComponent, - ApprovalTypeComponent, - ApprovalTypeInputComponent, - ApprovalTypeFocusNextDirective, - ModifiedWeightsComponent, - FieldWarningMessageComponent, - AdrComponent, - AdrTankDetailsSubsequentInspectionsEditComponent, - AdrTankStatementUnNumberEditComponent, - CustomFormControlComponent, - AdrExaminerNotesHistoryEditComponent, - AdrExaminerNotesHistoryViewComponent, - AdrTankDetailsSubsequentInspectionsViewComponent, - AdrTankDetailsInitialInspectionViewComponent, - AdrTankStatementUnNumberViewComponent, - AdrCertificateHistoryComponent, - AdrTankDetailsM145ViewComponent, - ContingencyAdrGenerateCertComponent, - AdrNewCertificateRequiredViewComponent, - ], - imports: [CommonModule, FormsModule, ReactiveFormsModule, SharedModule, RouterModule], - exports: [ - TextInputComponent, - ViewListItemComponent, - DynamicFormGroupComponent, - ViewCombinationComponent, - CheckboxGroupComponent, - RadioGroupComponent, - DefectComponent, - DefectsComponent, - AutocompleteComponent, - NumberInputComponent, - TextAreaComponent, - DateComponent, - SelectComponent, - DynamicFormFieldComponent, - FieldErrorMessageComponent, - DefectSelectComponent, - RequiredStandardSelectComponent, - WeightsComponent, - LettersComponent, - PlatesComponent, - TyresComponent, - DimensionsComponent, - TrlBrakesComponent, - ReadOnlyComponent, - RequiredStandardComponent, - RequiredStandardsComponent, - CustomDefectsComponent, - CustomDefectComponent, - SwitchableInputComponent, - SuffixDirective, - ReadOnlyComponent, - AbandonDialogComponent, - BodyComponent, - PsvBrakesComponent, - PrefixDirective, - SuggestiveInputComponent, - CheckboxComponent, - ToUppercaseDirective, - NoSpaceDirective, - TrimWhitespaceDirective, - ApprovalTypeComponent, - ApprovalTypeInputComponent, - ApprovalTypeFocusNextDirective, - ModifiedWeightsComponent, - AdrComponent, - AdrCertificateHistoryComponent, - FieldWarningMessageComponent, - ], + declarations: [ + BaseControlComponent, + TextInputComponent, + ViewListItemComponent, + DynamicFormGroupComponent, + ViewCombinationComponent, + CheckboxGroupComponent, + RadioGroupComponent, + DefectComponent, + DefectsComponent, + AutocompleteComponent, + NumberInputComponent, + TextAreaComponent, + NumberOnlyDirective, + ToUppercaseDirective, + NoSpaceDirective, + TrimWhitespaceDirective, + DateComponent, + SelectComponent, + DynamicFormFieldComponent, + FieldErrorMessageComponent, + DefectSelectComponent, + RequiredStandardSelectComponent, + FocusNextDirective, + TruncatePipe, + WeightsComponent, + LettersComponent, + PlatesComponent, + DimensionsComponent, + TrlBrakesComponent, + ReadOnlyComponent, + CustomDefectsComponent, + RequiredStandardComponent, + RequiredStandardsComponent, + CustomDefectComponent, + SwitchableInputComponent, + ReadOnlyComponent, + SuffixDirective, + AbandonDialogComponent, + BodyComponent, + TyresComponent, + PsvBrakesComponent, + PrefixDirective, + SuggestiveInputComponent, + CheckboxComponent, + ApprovalTypeComponent, + ApprovalTypeInputComponent, + ApprovalTypeFocusNextDirective, + ModifiedWeightsComponent, + FieldWarningMessageComponent, + AdrComponent, + AdrTankDetailsSubsequentInspectionsEditComponent, + AdrTankStatementUnNumberEditComponent, + CustomFormControlComponent, + AdrExaminerNotesHistoryEditComponent, + AdrExaminerNotesHistoryViewComponent, + AdrTankDetailsSubsequentInspectionsViewComponent, + AdrTankDetailsInitialInspectionViewComponent, + AdrTankStatementUnNumberViewComponent, + AdrCertificateHistoryComponent, + AdrTankDetailsM145ViewComponent, + ContingencyAdrGenerateCertComponent, + AdrNewCertificateRequiredViewComponent, + ], + imports: [CommonModule, FormsModule, ReactiveFormsModule, SharedModule, RouterModule], + exports: [ + TextInputComponent, + ViewListItemComponent, + DynamicFormGroupComponent, + ViewCombinationComponent, + CheckboxGroupComponent, + RadioGroupComponent, + DefectComponent, + DefectsComponent, + AutocompleteComponent, + NumberInputComponent, + TextAreaComponent, + DateComponent, + SelectComponent, + DynamicFormFieldComponent, + FieldErrorMessageComponent, + DefectSelectComponent, + RequiredStandardSelectComponent, + WeightsComponent, + LettersComponent, + PlatesComponent, + TyresComponent, + DimensionsComponent, + TrlBrakesComponent, + ReadOnlyComponent, + RequiredStandardComponent, + RequiredStandardsComponent, + CustomDefectsComponent, + CustomDefectComponent, + SwitchableInputComponent, + SuffixDirective, + ReadOnlyComponent, + AbandonDialogComponent, + BodyComponent, + PsvBrakesComponent, + PrefixDirective, + SuggestiveInputComponent, + CheckboxComponent, + ToUppercaseDirective, + NoSpaceDirective, + TrimWhitespaceDirective, + ApprovalTypeComponent, + ApprovalTypeInputComponent, + ApprovalTypeFocusNextDirective, + ModifiedWeightsComponent, + AdrComponent, + AdrCertificateHistoryComponent, + FieldWarningMessageComponent, + ], }) -export class DynamicFormsModule { } +export class DynamicFormsModule {} diff --git a/src/app/forms/models/async-validators.enum.ts b/src/app/forms/models/async-validators.enum.ts index cec42b68f7..98f51b08b3 100644 --- a/src/app/forms/models/async-validators.enum.ts +++ b/src/app/forms/models/async-validators.enum.ts @@ -1,14 +1,14 @@ export enum AsyncValidatorNames { - ResultDependantOnCustomDefects = 'resultDependantOnCustomDefects', - ResultDependantOnRequiredStandards = 'resultDependantOnRequiredStandards', - UpdateTestStationDetails = 'updateTestStationDetails', - UpdateTesterDetails = 'updateTesterDetails', - RequiredIfNotFail = 'requiredIfNotfail', - RequiredIfNotAbandoned = 'requiredIfNotabandoned', - RequiredIfNotResultAndSiblingEquals = 'requiredIfNotResultAndSiblingEquals', - RequiredIfNotResult = 'requiredIfNotResult', - HideIfEqualsWithCondition = 'hideIfEqualsWithCondition', - PassResultDependantOnCustomDefects = 'passResultDependantOnCustomDefects', - RequiredWhenCarryingDangerousGoods = 'requiredWhenCarryingDangerousGoods', - Custom = 'custom', + ResultDependantOnCustomDefects = 'resultDependantOnCustomDefects', + ResultDependantOnRequiredStandards = 'resultDependantOnRequiredStandards', + UpdateTestStationDetails = 'updateTestStationDetails', + UpdateTesterDetails = 'updateTesterDetails', + RequiredIfNotFail = 'requiredIfNotfail', + RequiredIfNotAbandoned = 'requiredIfNotabandoned', + RequiredIfNotResultAndSiblingEquals = 'requiredIfNotResultAndSiblingEquals', + RequiredIfNotResult = 'requiredIfNotResult', + HideIfEqualsWithCondition = 'hideIfEqualsWithCondition', + PassResultDependantOnCustomDefects = 'passResultDependantOnCustomDefects', + RequiredWhenCarryingDangerousGoods = 'requiredWhenCarryingDangerousGoods', + Custom = 'custom', } diff --git a/src/app/forms/models/condition.model.ts b/src/app/forms/models/condition.model.ts index 8f491028b6..4908893c8d 100644 --- a/src/app/forms/models/condition.model.ts +++ b/src/app/forms/models/condition.model.ts @@ -1,10 +1,10 @@ export enum operatorEnum { - Equals = 'equals', - NotEquals = 'not equals', + Equals = 'equals', + NotEquals = 'not equals', } export interface Condition { - field: string; - operator: operatorEnum; - value: unknown; + field: string; + operator: operatorEnum; + value: unknown; } diff --git a/src/app/forms/models/options.model.ts b/src/app/forms/models/options.model.ts index 75b764014c..055ef6adab 100644 --- a/src/app/forms/models/options.model.ts +++ b/src/app/forms/models/options.model.ts @@ -1,5 +1,5 @@ export interface MultiOption { - label: string; - value: string | number | boolean; + label: string; + value: string | number | boolean; } export type MultiOptions = Array; diff --git a/src/app/forms/models/plateRequiredFields.model.ts b/src/app/forms/models/plateRequiredFields.model.ts index f1162de17a..0a6fedebad 100644 --- a/src/app/forms/models/plateRequiredFields.model.ts +++ b/src/app/forms/models/plateRequiredFields.model.ts @@ -1,43 +1,40 @@ export const hgvRequiredFields: string[] = [ - 'primaryVrm', - 'vin', - 'techRecord_brakes_dtpNumber', - 'techRecord_regnDate', - 'techRecord_manufactureYear', - 'techRecord_speedLimiterMrk', - 'techRecord_variantNumber', - 'techRecord_make', - 'techRecord_model', - 'techRecord_functionCode', - 'techRecord_dimensions_length', - 'techRecord_dimensions_width', - 'techRecord_tyreUseCode', - 'techRecord_axles', - 'techRecord_roadFriendly', - 'techRecord_vehicleConfiguration', + 'primaryVrm', + 'vin', + 'techRecord_brakes_dtpNumber', + 'techRecord_regnDate', + 'techRecord_manufactureYear', + 'techRecord_speedLimiterMrk', + 'techRecord_variantNumber', + 'techRecord_make', + 'techRecord_model', + 'techRecord_functionCode', + 'techRecord_dimensions_length', + 'techRecord_dimensions_width', + 'techRecord_tyreUseCode', + 'techRecord_axles', + 'techRecord_roadFriendly', + 'techRecord_vehicleConfiguration', ]; -export const tyreRequiredFields: string[] = [ - 'tyres_tyreSize', - 'tyres_fitmentCode', -]; +export const tyreRequiredFields: string[] = ['tyres_tyreSize', 'tyres_fitmentCode']; export const trlRequiredFields: string[] = [ - 'trailerId', - 'vin', - 'techRecord_brakes_dtpNumber', - 'techRecord_manufactureYear', - 'techRecord_maxLoadOnCoupling', - 'techRecord_variantNumber', - 'techRecord_make', - 'techRecord_model', - 'techRecord_functionCode', - 'techRecord_couplingCenterToRearTrlMax', - 'techRecord_couplingCenterToRearTrlMin', - 'techRecord_dimensions_length', - 'techRecord_dimensions_width', - 'techRecord_tyreUseCode', - 'techRecord_axles', - 'techRecord_roadFriendly', - 'techRecord_vehicleConfiguration', + 'trailerId', + 'vin', + 'techRecord_brakes_dtpNumber', + 'techRecord_manufactureYear', + 'techRecord_maxLoadOnCoupling', + 'techRecord_variantNumber', + 'techRecord_make', + 'techRecord_model', + 'techRecord_functionCode', + 'techRecord_couplingCenterToRearTrlMax', + 'techRecord_couplingCenterToRearTrlMin', + 'techRecord_dimensions_length', + 'techRecord_dimensions_width', + 'techRecord_tyreUseCode', + 'techRecord_axles', + 'techRecord_roadFriendly', + 'techRecord_vehicleConfiguration', ]; diff --git a/src/app/forms/models/testTypeId.enum.ts b/src/app/forms/models/testTypeId.enum.ts index 8ec7c67754..c445ba05b5 100644 --- a/src/app/forms/models/testTypeId.enum.ts +++ b/src/app/forms/models/testTypeId.enum.ts @@ -14,7 +14,23 @@ export const TEST_TYPES_GROUP2: string[] = ['15', '16', '23', '19', '22']; // voluntary smoke test, voluntary headlamp aim test, vitesse 100 replacement, vitesse 100 application, voluntary tempo 100 // 86 through 90 - tests for HGV - voluntary multi-check, voluntary speed limiter check, voluntary smoke and headlamp aim test // NOTE: the 47, and 48 from group 8 are excluded and use there own template to enable issuing documents centrally -export const TEST_TYPES_GROUP3_4_8: string[] = ['38', '30', '33', '34', '32', '31', '100', '121', '36', '86', '88', '89', '90', '87', '85']; +export const TEST_TYPES_GROUP3_4_8: string[] = [ + '38', + '30', + '33', + '34', + '32', + '31', + '100', + '121', + '36', + '86', + '88', + '89', + '90', + '87', + '85', +]; // 47 - free notifiable alteration (HGV/TRL), 48 - paid notifiable alteration (HGV/TRL) export const TEST_TYPES_GROUP8_NOTIFABLE = ['47', '48']; @@ -34,7 +50,22 @@ export const TEST_TYPES_GROUP6_11: string[] = ['62', '63', '122', '101', '91']; export const TEST_TYPES_GROUP7: string[] = ['59', '60', '50']; // tests for HGV and TRL - Annual tests, Annual retests, Paid/Part paid prohibition clearance on annual test -export const TEST_TYPES_GROUP9_10: string[] = ['76', '94', '53', '54', '70', '79', '40', '98', '99', '67', '107', '113', '116', '199']; +export const TEST_TYPES_GROUP9_10: string[] = [ + '76', + '94', + '53', + '54', + '70', + '79', + '40', + '98', + '99', + '67', + '107', + '113', + '116', + '199', +]; // tests for HGV and TRL - First tests, Paid/Part paid prohibition clearance on first test export const TEST_TYPES_GROUP9_10_CENTRAL_DOCS = ['95', '41', '65', '103', '66', '104', '82', '119', '83', '120']; @@ -49,44 +80,55 @@ export const TEST_TYPES_GROUP15_16: string[] = ['39', '201', '45', '44']; // Test/Retest - Free/Paid - IVA inspection, MSVA inspection export const TEST_TYPES_GROUP1_SPEC_TEST: string[] = [ - '125', - '126', - '186', - '187', - '128', - '188', - '189', - '129', - '130', - '133', - '134', - '135', - '136', - '138', - '139', - '140', - '158', - '159', - '161', - '192', - '193', - '162', - '194', - '195', - '163', - '166', - '167', - '169', - '170', - '172', - '173', + '125', + '126', + '186', + '187', + '128', + '188', + '189', + '129', + '130', + '133', + '134', + '135', + '136', + '138', + '139', + '140', + '158', + '159', + '161', + '192', + '193', + '162', + '194', + '195', + '163', + '166', + '167', + '169', + '170', + '172', + '173', ]; // Test/Retest COIF with annual test, Seatbelt installation check COIF with annual test export const TEST_TYPES_GROUP2_SPEC_TEST: string[] = ['142', '146', '175', '177']; // Test/Retest COIF without annual test, Type approved to bus directive COIF, Annex 7 COIF, TILT COIF retest -export const TEST_TYPES_GROUP3_SPEC_TEST: string[] = ['143', '144', '148', '176', '178', '179', '150', '151', '181', '182']; +export const TEST_TYPES_GROUP3_SPEC_TEST: string[] = [ + '143', + '144', + '148', + '176', + '178', + '179', + '150', + '151', + '181', + '182', +]; // Test Seatbelt installation check COIF without annual test export const TEST_TYPES_GROUP4_SPEC_TEST: string[] = ['147']; @@ -95,104 +137,116 @@ export const TEST_TYPES_GROUP4_SPEC_TEST: string[] = ['147']; export const TEST_TYPES_GROUP5_SPEC_TEST: string[] = ['153', '190', '191', '154', '184', '196', '197', '185']; export const SPECIALIST_TEST_TYPE_IDS: string[] = [ - '125', - '126', - '186', - '187', - '128', - '188', - '189', - '129', - '130', - '133', - '134', - '135', - '136', - '138', - '139', - '140', - '150', - '151', - '158', - '159', - '161', - '192', - '193', - '162', - '194', - '195', - '163', - '166', - '167', - '169', - '170', - '172', - '173', - '181', - '182', - '142', - '146', - '175', - '177', - '143', - '144', - '148', - '176', - '178', - '179', - '147', - '153', - '190', - '191', - '154', - '184', - '196', - '197', - '185', + '125', + '126', + '186', + '187', + '128', + '188', + '189', + '129', + '130', + '133', + '134', + '135', + '136', + '138', + '139', + '140', + '150', + '151', + '158', + '159', + '161', + '192', + '193', + '162', + '194', + '195', + '163', + '166', + '167', + '169', + '170', + '172', + '173', + '181', + '182', + '142', + '146', + '175', + '177', + '143', + '144', + '148', + '176', + '178', + '179', + '147', + '153', + '190', + '191', + '154', + '184', + '196', + '197', + '185', ]; export const TEST_TYPES_GROUP1_DESK_BASED_TEST: string[] = ['417', '418']; export const TEST_TYPES_GROUP2_DESK_BASED_TEST: string[] = ['403', '404', '415']; export const TEST_TYPES_GROUP3_DESK_BASED_TEST: string[] = [ - '407', - '408', - '414', - '420', - '426', - '431', - '432', - '443', - '444', - '445', - '446', - '447', - '448', + '407', + '408', + '414', + '420', + '426', + '431', + '432', + '443', + '444', + '445', + '446', + '447', + '448', +]; +export const TEST_TYPES_GROUP4_DESK_BASED_TEST: string[] = [ + '409', + '411', + '412', + '423', + '424', + '425', + '433', + '435', + '436', + '437', + '438', ]; -export const TEST_TYPES_GROUP4_DESK_BASED_TEST: string[] = ['409', '411', '412', '423', '424', '425', '433', '435', '436', '437', '438']; export const TEST_TYPES_GROUP5_DESK_BASED_TEST: string[] = ['439', '441', '442', '449']; export const TEST_TYPES = { - testTypesGroup1: TEST_TYPES_GROUP1, - testTypesGroup2: TEST_TYPES_GROUP2, - testTypesGroup3And4And8: TEST_TYPES_GROUP3_4_8, - testTypesGroup7: TEST_TYPES_GROUP7, - testTypesGroup8Notifiable: TEST_TYPES_GROUP8_NOTIFABLE, - testTypesGroup9And10: TEST_TYPES_GROUP9_10, - testTypesGroup9And10CentralDocs: TEST_TYPES_GROUP9_10_CENTRAL_DOCS, - testTypesGroup6And11: TEST_TYPES_GROUP6_11, - testTypesGroup12And14: TEST_TYPES_GROUP12_14, - testTypesGroup5And13: TEST_TYPES_GROUP5_13, - testTypesGroup15And16: TEST_TYPES_GROUP15_16, - testTypesSpecialistGroup1: TEST_TYPES_GROUP1_SPEC_TEST, - testTypesSpecialistGroup2: TEST_TYPES_GROUP2_SPEC_TEST, - testTypesSpecialistGroup3: TEST_TYPES_GROUP3_SPEC_TEST, - testTypesSpecialistGroup4: TEST_TYPES_GROUP4_SPEC_TEST, - testTypesSpecialistGroup5: TEST_TYPES_GROUP5_SPEC_TEST, - testTypesDeskBasedGroup1: TEST_TYPES_GROUP1_DESK_BASED_TEST, - testTypesDeskBasedGroup2: TEST_TYPES_GROUP2_DESK_BASED_TEST, - testTypesDeskBasedGroup3: TEST_TYPES_GROUP3_DESK_BASED_TEST, - testTypesDeskBasedGroup4: TEST_TYPES_GROUP4_DESK_BASED_TEST, - testTypesDeskBasedGroup5: TEST_TYPES_GROUP5_DESK_BASED_TEST, - testTypesSpecialistGroup1OldIVAorMSVA: TEST_TYPES_GROUP1_SPEC_TEST, - testTypesSpecialistGroup5OldIVAorMSVA: TEST_TYPES_GROUP5_SPEC_TEST, + testTypesGroup1: TEST_TYPES_GROUP1, + testTypesGroup2: TEST_TYPES_GROUP2, + testTypesGroup3And4And8: TEST_TYPES_GROUP3_4_8, + testTypesGroup7: TEST_TYPES_GROUP7, + testTypesGroup8Notifiable: TEST_TYPES_GROUP8_NOTIFABLE, + testTypesGroup9And10: TEST_TYPES_GROUP9_10, + testTypesGroup9And10CentralDocs: TEST_TYPES_GROUP9_10_CENTRAL_DOCS, + testTypesGroup6And11: TEST_TYPES_GROUP6_11, + testTypesGroup12And14: TEST_TYPES_GROUP12_14, + testTypesGroup5And13: TEST_TYPES_GROUP5_13, + testTypesGroup15And16: TEST_TYPES_GROUP15_16, + testTypesSpecialistGroup1: TEST_TYPES_GROUP1_SPEC_TEST, + testTypesSpecialistGroup2: TEST_TYPES_GROUP2_SPEC_TEST, + testTypesSpecialistGroup3: TEST_TYPES_GROUP3_SPEC_TEST, + testTypesSpecialistGroup4: TEST_TYPES_GROUP4_SPEC_TEST, + testTypesSpecialistGroup5: TEST_TYPES_GROUP5_SPEC_TEST, + testTypesDeskBasedGroup1: TEST_TYPES_GROUP1_DESK_BASED_TEST, + testTypesDeskBasedGroup2: TEST_TYPES_GROUP2_DESK_BASED_TEST, + testTypesDeskBasedGroup3: TEST_TYPES_GROUP3_DESK_BASED_TEST, + testTypesDeskBasedGroup4: TEST_TYPES_GROUP4_DESK_BASED_TEST, + testTypesDeskBasedGroup5: TEST_TYPES_GROUP5_DESK_BASED_TEST, + testTypesSpecialistGroup1OldIVAorMSVA: TEST_TYPES_GROUP1_SPEC_TEST, + testTypesSpecialistGroup5OldIVAorMSVA: TEST_TYPES_GROUP5_SPEC_TEST, }; diff --git a/src/app/forms/models/validators.enum.ts b/src/app/forms/models/validators.enum.ts index 550695214e..a7c2148a05 100644 --- a/src/app/forms/models/validators.enum.ts +++ b/src/app/forms/models/validators.enum.ts @@ -1,50 +1,50 @@ export enum ValidatorNames { - CustomPattern = 'customPattern', - DisableIfEquals = 'disableIfEquals', - Email = 'email', - EnableIfEquals = 'enableIfEquals', - HideIfEmpty = 'hideIfEmpty', - HideIfNotEqual = 'hideIfNotEqual', - HideIfParentSiblingEqual = 'hideIfParentSiblingEqual', - HideIfParentSiblingNotEqual = 'hideIfParentSiblingNotEqual', - MaxLength = 'maxlength', - MinLength = 'minlength', - Max = 'max', - Min = 'min', - Alphanumeric = 'alphanumeric', - Numeric = 'numeric', - Pattern = 'pattern', - Required = 'required', - RequiredIfEquals = 'requiredIfEquals', - requiredIfAllEquals = 'requiredIfAllEquals', - RequiredIfNotHidden = 'requiredIfNotHidden', - RequiredIfNotEquals = 'requiredIfNotEquals', - Defined = 'defined', - ValidateDefectNotes = 'validateDefectNotes', - ValidateVRMTrailerIdLength = 'validateVRMTrailerIdLength', - PastDate = 'pastDate', - FutureDate = 'futureDate', - AheadOfDate = 'aheadOfDate', - DateNotExceed = 'dateNotExceed', - PastYear = 'pastYear', - CopyValueToRootControl = 'copyValueToRootControl', - ValidateProhibitionIssued = 'validateProhibitionIssued', - NotZNumber = 'notZNumber', - MustEqualSibling = 'mustEqualSibling', - HandlePsvPassengersChange = 'HandlePsvPassengersChange', - IsMemberOfEnum = 'isMemberOfEnum', - UpdateFunctionCode = 'updateFunctionCode', - ShowGroupsWhenEqualTo = 'showGroupsWhenEqualTo', - HideGroupsWhenEqualTo = 'hideGroupsWhenEqualTo', - ShowGroupsWhenIncludes = 'showGroupsWhenIncludes', - HideGroupsWhenIncludes = 'hideGroupsWhenIncludes', - ShowGroupsWhenExcludes = 'showGroupsWhenExcludes', - HideGroupsWhenExcludes = 'hideGroupsWhenExcludes', - AddWarningForAdrField = 'addWarningForAdrField', - IsArray = 'isArray', - Custom = 'custom', - Tc3TestValidator = 'tc3TestValidator', - DateIsInvalid = 'dateIsInvalid', - MinArrayLengthIfNotEmpty = 'minArrayLengthIfNotEmpty', - IssueRequired = 'issueRequired', + CustomPattern = 'customPattern', + DisableIfEquals = 'disableIfEquals', + Email = 'email', + EnableIfEquals = 'enableIfEquals', + HideIfEmpty = 'hideIfEmpty', + HideIfNotEqual = 'hideIfNotEqual', + HideIfParentSiblingEqual = 'hideIfParentSiblingEqual', + HideIfParentSiblingNotEqual = 'hideIfParentSiblingNotEqual', + MaxLength = 'maxlength', + MinLength = 'minlength', + Max = 'max', + Min = 'min', + Alphanumeric = 'alphanumeric', + Numeric = 'numeric', + Pattern = 'pattern', + Required = 'required', + RequiredIfEquals = 'requiredIfEquals', + requiredIfAllEquals = 'requiredIfAllEquals', + RequiredIfNotHidden = 'requiredIfNotHidden', + RequiredIfNotEquals = 'requiredIfNotEquals', + Defined = 'defined', + ValidateDefectNotes = 'validateDefectNotes', + ValidateVRMTrailerIdLength = 'validateVRMTrailerIdLength', + PastDate = 'pastDate', + FutureDate = 'futureDate', + AheadOfDate = 'aheadOfDate', + DateNotExceed = 'dateNotExceed', + PastYear = 'pastYear', + CopyValueToRootControl = 'copyValueToRootControl', + ValidateProhibitionIssued = 'validateProhibitionIssued', + NotZNumber = 'notZNumber', + MustEqualSibling = 'mustEqualSibling', + HandlePsvPassengersChange = 'HandlePsvPassengersChange', + IsMemberOfEnum = 'isMemberOfEnum', + UpdateFunctionCode = 'updateFunctionCode', + ShowGroupsWhenEqualTo = 'showGroupsWhenEqualTo', + HideGroupsWhenEqualTo = 'hideGroupsWhenEqualTo', + ShowGroupsWhenIncludes = 'showGroupsWhenIncludes', + HideGroupsWhenIncludes = 'hideGroupsWhenIncludes', + ShowGroupsWhenExcludes = 'showGroupsWhenExcludes', + HideGroupsWhenExcludes = 'hideGroupsWhenExcludes', + AddWarningForAdrField = 'addWarningForAdrField', + IsArray = 'isArray', + Custom = 'custom', + Tc3TestValidator = 'tc3TestValidator', + DateIsInvalid = 'dateIsInvalid', + MinArrayLengthIfNotEmpty = 'minArrayLengthIfNotEmpty', + IssueRequired = 'issueRequired', } diff --git a/src/app/forms/services/dynamic-form.service.spec.ts b/src/app/forms/services/dynamic-form.service.spec.ts index c02f9dce36..634d7b751d 100644 --- a/src/app/forms/services/dynamic-form.service.spec.ts +++ b/src/app/forms/services/dynamic-form.service.spec.ts @@ -1,8 +1,6 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; -import { - AbstractControl, FormArray, ValidatorFn, Validators, -} from '@angular/forms'; +import { AbstractControl, FormArray, ValidatorFn, Validators } from '@angular/forms'; import { RouterTestingModule } from '@angular/router/testing'; import { GlobalError } from '@core/components/global-error/global-error.interface'; import { ValidatorNames } from '@forms/models/validators.enum'; @@ -10,244 +8,258 @@ import { provideMockStore } from '@ngrx/store/testing'; import { initialAppState } from '@store/.'; import { DynamicFormService } from './dynamic-form.service'; import { - CustomControl, CustomFormArray, CustomFormControl, CustomFormGroup, FormNode, FormNodeTypes, FormNodeViewTypes, + CustomControl, + CustomFormArray, + CustomFormControl, + CustomFormGroup, + FormNode, + FormNodeTypes, + FormNodeViewTypes, } from './dynamic-form.types'; describe('DynamicFormService', () => { - let service: DynamicFormService; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideMockStore({ initialState: initialAppState })], - imports: [RouterTestingModule, HttpClientTestingModule], - }); - service = TestBed.inject(DynamicFormService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('createForm', () => { - it('should return an empty FormGroup if the root node has no children', () => { - const node: FormNode = { - name: 'empty', - type: FormNodeTypes.GROUP, - }; - - expect(service.createForm(node)).toMatchObject({}); - }); - it('should return a FormGroup containing a single control', () => { - const node: FormNode = { - name: 'group', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'vin', - label: 'Vehicle Identification Number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - }, - ], - }; - - const outputGroup = service.createForm(node); - const children = node.children as FormNode[]; - - expect( - ( - outputGroup.controls as { - [key: string]: AbstractControl; - } - )[children[0].name], - ).toBeTruthy(); - }); - - it('should return a FormGroup mirroring the nested structure of the controls it was created with', () => { - const node: FormNode = { - name: 'group', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'sub-group', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'vin', - label: 'Vehicle Identification Number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - }, - ], - }, - ], - }; - - const children = node.children as FormNode[]; - const grandChildren = children[0].children as FormNode[]; - - const outputGroup = service.createForm(node); - const subGroup = ( - outputGroup.controls as { - [key: string]: AbstractControl; - } - )[children[0].name] as CustomFormGroup; - - expect(subGroup.controls[grandChildren[0].name]).toBeTruthy(); - }); - - it('should return a formGroup with a nested FormArray', () => { - const node: FormNode = { - name: 'group', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'vins', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', - label: 'Vehicle Identification Number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - }, - ], - }, - ], - }; - - const data = { - vins: ['123', '456'], - }; - - const outputGroup = service.createForm(node, data); - const formArray = outputGroup.get('vins'); - expect(formArray instanceof FormArray).toBeTruthy(); - expect((formArray as FormArray).controls).toHaveLength(2); - }); - - it('should return a formGroup with a nested FormArray with data given', () => { - const node: FormNode = { - name: 'group', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'axelsArray', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'vin', - label: 'Vehicle Identification Number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - }, - ], - }, - ], - }, - ], - }; - - const data = { - axelsArray: [ - { - vin: '12345', - }, - { - vin: '78910', - }, - ], - }; - - const outputGroup = service.createForm(node, data); - const formArray = outputGroup.get('axelsArray'); - const subGroup = (formArray as CustomFormArray).controls; - - expect(subGroup).toHaveLength(2); - }); - - it('should return a formGroup with a nested FormArray of simple controls', () => { - const node: FormNode = { - name: 'group', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'axelsArray', - type: FormNodeTypes.ARRAY, - children: [ - { - name: 'vin', - label: 'Vehicle Identification Number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - }, - ], - }, - ], - }; - - const data = { axelsArray: ['12345', '78910'] }; - - const outputGroup = service.createForm(node, data); - const formArray = outputGroup.get('axelsArray'); - const subGroup = (formArray as CustomFormArray).controls; - - expect(subGroup).toHaveLength(2); - }); - - it('should add correct validators', () => { - const node: FormNode = { - name: 'group', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'foo', - type: FormNodeTypes.CONTROL, - validators: [{ name: 'required' }], - }, - ], - }; - - const outputGroup = service.createForm(node); - const control = outputGroup.get('foo'); - expect(control instanceof CustomFormControl).toBeTruthy(); - expect(control?.hasValidator(Validators.required)).toBeTruthy(); - }); - }); - - describe('addValidators', () => { - it('should add validators', () => { - const control: CustomControl = new CustomFormControl({ name: 'testControl', type: FormNodeTypes.CONTROL, children: [] }); - const validators = [{ name: ValidatorNames.Required }]; - const expectedValidator: ValidatorFn = Validators.required; - service.addValidators(control, validators); - expect(control.hasValidator(expectedValidator)).toBeTruthy(); - }); - }); - - describe('static validate functions', () => { - it('should return a list of global errors for invalid controls', () => { - const errors: GlobalError[] = []; - const form = new CustomFormGroup( - { name: 'group', type: FormNodeTypes.GROUP }, - { - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL }, '', { validators: [Validators.required] }), - bar: new CustomFormGroup( - { name: 'innerGroup', type: FormNodeTypes.GROUP }, - { - baz: new CustomFormControl({ name: 'baz', type: FormNodeTypes.CONTROL }, '', { validators: [Validators.required] }), - }, - ), - }, - ); - - DynamicFormService.validate(form, errors); - - expect(errors).toHaveLength(2); - }); - }); + let service: DynamicFormService; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore({ initialState: initialAppState })], + imports: [RouterTestingModule, HttpClientTestingModule], + }); + service = TestBed.inject(DynamicFormService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + describe('createForm', () => { + it('should return an empty FormGroup if the root node has no children', () => { + const node: FormNode = { + name: 'empty', + type: FormNodeTypes.GROUP, + }; + + expect(service.createForm(node)).toMatchObject({}); + }); + it('should return a FormGroup containing a single control', () => { + const node: FormNode = { + name: 'group', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'vin', + label: 'Vehicle Identification Number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + }, + ], + }; + + const outputGroup = service.createForm(node); + const children = node.children as FormNode[]; + + expect( + ( + outputGroup.controls as { + [key: string]: AbstractControl; + } + )[children[0].name] + ).toBeTruthy(); + }); + + it('should return a FormGroup mirroring the nested structure of the controls it was created with', () => { + const node: FormNode = { + name: 'group', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'sub-group', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'vin', + label: 'Vehicle Identification Number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + }, + ], + }, + ], + }; + + const children = node.children as FormNode[]; + const grandChildren = children[0].children as FormNode[]; + + const outputGroup = service.createForm(node); + const subGroup = ( + outputGroup.controls as { + [key: string]: AbstractControl; + } + )[children[0].name] as CustomFormGroup; + + expect(subGroup.controls[grandChildren[0].name]).toBeTruthy(); + }); + + it('should return a formGroup with a nested FormArray', () => { + const node: FormNode = { + name: 'group', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'vins', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + label: 'Vehicle Identification Number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + }, + ], + }, + ], + }; + + const data = { + vins: ['123', '456'], + }; + + const outputGroup = service.createForm(node, data); + const formArray = outputGroup.get('vins'); + expect(formArray instanceof FormArray).toBeTruthy(); + expect((formArray as FormArray).controls).toHaveLength(2); + }); + + it('should return a formGroup with a nested FormArray with data given', () => { + const node: FormNode = { + name: 'group', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'axelsArray', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'vin', + label: 'Vehicle Identification Number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + }, + ], + }, + ], + }, + ], + }; + + const data = { + axelsArray: [ + { + vin: '12345', + }, + { + vin: '78910', + }, + ], + }; + + const outputGroup = service.createForm(node, data); + const formArray = outputGroup.get('axelsArray'); + const subGroup = (formArray as CustomFormArray).controls; + + expect(subGroup).toHaveLength(2); + }); + + it('should return a formGroup with a nested FormArray of simple controls', () => { + const node: FormNode = { + name: 'group', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'axelsArray', + type: FormNodeTypes.ARRAY, + children: [ + { + name: 'vin', + label: 'Vehicle Identification Number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + }, + ], + }, + ], + }; + + const data = { axelsArray: ['12345', '78910'] }; + + const outputGroup = service.createForm(node, data); + const formArray = outputGroup.get('axelsArray'); + const subGroup = (formArray as CustomFormArray).controls; + + expect(subGroup).toHaveLength(2); + }); + + it('should add correct validators', () => { + const node: FormNode = { + name: 'group', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'foo', + type: FormNodeTypes.CONTROL, + validators: [{ name: 'required' }], + }, + ], + }; + + const outputGroup = service.createForm(node); + const control = outputGroup.get('foo'); + expect(control instanceof CustomFormControl).toBeTruthy(); + expect(control?.hasValidator(Validators.required)).toBeTruthy(); + }); + }); + + describe('addValidators', () => { + it('should add validators', () => { + const control: CustomControl = new CustomFormControl({ + name: 'testControl', + type: FormNodeTypes.CONTROL, + children: [], + }); + const validators = [{ name: ValidatorNames.Required }]; + const expectedValidator: ValidatorFn = Validators.required; + service.addValidators(control, validators); + expect(control.hasValidator(expectedValidator)).toBeTruthy(); + }); + }); + + describe('static validate functions', () => { + it('should return a list of global errors for invalid controls', () => { + const errors: GlobalError[] = []; + const form = new CustomFormGroup( + { name: 'group', type: FormNodeTypes.GROUP }, + { + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL }, '', { + validators: [Validators.required], + }), + bar: new CustomFormGroup( + { name: 'innerGroup', type: FormNodeTypes.GROUP }, + { + baz: new CustomFormControl({ name: 'baz', type: FormNodeTypes.CONTROL }, '', { + validators: [Validators.required], + }), + } + ), + } + ); + + DynamicFormService.validate(form, errors); + + expect(errors).toHaveLength(2); + }); + }); }); diff --git a/src/app/forms/services/dynamic-form.service.ts b/src/app/forms/services/dynamic-form.service.ts index 67d69c5c77..de464f6635 100644 --- a/src/app/forms/services/dynamic-form.service.ts +++ b/src/app/forms/services/dynamic-form.service.ts @@ -1,7 +1,5 @@ import { Injectable } from '@angular/core'; -import { - AsyncValidatorFn, FormArray, FormControl, FormGroup, ValidatorFn, Validators, -} from '@angular/forms'; +import { 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'; import { Condition } from '@forms/models/condition.model'; @@ -14,230 +12,251 @@ import { DefectValidators } from '@forms/validators/defects/defect.validators'; import { resultOfTestEnum } from '@models/test-types/test-type.model'; import { Store } from '@ngrx/store'; import { State } from '@store/index'; -import { - CustomFormArray, CustomFormControl, CustomFormGroup, FormNode, FormNodeTypes, -} from './dynamic-form.types'; +import { CustomFormArray, CustomFormControl, CustomFormGroup, FormNode, FormNodeTypes } from './dynamic-form.types'; type CustomFormFields = CustomFormControl | CustomFormArray | CustomFormGroup; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class DynamicFormService { - constructor(private store: Store) {} - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - validatorMap: Record ValidatorFn> = { - [ValidatorNames.AheadOfDate]: (arg: string) => CustomValidators.aheadOfDate(arg), - [ValidatorNames.Alphanumeric]: () => CustomValidators.alphanumeric(), - [ValidatorNames.Email]: () => CustomValidators.email(), - [ValidatorNames.CopyValueToRootControl]: (arg: string) => CustomValidators.copyValueToRootControl(arg), - [ValidatorNames.CustomPattern]: (args: string[]) => CustomValidators.customPattern([...args]), - [ValidatorNames.DateNotExceed]: (args: { sibling: string; months: number }) => CustomValidators.dateNotExceed(args.sibling, args.months), - [ValidatorNames.Defined]: () => CustomValidators.defined(), - [ValidatorNames.DisableIfEquals]: (args: { sibling: string; value: unknown }) => CustomValidators.disableIfEquals(args.sibling, args.value), - [ValidatorNames.EnableIfEquals]: (args: { sibling: string; value: unknown }) => CustomValidators.enableIfEquals(args.sibling, args.value), - [ValidatorNames.FutureDate]: () => CustomValidators.futureDate, - [ValidatorNames.PastYear]: () => CustomValidators.pastYear, - [ValidatorNames.HideIfEmpty]: (args: string) => CustomValidators.hideIfEmpty(args), - [ValidatorNames.HideIfNotEqual]: (args: { sibling: string; value: unknown }) => CustomValidators.hideIfNotEqual(args.sibling, args.value), - [ValidatorNames.HideIfParentSiblingEqual]: (args: { sibling: string; value: unknown }) => - CustomValidators.hideIfParentSiblingEquals(args.sibling, args.value), - [ValidatorNames.HideIfParentSiblingNotEqual]: (args: { sibling: string; value: unknown }) => - CustomValidators.hideIfParentSiblingNotEqual(args.sibling, args.value), - [ValidatorNames.Max]: (args: number) => Validators.max(args), - [ValidatorNames.MaxLength]: (args: number) => Validators.maxLength(args), - [ValidatorNames.Min]: (args: number) => Validators.min(args), - [ValidatorNames.MinLength]: (args: number) => Validators.minLength(args), - [ValidatorNames.NotZNumber]: () => CustomValidators.notZNumber, - [ValidatorNames.Numeric]: () => CustomValidators.numeric(), - [ValidatorNames.PastDate]: () => CustomValidators.pastDate, - [ValidatorNames.Pattern]: (args: string) => Validators.pattern(args), - [ValidatorNames.Required]: () => Validators.required, - [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), - [ValidatorNames.RequiredIfNotEquals]: (args: { sibling: string; value: unknown[] }) => - CustomValidators.requiredIfNotEquals(args.sibling, args.value), - [ValidatorNames.ValidateVRMTrailerIdLength]: (args: { sibling: string }) => CustomValidators.validateVRMTrailerIdLength(args.sibling), - [ValidatorNames.ValidateDefectNotes]: () => DefectValidators.validateDefectNotes, - [ValidatorNames.ValidateProhibitionIssued]: () => DefectValidators.validateProhibitionIssued, - [ValidatorNames.MustEqualSibling]: (args: { sibling: string }) => CustomValidators.mustEqualSibling(args.sibling), - [ValidatorNames.HandlePsvPassengersChange]: (args: { passengersOne: string; passengersTwo: string }) => - CustomValidators.handlePsvPassengersChange(args.passengersOne, args.passengersTwo), - [ValidatorNames.IsMemberOfEnum]: (args: { enum: Record; options?: Partial }) => - CustomValidators.isMemberOfEnum(args.enum, args.options), - [ValidatorNames.UpdateFunctionCode]: () => CustomValidators.updateFunctionCode(), - [ValidatorNames.ShowGroupsWhenEqualTo]: (args: { values: unknown[]; groups: string[] }) => - CustomValidators.showGroupsWhenEqualTo(args.values, args.groups), - [ValidatorNames.HideGroupsWhenEqualTo]: (args: { values: unknown[]; groups: string[] }) => - CustomValidators.hideGroupsWhenEqualTo(args.values, args.groups), - [ValidatorNames.ShowGroupsWhenIncludes]: (args: { values: unknown[]; groups: string[] }) => - CustomValidators.showGroupsWhenIncludes(args.values, args.groups), - [ValidatorNames.HideGroupsWhenIncludes]: (args: { values: unknown[]; groups: string[] }) => - CustomValidators.hideGroupsWhenIncludes(args.values, args.groups), - [ValidatorNames.ShowGroupsWhenExcludes]: (args: { values: unknown[]; groups: string[] }) => - CustomValidators.showGroupsWhenExcludes(args.values, args.groups), - [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), - [ValidatorNames.Custom]: (...args) => CustomValidators.custom(...args), - [ValidatorNames.Tc3TestValidator]: (args: { inspectionNumber: number }) => CustomValidators.tc3TestValidator(args), - [ValidatorNames.RequiredIfNotHidden]: () => CustomValidators.requiredIfNotHidden(), - [ValidatorNames.DateIsInvalid]: () => CustomValidators.dateIsInvalid, - [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 - asyncValidatorMap: Record AsyncValidatorFn> = { - [AsyncValidatorNames.HideIfEqualsWithCondition]: (args: { sibling: string; value: string; conditions: Condition | Condition[] }) => - CustomAsyncValidators.hideIfEqualsWithCondition(this.store, args.sibling, args.value, args.conditions), - [AsyncValidatorNames.PassResultDependantOnCustomDefects]: () => CustomAsyncValidators.passResultDependantOnCustomDefects(this.store), - [AsyncValidatorNames.RequiredIfNotAbandoned]: () => CustomAsyncValidators.requiredIfNotAbandoned(this.store), - [AsyncValidatorNames.RequiredIfNotFail]: () => CustomAsyncValidators.requiredIfNotFail(this.store), - [AsyncValidatorNames.RequiredIfNotResult]: (args: { testResult: resultOfTestEnum | resultOfTestEnum[] }) => - CustomAsyncValidators.requiredIfNotResult(this.store, args.testResult), - [AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals]: (args: { - 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 - createForm(formNode: FormNode, data?: any): CustomFormGroup | CustomFormArray { - if (!formNode) { - return new CustomFormGroup(formNode, {}); - } - - const form: CustomFormGroup | CustomFormArray = formNode.type === FormNodeTypes.ARRAY - ? new CustomFormArray(formNode, [], this.store) - : new CustomFormGroup(formNode, {}); - - data = data ?? (formNode.type === FormNodeTypes.ARRAY ? [] : {}); - - formNode.children?.forEach((child) => { - const { - name, type, value, validators, asyncValidators, disabled, - } = child; - - const control = FormNodeTypes.CONTROL === type - ? new CustomFormControl({ ...child }, { value, disabled: !!disabled }) - : this.createForm(child, data[`${name}`]); - - if (validators?.length) { - this.addValidators(control, validators); - } - - if (asyncValidators?.length) { - this.addAsyncValidators(control, asyncValidators); - } - - if (form instanceof FormGroup) { - form.addControl(name, control); - } else if (form instanceof FormArray) { - this.createControls(child, data).forEach((element) => form.push(element)); - } - }); - - if (data) { - form.patchValue(data); - } - - return form; - } - - createControls(child: FormNode, data: unknown): CustomFormFields[] { - // Note: There's a quirk here when dealing with arrays where if - // `data` is an array then `child.name` should be a correct index so - // make sure the template has the correct name to the node. - return Array.isArray(data) - ? data.map(() => - FormNodeTypes.CONTROL !== child.type - ? this.createForm(child, data[Number(child.name)]) - : new CustomFormControl({ ...child }, { value: child.value, disabled: !!child.disabled })) - : [new CustomFormControl({ ...child }, { value: child.value, disabled: !!child.disabled })]; - } - - addValidators(control: CustomFormFields, validators: Array<{ name: ValidatorNames; args?: unknown }> = []) { - validators.forEach((v) => control.addValidators(this.validatorMap[v.name](v.args))); - } - - addAsyncValidators(control: CustomFormFields, validators: Array<{ name: AsyncValidatorNames; args?: unknown }> = []) { - validators.forEach((v) => control.addAsyncValidators(this.asyncValidatorMap[v.name](v.args))); - } - - static validate(form: CustomFormGroup | CustomFormArray | FormGroup | FormArray, errors: GlobalError[], updateValidity = true) { - this.getFormLevelErrors(form, errors); - Object.entries(form.controls).forEach(([, value]) => { - if (!(value instanceof FormControl || value instanceof CustomFormControl)) { - this.validate(value as CustomFormGroup | CustomFormArray, errors, updateValidity); - } else { - value.markAsTouched(); - if (updateValidity) { - value.updateValueAndValidity(); - } - (value as CustomFormControl).meta?.changeDetection?.detectChanges(); - this.getControlErrors(value, errors); - } - }); - } - - static getFormLevelErrors(form: CustomFormGroup | CustomFormArray | FormGroup | FormArray, errors: GlobalError[]) { - if (!(form instanceof CustomFormGroup || form instanceof CustomFormArray)) { - return; - } - if (form.errors) { - Object.entries(form.errors).forEach(([key, error]) => { - // If an anchor link is provided, use that, otherwise determine target element from customId or name - const anchorLink = form.meta?.customId ?? form.meta?.name; - errors.push({ - error: ErrorMessageMap[`${key}`](error), - anchorLink, - }); - }); - } - } - - static validateControl(control: FormControl | CustomFormControl, errors: GlobalError[]) { - control.markAsTouched(); - (control as CustomFormControl).meta?.changeDetection?.detectChanges(); - this.getControlErrors(control, errors); - } - - private static getControlErrors(control: FormControl | CustomFormControl, validationErrorList: GlobalError[]) { - const { errors } = control; - const meta = (control as CustomFormControl).meta as FormNode | undefined; - - if (errors) { - if (meta?.hide) return; - 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; - - // 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, - }, - ]; - - validationErrorList.push(...globalErrors); - }); - } - } + constructor(private store: Store) {} + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + validatorMap: Record ValidatorFn> = { + [ValidatorNames.AheadOfDate]: (arg: string) => CustomValidators.aheadOfDate(arg), + [ValidatorNames.Alphanumeric]: () => CustomValidators.alphanumeric(), + [ValidatorNames.Email]: () => CustomValidators.email(), + [ValidatorNames.CopyValueToRootControl]: (arg: string) => CustomValidators.copyValueToRootControl(arg), + [ValidatorNames.CustomPattern]: (args: string[]) => CustomValidators.customPattern([...args]), + [ValidatorNames.DateNotExceed]: (args: { sibling: string; months: number }) => + CustomValidators.dateNotExceed(args.sibling, args.months), + [ValidatorNames.Defined]: () => CustomValidators.defined(), + [ValidatorNames.DisableIfEquals]: (args: { sibling: string; value: unknown }) => + CustomValidators.disableIfEquals(args.sibling, args.value), + [ValidatorNames.EnableIfEquals]: (args: { sibling: string; value: unknown }) => + CustomValidators.enableIfEquals(args.sibling, args.value), + [ValidatorNames.FutureDate]: () => CustomValidators.futureDate, + [ValidatorNames.PastYear]: () => CustomValidators.pastYear, + [ValidatorNames.HideIfEmpty]: (args: string) => CustomValidators.hideIfEmpty(args), + [ValidatorNames.HideIfNotEqual]: (args: { sibling: string; value: unknown }) => + CustomValidators.hideIfNotEqual(args.sibling, args.value), + [ValidatorNames.HideIfParentSiblingEqual]: (args: { sibling: string; value: unknown }) => + CustomValidators.hideIfParentSiblingEquals(args.sibling, args.value), + [ValidatorNames.HideIfParentSiblingNotEqual]: (args: { sibling: string; value: unknown }) => + CustomValidators.hideIfParentSiblingNotEqual(args.sibling, args.value), + [ValidatorNames.Max]: (args: number) => Validators.max(args), + [ValidatorNames.MaxLength]: (args: number) => Validators.maxLength(args), + [ValidatorNames.Min]: (args: number) => Validators.min(args), + [ValidatorNames.MinLength]: (args: number) => Validators.minLength(args), + [ValidatorNames.NotZNumber]: () => CustomValidators.notZNumber, + [ValidatorNames.Numeric]: () => CustomValidators.numeric(), + [ValidatorNames.PastDate]: () => CustomValidators.pastDate, + [ValidatorNames.Pattern]: (args: string) => Validators.pattern(args), + [ValidatorNames.Required]: () => Validators.required, + [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), + [ValidatorNames.RequiredIfNotEquals]: (args: { sibling: string; value: unknown[] }) => + CustomValidators.requiredIfNotEquals(args.sibling, args.value), + [ValidatorNames.ValidateVRMTrailerIdLength]: (args: { sibling: string }) => + CustomValidators.validateVRMTrailerIdLength(args.sibling), + [ValidatorNames.ValidateDefectNotes]: () => DefectValidators.validateDefectNotes, + [ValidatorNames.ValidateProhibitionIssued]: () => DefectValidators.validateProhibitionIssued, + [ValidatorNames.MustEqualSibling]: (args: { sibling: string }) => CustomValidators.mustEqualSibling(args.sibling), + [ValidatorNames.HandlePsvPassengersChange]: (args: { passengersOne: string; passengersTwo: string }) => + CustomValidators.handlePsvPassengersChange(args.passengersOne, args.passengersTwo), + [ValidatorNames.IsMemberOfEnum]: (args: { + enum: Record; + options?: Partial; + }) => CustomValidators.isMemberOfEnum(args.enum, args.options), + [ValidatorNames.UpdateFunctionCode]: () => CustomValidators.updateFunctionCode(), + [ValidatorNames.ShowGroupsWhenEqualTo]: (args: { values: unknown[]; groups: string[] }) => + CustomValidators.showGroupsWhenEqualTo(args.values, args.groups), + [ValidatorNames.HideGroupsWhenEqualTo]: (args: { values: unknown[]; groups: string[] }) => + CustomValidators.hideGroupsWhenEqualTo(args.values, args.groups), + [ValidatorNames.ShowGroupsWhenIncludes]: (args: { values: unknown[]; groups: string[] }) => + CustomValidators.showGroupsWhenIncludes(args.values, args.groups), + [ValidatorNames.HideGroupsWhenIncludes]: (args: { values: unknown[]; groups: string[] }) => + CustomValidators.hideGroupsWhenIncludes(args.values, args.groups), + [ValidatorNames.ShowGroupsWhenExcludes]: (args: { values: unknown[]; groups: string[] }) => + CustomValidators.showGroupsWhenExcludes(args.values, args.groups), + [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), + [ValidatorNames.Custom]: (...args) => CustomValidators.custom(...args), + [ValidatorNames.Tc3TestValidator]: (args: { inspectionNumber: number }) => CustomValidators.tc3TestValidator(args), + [ValidatorNames.RequiredIfNotHidden]: () => CustomValidators.requiredIfNotHidden(), + [ValidatorNames.DateIsInvalid]: () => CustomValidators.dateIsInvalid, + [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 + asyncValidatorMap: Record AsyncValidatorFn> = { + [AsyncValidatorNames.HideIfEqualsWithCondition]: (args: { + sibling: string; + value: string; + conditions: Condition | Condition[]; + }) => CustomAsyncValidators.hideIfEqualsWithCondition(this.store, args.sibling, args.value, args.conditions), + [AsyncValidatorNames.PassResultDependantOnCustomDefects]: () => + CustomAsyncValidators.passResultDependantOnCustomDefects(this.store), + [AsyncValidatorNames.RequiredIfNotAbandoned]: () => CustomAsyncValidators.requiredIfNotAbandoned(this.store), + [AsyncValidatorNames.RequiredIfNotFail]: () => CustomAsyncValidators.requiredIfNotFail(this.store), + [AsyncValidatorNames.RequiredIfNotResult]: (args: { testResult: resultOfTestEnum | resultOfTestEnum[] }) => + CustomAsyncValidators.requiredIfNotResult(this.store, args.testResult), + [AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals]: (args: { + 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 + createForm(formNode: FormNode, data?: any): CustomFormGroup | CustomFormArray { + if (!formNode) { + return new CustomFormGroup(formNode, {}); + } + + const form: CustomFormGroup | CustomFormArray = + formNode.type === FormNodeTypes.ARRAY + ? new CustomFormArray(formNode, [], this.store) + : new CustomFormGroup(formNode, {}); + + data = data ?? (formNode.type === FormNodeTypes.ARRAY ? [] : {}); + + formNode.children?.forEach((child) => { + const { name, type, value, validators, asyncValidators, disabled } = child; + + const control = + FormNodeTypes.CONTROL === type + ? new CustomFormControl({ ...child }, { value, disabled: !!disabled }) + : this.createForm(child, data[`${name}`]); + + if (validators?.length) { + this.addValidators(control, validators); + } + + if (asyncValidators?.length) { + this.addAsyncValidators(control, asyncValidators); + } + + if (form instanceof FormGroup) { + form.addControl(name, control); + } else if (form instanceof FormArray) { + this.createControls(child, data).forEach((element) => form.push(element)); + } + }); + + if (data) { + form.patchValue(data); + } + + return form; + } + + createControls(child: FormNode, data: unknown): CustomFormFields[] { + // Note: There's a quirk here when dealing with arrays where if + // `data` is an array then `child.name` should be a correct index so + // make sure the template has the correct name to the node. + return Array.isArray(data) + ? data.map(() => + FormNodeTypes.CONTROL !== child.type + ? this.createForm(child, data[Number(child.name)]) + : new CustomFormControl({ ...child }, { value: child.value, disabled: !!child.disabled }) + ) + : [new CustomFormControl({ ...child }, { value: child.value, disabled: !!child.disabled })]; + } + + addValidators(control: CustomFormFields, validators: Array<{ name: ValidatorNames; args?: unknown }> = []) { + validators.forEach((v) => control.addValidators(this.validatorMap[v.name](v.args))); + } + + addAsyncValidators(control: CustomFormFields, validators: Array<{ name: AsyncValidatorNames; args?: unknown }> = []) { + validators.forEach((v) => control.addAsyncValidators(this.asyncValidatorMap[v.name](v.args))); + } + + static validate( + form: CustomFormGroup | CustomFormArray | FormGroup | FormArray, + errors: GlobalError[], + updateValidity = true + ) { + this.getFormLevelErrors(form, errors); + Object.entries(form.controls).forEach(([, value]) => { + if (!(value instanceof FormControl || value instanceof CustomFormControl)) { + this.validate(value as CustomFormGroup | CustomFormArray, errors, updateValidity); + } else { + value.markAsTouched(); + if (updateValidity) { + value.updateValueAndValidity(); + } + (value as CustomFormControl).meta?.changeDetection?.detectChanges(); + this.getControlErrors(value, errors); + } + }); + } + + static getFormLevelErrors(form: CustomFormGroup | CustomFormArray | FormGroup | FormArray, errors: GlobalError[]) { + if (!(form instanceof CustomFormGroup || form instanceof CustomFormArray)) { + return; + } + if (form.errors) { + Object.entries(form.errors).forEach(([key, error]) => { + // If an anchor link is provided, use that, otherwise determine target element from customId or name + const anchorLink = form.meta?.customId ?? form.meta?.name; + errors.push({ + error: ErrorMessageMap[`${key}`](error), + anchorLink, + }); + }); + } + } + + static validateControl(control: FormControl | CustomFormControl, errors: GlobalError[]) { + control.markAsTouched(); + (control as CustomFormControl).meta?.changeDetection?.detectChanges(); + this.getControlErrors(control, errors); + } + + private static getControlErrors(control: FormControl | CustomFormControl, validationErrorList: GlobalError[]) { + const { errors } = control; + const meta = (control as CustomFormControl).meta as FormNode | undefined; + + if (errors) { + if (meta?.hide) return; + 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; + + // 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, + }, + ]; + + validationErrorList.push(...globalErrors); + }); + } + } } diff --git a/src/app/forms/services/dynamic-form.types.spec.ts b/src/app/forms/services/dynamic-form.types.spec.ts index ced81f8e7f..a9737423a6 100644 --- a/src/app/forms/services/dynamic-form.types.spec.ts +++ b/src/app/forms/services/dynamic-form.types.spec.ts @@ -1,5 +1,5 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { inject, TestBed } from '@angular/core/testing'; +import { TestBed, inject } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { provideMockStore } from '@ngrx/store/testing'; import { initialAppState } from '@store/.'; @@ -7,64 +7,73 @@ import { DynamicFormService } from './dynamic-form.service'; import { FormNode, FormNodeTypes } from './dynamic-form.types'; describe('Custom Classes', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideMockStore({ initialState: initialAppState })], - imports: [HttpClientTestingModule, RouterTestingModule], - }); - }); + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore({ initialState: initialAppState })], + imports: [HttpClientTestingModule, RouterTestingModule], + }); + }); - describe('getCleanValue', () => { - const template = { - name: 'myForm', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'combinationLevelOne', - label: 'Combination Level One', - type: FormNodeTypes.COMBINATION, - options: { - leftComponentName: 'levelOneControl1', - rightComponentName: 'levelOneControl2', - separator: ' ', - }, - }, - { - name: 'levelOneControl1', type: FormNodeTypes.CONTROL, label: 'Level one control 1', value: 'some string', - }, - { - name: 'levelOneControl2', type: FormNodeTypes.CONTROL, label: 'Level one control 2', value: 'some string', - }, - { name: 'sectionLabel', type: FormNodeTypes.SECTION, label: 'Section Label' }, - { - name: 'levelOneGroup', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'levelTwoControl', type: FormNodeTypes.CONTROL, label: 'Level two control', value: 'some string', - }, - { - name: 'levelTwoArray', - type: FormNodeTypes.ARRAY, - children: [{ name: '0', type: FormNodeTypes.CONTROL, value: '1' }], - }, - ], - }, - ], - }; + describe('getCleanValue', () => { + const template = { + name: 'myForm', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'combinationLevelOne', + label: 'Combination Level One', + type: FormNodeTypes.COMBINATION, + options: { + leftComponentName: 'levelOneControl1', + rightComponentName: 'levelOneControl2', + separator: ' ', + }, + }, + { + name: 'levelOneControl1', + type: FormNodeTypes.CONTROL, + label: 'Level one control 1', + value: 'some string', + }, + { + name: 'levelOneControl2', + type: FormNodeTypes.CONTROL, + label: 'Level one control 2', + value: 'some string', + }, + { name: 'sectionLabel', type: FormNodeTypes.SECTION, label: 'Section Label' }, + { + name: 'levelOneGroup', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'levelTwoControl', + type: FormNodeTypes.CONTROL, + label: 'Level two control', + value: 'some string', + }, + { + name: 'levelTwoArray', + type: FormNodeTypes.ARRAY, + children: [{ name: '0', type: FormNodeTypes.CONTROL, value: '1' }], + }, + ], + }, + ], + }; - const expected = { - levelOneControl1: 'some string', - levelOneControl2: 'some string', - levelOneGroup: { levelTwoControl: 'some string', levelTwoArray: ['1', '2'] }, - }; + const expected = { + levelOneControl1: 'some string', + levelOneControl2: 'some string', + levelOneGroup: { levelTwoControl: 'some string', levelTwoArray: ['1', '2'] }, + }; - it('should return a json object where properties are only FormNodeTypes GROUP | ARRAY | CONTROL', inject( - [DynamicFormService], - (dfs: DynamicFormService) => { - const form = dfs.createForm(template, expected); - expect(form.getCleanValue(form)).toEqual(expected); - }, - )); - }); + it('should return a json object where properties are only FormNodeTypes GROUP | ARRAY | CONTROL', inject( + [DynamicFormService], + (dfs: DynamicFormService) => { + const form = dfs.createForm(template, expected); + expect(form.getCleanValue(form)).toEqual(expected); + } + )); + }); }); diff --git a/src/app/forms/services/dynamic-form.types.ts b/src/app/forms/services/dynamic-form.types.ts index 4f30654ceb..1741082f66 100644 --- a/src/app/forms/services/dynamic-form.types.ts +++ b/src/app/forms/services/dynamic-form.types.ts @@ -1,16 +1,18 @@ // eslint-disable-next-line max-classes-per-file import { ChangeDetectorRef } from '@angular/core'; import { - AbstractControl, - AbstractControlOptions, - AsyncValidatorFn, - FormArray, - FormControl, - FormControlOptions, - FormGroup, - ValidatorFn, + AbstractControl, + AbstractControlOptions, + AsyncValidatorFn, + FormArray, + FormControl, + FormControlOptions, + FormGroup, + ValidatorFn, } from '@angular/forms'; import { Params } from '@angular/router'; +// eslint-disable-next-line import/no-cycle +import { BaseControlComponent } from '@forms/components/base-control/base-control.component'; import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; import { ReferenceDataResourceType } from '@models/reference-data.model'; @@ -18,289 +20,287 @@ import { Store } from '@ngrx/store'; import { TagTypes } from '@shared/components/tag/tag.component'; // eslint-disable-next-line import/no-cycle import { State } from '@store/.'; -// eslint-disable-next-line import/no-cycle -import { BaseControlComponent } from '@forms/components/base-control/base-control.component'; -import { map, Observable } from 'rxjs'; -import { SpecialRefData } from './multi-options.service'; +import { Observable, map } from 'rxjs'; // eslint-disable-next-line import/no-cycle import { DynamicFormService } from './dynamic-form.service'; +import { SpecialRefData } from './multi-options.service'; export enum FormNodeViewTypes { - DATE = 'date', - DATETIME = 'dateTime', - FULLWIDTH = 'fullWidth', - HIDDEN = 'hidden', - STRING = 'string', - SUBHEADING = 'subHeading', - TIME = 'time', - VEHICLETYPE = 'vehicleType', - VRM = 'vrm', - CUSTOM = 'custom', - ADR_EXAMINER_NOTES = 'adrExaminerNotes', // TODO: remove in favour of custom + DATE = 'date', + DATETIME = 'dateTime', + FULLWIDTH = 'fullWidth', + HIDDEN = 'hidden', + STRING = 'string', + SUBHEADING = 'subHeading', + TIME = 'time', + VEHICLETYPE = 'vehicleType', + VRM = 'vrm', + CUSTOM = 'custom', + ADR_EXAMINER_NOTES = 'adrExaminerNotes', // TODO: remove in favour of custom } export enum TagTypeLabels { - REQUIRED = 'Required', - PLATES = 'Plates', + REQUIRED = 'Required', + PLATES = 'Plates', } export enum FormNodeTypes { - ARRAY = 'array', - COMBINATION = 'combination', - CONTROL = 'control', - DIMENSIONS = 'dimensions', - GROUP = 'group', - ROOT = 'root', - SECTION = 'section', - TITLE = 'title', - SUBTITLE = 'subtitle', + ARRAY = 'array', + COMBINATION = 'combination', + CONTROL = 'control', + DIMENSIONS = 'dimensions', + GROUP = 'group', + ROOT = 'root', + SECTION = 'section', + TITLE = 'title', + SUBTITLE = 'subtitle', } export enum FormNodeEditTypes { - AUTOCOMPLETE = 'autocomplete', - CHECKBOX = 'checkbox', - CHECKBOXGROUP = 'checkboxgroup', - DATE = 'date', - DATETIME = 'datetime', - DROPDOWN = 'dropdown', - HIDDEN = 'hidden', - NUMBER = 'number', - NUMERICSTRING = 'numericstring', - RADIO = 'radio', - SELECT = 'select', - TEXT = 'text', - TEXTAREA = 'textarea', - APPROVAL_TYPE = 'approvalType', - CUSTOM = 'custom', + AUTOCOMPLETE = 'autocomplete', + CHECKBOX = 'checkbox', + CHECKBOXGROUP = 'checkboxgroup', + DATE = 'date', + DATETIME = 'datetime', + DROPDOWN = 'dropdown', + HIDDEN = 'hidden', + NUMBER = 'number', + NUMERICSTRING = 'numericstring', + RADIO = 'radio', + SELECT = 'select', + TEXT = 'text', + TEXTAREA = 'textarea', + APPROVAL_TYPE = 'approvalType', + CUSTOM = 'custom', } export enum FormNodeWidth { - XXXL = 50, - XXL = 30, - XL = 20, - L = 10, - M = 5, - S = 4, - XS = 3, - XXS = 2, - UNSET = 'unset', + XXXL = 50, + XXL = 30, + XL = 20, + L = 10, + M = 5, + S = 4, + XS = 3, + XXS = 2, + UNSET = 'unset', } export interface FormNodeOption { - value: T; - label: string; - hint?: string; + value: T; + label: string; + hint?: string; } type AsyncValidatorOptions = AsyncValidatorFn | AsyncValidatorFn[] | null; export interface FormNode { - name: string; - children?: FormNode[]; - type: FormNodeTypes; // maybe updateType? - viewType?: FormNodeViewTypes; - editType?: FormNodeEditTypes; - width?: FormNodeWidth; - label?: string; - hint?: string; - delimited?: { regex?: string; separator: string }; - value?: unknown; - path?: string; - options?: FormNodeOption[] | FormNodeCombinationOptions; - validators?: FormNodeValidator[]; - customErrorMessage?: string; - customValidatorErrorName?: string; - asyncValidators?: { name: AsyncValidatorNames; args?: unknown }[]; - disabled?: boolean; - readonly?: boolean; - hide?: boolean; - required?: boolean; - changeDetection?: ChangeDetectorRef; - subHeadingLink?: SubHeadingLink; - referenceData?: ReferenceDataResourceType | SpecialRefData; - suffix?: string; - isoDate?: boolean; - class?: string; - customId?: string; - warning?: string; - customTags?: CustomTag[]; - enableDecimals?: boolean; - groups?: string[]; - viewComponent?: typeof BaseControlComponent; - editComponent?: typeof BaseControlComponent; + name: string; + children?: FormNode[]; + type: FormNodeTypes; // maybe updateType? + viewType?: FormNodeViewTypes; + editType?: FormNodeEditTypes; + width?: FormNodeWidth; + label?: string; + hint?: string; + delimited?: { regex?: string; separator: string }; + value?: unknown; + path?: string; + options?: FormNodeOption[] | FormNodeCombinationOptions; + validators?: FormNodeValidator[]; + customErrorMessage?: string; + customValidatorErrorName?: string; + asyncValidators?: { name: AsyncValidatorNames; args?: unknown }[]; + disabled?: boolean; + readonly?: boolean; + hide?: boolean; + required?: boolean; + changeDetection?: ChangeDetectorRef; + subHeadingLink?: SubHeadingLink; + referenceData?: ReferenceDataResourceType | SpecialRefData; + suffix?: string; + isoDate?: boolean; + class?: string; + customId?: string; + warning?: string; + customTags?: CustomTag[]; + enableDecimals?: boolean; + groups?: string[]; + viewComponent?: typeof BaseControlComponent; + editComponent?: typeof BaseControlComponent; } export interface CustomTag { - label: TagTypeLabels; - colour: TagTypes; + label: TagTypeLabels; + colour: TagTypes; } export interface FormNodeValidator { - name: ValidatorNames; - args?: unknown; + name: ValidatorNames; + args?: unknown; } export interface FormNodeCombinationOptions { - leftComponentName: string; - rightComponentName: string; - separator: string; + leftComponentName: string; + rightComponentName: string; + separator: string; } export interface SubHeadingLink { - label: string; - url: string; - queryParams?: Params; + label: string; + url: string; + queryParams?: Params; } export interface CustomControl extends FormControl { - meta: FormNode; + meta: FormNode; } export interface SearchParams { - systemNumber?: string; - vin?: string; - reason?: string; - axleNumber?: number; + systemNumber?: string; + vin?: string; + reason?: string; + axleNumber?: number; } export class CustomFormControl extends FormControl implements CustomControl { - meta: FormNode; - - constructor( - meta: FormNode, - formState?: unknown, - validatorOrOpts?: ValidatorFn | ValidatorFn[] | FormControlOptions | null, - asyncValidator?: AsyncValidatorOptions, - ) { - super(formState, validatorOrOpts, asyncValidator); - this.meta = meta; - } + meta: FormNode; + + constructor( + meta: FormNode, + formState?: unknown, + validatorOrOpts?: ValidatorFn | ValidatorFn[] | FormControlOptions | null, + asyncValidator?: AsyncValidatorOptions + ) { + super(formState, validatorOrOpts, asyncValidator); + this.meta = meta; + } } interface BaseForm { - /** - * function that returns the json object value of the form after removing all the disabled controls - * and properties where meta.type is not 'control', 'group' or 'array - * - * @returns form json value - */ - getCleanValue: (form: CustomFormGroup | CustomFormArray) => { [key: string]: unknown } | Array<[]>; - - cleanValueChanges: Observable; + /** + * function that returns the json object value of the form after removing all the disabled controls + * and properties where meta.type is not 'control', 'group' or 'array + * + * @returns form json value + */ + getCleanValue: (form: CustomFormGroup | CustomFormArray) => { [key: string]: unknown } | Array<[]>; + + cleanValueChanges: Observable; } export interface CustomGroup extends FormGroup { - meta: FormNode; + meta: FormNode; } export class CustomFormGroup extends FormGroup implements CustomGroup, BaseForm { - meta: FormNode; - - constructor( - meta: FormNode, - controls: { - [key: string]: AbstractControl; - }, - validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, - asyncValidator?: AsyncValidatorOptions, - ) { - super(controls, validatorOrOpts, asyncValidator); - this.meta = meta; - } - - getCleanValue = cleanValue.bind(this); - - get cleanValueChanges() { - return this.valueChanges.pipe(map(() => this.getCleanValue(this))); - } + meta: FormNode; + + constructor( + meta: FormNode, + controls: { + [key: string]: AbstractControl; + }, + validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, + asyncValidator?: AsyncValidatorOptions + ) { + super(controls, validatorOrOpts, asyncValidator); + this.meta = meta; + } + + getCleanValue = cleanValue.bind(this); + + get cleanValueChanges() { + return this.valueChanges.pipe(map(() => this.getCleanValue(this))); + } } export interface CustomArray extends FormArray { - meta: FormNode; + meta: FormNode; } export class CustomFormArray extends FormArray implements CustomArray, BaseForm { - meta: FormNode; - private dynamicFormService: DynamicFormService; - - constructor( - meta: FormNode, - controls: AbstractControl[], - store: Store, - validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, - asyncValidator?: AsyncValidatorOptions, - ) { - super(controls, validatorOrOpts, asyncValidator); - this.meta = meta; - this.dynamicFormService = new DynamicFormService(store); - } - - getCleanValue = cleanValue.bind(this); - - get cleanValueChanges() { - return this.valueChanges.pipe(map(() => this.getCleanValue(this))); - } - - addControl(data?: unknown): void { - if (this.meta?.children) { - super.push(this.dynamicFormService.createForm(this.meta.children[0], data)); - } - } - - override patchValue( - value: unknown[] | undefined | null, - options?: { - onlySelf?: boolean; - emitEvent?: boolean; - }, - ): void { - if (value) { - if (value.length !== this.controls.length && this.meta.children && this.meta.children[0].type === 'group') { - if (value.length > this.controls.length) { - super.push(this.dynamicFormService.createForm(this.meta.children[0], value)); - } else { - this.controls.pop(); - } - } - super.patchValue(value, options); - } - } + meta: FormNode; + private dynamicFormService: DynamicFormService; + + constructor( + meta: FormNode, + controls: AbstractControl[], + store: Store, + validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, + asyncValidator?: AsyncValidatorOptions + ) { + super(controls, validatorOrOpts, asyncValidator); + this.meta = meta; + this.dynamicFormService = new DynamicFormService(store); + } + + getCleanValue = cleanValue.bind(this); + + get cleanValueChanges() { + return this.valueChanges.pipe(map(() => this.getCleanValue(this))); + } + + addControl(data?: unknown): void { + if (this.meta?.children) { + super.push(this.dynamicFormService.createForm(this.meta.children[0], data)); + } + } + + override patchValue( + value: unknown[] | undefined | null, + options?: { + onlySelf?: boolean; + emitEvent?: boolean; + } + ): void { + if (value) { + if (value.length !== this.controls.length && this.meta.children && this.meta.children[0].type === 'group') { + if (value.length > this.controls.length) { + super.push(this.dynamicFormService.createForm(this.meta.children[0], value)); + } else { + this.controls.pop(); + } + } + super.patchValue(value, options); + } + } } // TODO: clean this // eslint-disable-next-line @typescript-eslint/no-explicit-any const cleanValue = (form: CustomFormGroup | CustomFormArray): Record | Array<[]> => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const localCleanValue = form instanceof CustomFormArray ? [] : ({} as Record); - Object.keys(form.controls).forEach((key) => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any, security/detect-object-injection - const control = (form.controls as any)[key]; - if (control instanceof CustomFormGroup && control.meta.type === FormNodeTypes.GROUP) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any, security/detect-object-injection - (localCleanValue as any)[key] = objectOrNull(control.getCleanValue(control)); - } else if (control instanceof CustomFormArray) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any, security/detect-object-injection - (localCleanValue as any)[key] = control.getCleanValue(control); - } else if (control instanceof CustomFormControl && control.meta.type === FormNodeTypes.CONTROL) { - if (control.meta.required && control.meta.hide) { - pushOrAssignAt(control.meta.value || null, localCleanValue, key); - } else if (!control.meta.hide) { - pushOrAssignAt(control.value, localCleanValue, key); - } - } - }); - - return localCleanValue; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const localCleanValue = form instanceof CustomFormArray ? [] : ({} as Record); + Object.keys(form.controls).forEach((key) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any, security/detect-object-injection + const control = (form.controls as any)[key]; + if (control instanceof CustomFormGroup && control.meta.type === FormNodeTypes.GROUP) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any, security/detect-object-injection + (localCleanValue as any)[key] = objectOrNull(control.getCleanValue(control)); + } else if (control instanceof CustomFormArray) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any, security/detect-object-injection + (localCleanValue as any)[key] = control.getCleanValue(control); + } else if (control instanceof CustomFormControl && control.meta.type === FormNodeTypes.CONTROL) { + if (control.meta.required && control.meta.hide) { + pushOrAssignAt(control.meta.value || null, localCleanValue, key); + } else if (!control.meta.hide) { + pushOrAssignAt(control.value, localCleanValue, key); + } + } + }); + + return localCleanValue; }; function objectOrNull(obj: Object) { - return Object.values(obj).some((value) => undefined !== value) ? obj : null; + return Object.values(obj).some((value) => undefined !== value) ? obj : null; } // eslint-disable-next-line @typescript-eslint/no-explicit-any function pushOrAssignAt(value: any, localCleanValue: Array<[]> | Record, key: string) { - if (Array.isArray(localCleanValue)) { - localCleanValue.push(value); - } else { - localCleanValue[`${key}`] = value; - } + if (Array.isArray(localCleanValue)) { + localCleanValue.push(value); + } else { + localCleanValue[`${key}`] = value; + } } diff --git a/src/app/forms/services/multi-options.service.ts b/src/app/forms/services/multi-options.service.ts index 669ea9f57a..d0393b46ba 100644 --- a/src/app/forms/services/multi-options.service.ts +++ b/src/app/forms/services/multi-options.service.ts @@ -1,53 +1,53 @@ import { Injectable } from '@angular/core'; import { MultiOptions } from '@forms/models/options.model'; import { ReferenceDataResourceType } from '@models/reference-data.model'; -import { select, Store } from '@ngrx/store'; +import { Store, select } from '@ngrx/store'; import { ReferenceDataService } from '@services/reference-data/reference-data.service'; import { TestStationsService } from '@services/test-stations/test-stations.service'; import { fetchReasonsForAbandoning } from '@store/reference-data'; // eslint-disable-next-line import/no-cycle import { testResultInEdit } from '@store/test-records'; -import { fetchTestStations, TestStationsState } from '@store/test-stations'; +import { TestStationsState, fetchTestStations } from '@store/test-stations'; import { Observable, switchMap } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class MultiOptionsService { - constructor( - private referenceDataService: ReferenceDataService, - private store: Store, - private testStationsService: TestStationsService, - ) {} + constructor( + private referenceDataService: ReferenceDataService, + private store: Store, + private testStationsService: TestStationsService + ) {} - getOptions(referenceData: ReferenceDataResourceType | SpecialRefData): Observable { - switch (referenceData) { - case SpecialRefData.TEST_STATION_P_NUMBER: - return this.testStationsService.getTestStationsOptions(); - case SpecialRefData.ReasonsForAbandoning: - return this.store.pipe( - select(testResultInEdit), - switchMap((testResult) => this.referenceDataService.getReasonsForAbandoning(testResult?.vehicleType)), - ); - default: - return this.referenceDataService.getReferenceDataOptions(referenceData); - } - } + getOptions(referenceData: ReferenceDataResourceType | SpecialRefData): Observable { + switch (referenceData) { + case SpecialRefData.TEST_STATION_P_NUMBER: + return this.testStationsService.getTestStationsOptions(); + case SpecialRefData.ReasonsForAbandoning: + return this.store.pipe( + select(testResultInEdit), + switchMap((testResult) => this.referenceDataService.getReasonsForAbandoning(testResult?.vehicleType)) + ); + default: + return this.referenceDataService.getReferenceDataOptions(referenceData); + } + } - loadOptions(referenceData: ReferenceDataResourceType | SpecialRefData): void { - switch (referenceData) { - case SpecialRefData.TEST_STATION_P_NUMBER: - this.store.dispatch(fetchTestStations()); - break; - case SpecialRefData.ReasonsForAbandoning: - this.store.dispatch(fetchReasonsForAbandoning()); - break; - default: - this.referenceDataService.loadReferenceData(referenceData); - break; - } - } + loadOptions(referenceData: ReferenceDataResourceType | SpecialRefData): void { + switch (referenceData) { + case SpecialRefData.TEST_STATION_P_NUMBER: + this.store.dispatch(fetchTestStations()); + break; + case SpecialRefData.ReasonsForAbandoning: + this.store.dispatch(fetchReasonsForAbandoning()); + break; + default: + this.referenceDataService.loadReferenceData(referenceData); + break; + } + } } export enum SpecialRefData { - TEST_STATION_P_NUMBER = 'testStationPNumber', - ReasonsForAbandoning = 'REASONS_FOR_ABANDONING', + TEST_STATION_P_NUMBER = 'testStationPNumber', + ReasonsForAbandoning = 'REASONS_FOR_ABANDONING', } diff --git a/src/app/forms/templates/car/car-tech-record.template.ts b/src/app/forms/templates/car/car-tech-record.template.ts index f3add8a924..fa57a0c0cf 100644 --- a/src/app/forms/templates/car/car-tech-record.template.ts +++ b/src/app/forms/templates/car/car-tech-record.template.ts @@ -2,96 +2,100 @@ import { EUVehicleCategory } from '@dvsa/cvs-type-definitions/types/v3/tech-reco import { VehicleConfiguration } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleConfigurationLightVehicle.enum.js'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, - TagTypeLabels, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, + TagTypeLabels, } from '@forms/services/dynamic-form.types'; import { getOptionsFromEnum } from '@forms/utils/enum-map'; import { VehicleSubclass } from '@models/vehicle-tech-record.model'; import { TagType } from '@shared/components/tag/tag.component'; export const CarTechRecord: FormNode = { - name: 'techRecordSummary', - type: FormNodeTypes.GROUP, - label: 'Vehicle Summary', - children: [ - { - name: 'techRecord_vehicleType', - label: 'Vehicle type', - value: '', - width: FormNodeWidth.XS, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.VEHICLETYPE, - disabled: true, - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_statusCode', - label: 'Record status', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_regnDate', - label: 'Date of first registration', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - isoDate: false, - }, - { - name: 'techRecord_manufactureYear', - label: 'Year of manufacture', - value: null, - width: FormNodeWidth.XS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [ - { name: ValidatorNames.Max, args: 9999 }, - { name: ValidatorNames.Min, args: 1000 }, - { name: ValidatorNames.PastYear }, - ], - }, - { - name: 'techRecord_noOfAxles', - label: 'Number of axles', - value: 2, - width: FormNodeWidth.XXS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [{ name: ValidatorNames.Max, args: 99 }], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_vehicleSubclass', - label: 'Vehicle Subclass', - width: FormNodeWidth.XXS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CHECKBOXGROUP, - options: getOptionsFromEnum(VehicleSubclass), - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_vehicleConfiguration', - label: 'Vehicle configuration', - value: VehicleConfiguration.OTHER, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - options: getOptionsFromEnum(VehicleConfiguration), - validators: [{ name: ValidatorNames.Required }], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_euVehicleCategory', - label: 'EU vehicle category', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - options: getOptionsFromEnum(EUVehicleCategory), - width: FormNodeWidth.S, - }, - ], + name: 'techRecordSummary', + type: FormNodeTypes.GROUP, + label: 'Vehicle Summary', + children: [ + { + name: 'techRecord_vehicleType', + label: 'Vehicle type', + value: '', + width: FormNodeWidth.XS, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.VEHICLETYPE, + disabled: true, + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_statusCode', + label: 'Record status', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_regnDate', + label: 'Date of first registration', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + isoDate: false, + }, + { + name: 'techRecord_manufactureYear', + label: 'Year of manufacture', + value: null, + width: FormNodeWidth.XS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [ + { name: ValidatorNames.Max, args: 9999 }, + { name: ValidatorNames.Min, args: 1000 }, + { name: ValidatorNames.PastYear }, + ], + }, + { + name: 'techRecord_noOfAxles', + label: 'Number of axles', + value: 2, + width: FormNodeWidth.XXS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [{ name: ValidatorNames.Max, args: 99 }], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_vehicleSubclass', + label: 'Vehicle Subclass', + width: FormNodeWidth.XXS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CHECKBOXGROUP, + options: getOptionsFromEnum(VehicleSubclass), + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_vehicleConfiguration', + label: 'Vehicle configuration', + value: VehicleConfiguration.OTHER, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: getOptionsFromEnum(VehicleConfiguration), + validators: [{ name: ValidatorNames.Required }], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_euVehicleCategory', + label: 'EU vehicle category', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: getOptionsFromEnum(EUVehicleCategory), + width: FormNodeWidth.S, + }, + ], }; diff --git a/src/app/forms/templates/general/adr-certificate.template.ts b/src/app/forms/templates/general/adr-certificate.template.ts index 1a6b8ec067..97842c5a00 100644 --- a/src/app/forms/templates/general/adr-certificate.template.ts +++ b/src/app/forms/templates/general/adr-certificate.template.ts @@ -1,18 +1,16 @@ +import { AdrCertificateHistoryComponent } from '@forms/custom-sections/adr-certificate-history/adr-certificate-history.component'; import { FormNode, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; -import { - AdrCertificateHistoryComponent, -} from '@forms/custom-sections/adr-certificate-history/adr-certificate-history.component'; export const AdrCertificateTemplate: FormNode = { - name: 'adrCertificateSection', - type: FormNodeTypes.SECTION, - label: 'ADR Certificates', - children: [ - { - name: 'techRecord_adrDetails_certificates', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.CUSTOM, - viewComponent: AdrCertificateHistoryComponent, - }, - ], + name: 'adrCertificateSection', + type: FormNodeTypes.SECTION, + label: 'ADR Certificates', + children: [ + { + name: 'techRecord_adrDetails_certificates', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.CUSTOM, + viewComponent: AdrCertificateHistoryComponent, + }, + ], }; diff --git a/src/app/forms/templates/general/adr-summary.template.ts b/src/app/forms/templates/general/adr-summary.template.ts index 832e83a152..3f8ea2bc46 100644 --- a/src/app/forms/templates/general/adr-summary.template.ts +++ b/src/app/forms/templates/general/adr-summary.template.ts @@ -4,791 +4,814 @@ import { ADRCompatibilityGroupJ } from '@dvsa/cvs-type-definitions/types/v3/tech import { ADRDangerousGood } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrDangerousGood.enum.js'; import { ADRTankDetailsTankStatementSelect } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrTankDetailsTankStatementSelect.enum.js'; import { ADRTankStatementSubstancePermitted } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrTankStatementSubstancePermitted.js'; -import { - AdrExaminerNotesHistoryEditComponent, -} from '@forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit'; -import { - AdrExaminerNotesHistoryViewComponent, -} from '@forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component'; -import { - AdrNewCertificateRequiredViewComponent, -} from '@forms/custom-sections/adr-new-certificate-required-view/adr-new-certificate-required-view.component'; -import { - AdrTankDetailsInitialInspectionViewComponent, -} from '@forms/custom-sections/adr-tank-details-initial-inspection-view/adr-tank-details-initial-inspection-view.component'; +import { AdrExaminerNotesHistoryEditComponent } from '@forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit'; +import { AdrExaminerNotesHistoryViewComponent } from '@forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component'; +import { AdrNewCertificateRequiredViewComponent } from '@forms/custom-sections/adr-new-certificate-required-view/adr-new-certificate-required-view.component'; +import { AdrTankDetailsInitialInspectionViewComponent } from '@forms/custom-sections/adr-tank-details-initial-inspection-view/adr-tank-details-initial-inspection-view.component'; import { AdrTankDetailsM145ViewComponent } from '@forms/custom-sections/adr-tank-details-m145-view/adr-tank-details-m145-view.component'; -import { - AdrTankDetailsSubsequentInspectionsEditComponent, -} from '@forms/custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component'; -import { - AdrTankDetailsSubsequentInspectionsViewComponent, -} from '@forms/custom-sections/adr-tank-details-subsequent-inspections-view/adr-tank-details-subsequent-inspections-view.component'; -import { - AdrTankStatementUnNumberEditComponent, -} from '@forms/custom-sections/adr-tank-statement-un-number-edit/adr-tank-statement-un-number-edit.component'; -import { - AdrTankStatementUnNumberViewComponent, -} from '@forms/custom-sections/adr-tank-statement-un-number-view/adr-tank-statement-un-number-view.component'; +import { AdrTankDetailsSubsequentInspectionsEditComponent } from '@forms/custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component'; +import { AdrTankDetailsSubsequentInspectionsViewComponent } from '@forms/custom-sections/adr-tank-details-subsequent-inspections-view/adr-tank-details-subsequent-inspections-view.component'; +import { AdrTankStatementUnNumberEditComponent } from '@forms/custom-sections/adr-tank-statement-un-number-edit/adr-tank-statement-un-number-edit.component'; +import { AdrTankStatementUnNumberViewComponent } from '@forms/custom-sections/adr-tank-statement-un-number-view/adr-tank-statement-un-number-view.component'; import { ValidatorNames } from '@forms/models/validators.enum'; import { getOptionsFromEnum } from '@forms/utils/enum-map'; import { TC2Types } from '@models/adr.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '../../services/dynamic-form.types'; export const AdrSummaryTemplate: FormNode = { - name: 'adrSection', - type: FormNodeTypes.SECTION, - label: 'ADR', - children: [ - { - name: 'techRecord_adrDetails_dangerousGoods', - label: 'Able to carry dangerous goods', - width: FormNodeWidth.XS, - value: false, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [ - { name: ValidatorNames.ShowGroupsWhenEqualTo, args: { values: [true], groups: ['dangerous_goods'] } }, - { name: ValidatorNames.HideGroupsWhenEqualTo, args: { values: [false], groups: ['dangerous_goods'] } }, - { name: ValidatorNames.AddWarningForAdrField, args: 'By selecting this field it will delete all previous ADR field inputs' }, - ], - }, - { - name: 'applicationDetailsSectionTitle', - type: FormNodeTypes.TITLE, - label: 'Applicant Details', - groups: ['applicant_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_applicantDetails_name', - label: 'Name', - value: null, - width: FormNodeWidth.XXL, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 150 }], - groups: ['applicant_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_applicantDetails_street', - label: 'Street', - value: null, - width: FormNodeWidth.XXL, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 150 }], - groups: ['applicant_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_applicantDetails_town', - label: 'Town', - value: null, - width: FormNodeWidth.XXL, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 100 }], - groups: ['applicant_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_applicantDetails_city', - label: 'City', - value: null, - width: FormNodeWidth.XL, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 100 }], - groups: ['applicant_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_applicantDetails_postcode', - label: 'Postcode', - value: null, - width: FormNodeWidth.L, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 25 }], - groups: ['applicant_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'adrDetailsSectionTitle', - type: FormNodeTypes.TITLE, - label: 'ADR Details', - groups: ['adr_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_vehicleDetails_type', - label: 'ADR body type', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - editType: FormNodeEditTypes.SELECT, - groups: ['adr_details', 'dangerous_goods'], - hide: true, - options: getOptionsFromEnum(ADRBodyType), - validators: [ - { name: ValidatorNames.RequiredIfEquals, args: { sibling: 'techRecord_adrDetails_dangerousGoods', value: [true] } }, - { - name: ValidatorNames.ShowGroupsWhenIncludes, - args: { - values: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - groups: ['tank_details'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenExcludes, - args: { - values: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - groups: ['tank_details', 'tank_details_hide'], - }, - }, - { - name: ValidatorNames.ShowGroupsWhenIncludes, - args: { - values: Object.values(ADRBodyType).filter((value) => value.includes('battery')) as string[], - groups: ['battery_list'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenExcludes, - args: { - values: Object.values(ADRBodyType).filter((value) => value.includes('battery')) as string[], - groups: ['battery_list'], - }, - }, - ], - }, - { - name: 'techRecord_adrDetails_vehicleDetails_usedOnInternationalJourneys', - label: 'Vehicle used on international journeys', - type: FormNodeTypes.CONTROL, - options: [ - { value: 'yes', label: 'Yes' }, - { value: 'no', label: 'No' }, - { value: 'n/a', label: 'Not applicable' }, - ], - hide: true, - groups: ['adr_details', 'dangerous_goods'], - }, - { - name: 'techRecord_adrDetails_vehicleDetails_approvalDate', - label: 'Date processed', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.DATE, - viewType: FormNodeViewTypes.DATE, - groups: ['adr_details', 'dangerous_goods'], - hide: true, - isoDate: false, - validators: [ - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.RequiredIfEquals, args: { sibling: 'techRecord_adrDetails_dangerousGoods', value: [true] } }, - ], - }, - { - name: 'techRecord_adrDetails_permittedDangerousGoods', - label: 'Permitted dangerous goods', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CHECKBOXGROUP, - groups: ['adr_details', 'dangerous_goods'], - hide: true, - options: getOptionsFromEnum(ADRDangerousGood), - validators: [ - { - name: ValidatorNames.ShowGroupsWhenIncludes, - args: { - values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], - groups: ['compatibility_group_j'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenExcludes, - args: { - values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], - groups: ['compatibility_group_j'], - }, - }, - { name: ValidatorNames.RequiredIfEquals, args: { sibling: 'techRecord_adrDetails_dangerousGoods', value: [true] } }, - ], - }, - { - name: 'techRecord_adrDetails_compatibilityGroupJ', - label: 'Compatibility group J', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - groups: ['compatibility_group_j', 'adr_details', 'dangerous_goods'], - hide: true, - options: [ - { value: ADRCompatibilityGroupJ.I, label: 'Yes' }, - { value: ADRCompatibilityGroupJ.E, label: 'No' }, - ], - validators: [ - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_permittedDangerousGoods', - value: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], - }, - }, - ], - }, - { - name: 'techRecord_adrDetails_additionalNotes_number', - label: 'Guidance notes', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CHECKBOXGROUP, - groups: ['adr_details', 'dangerous_goods'], - hide: true, - width: FormNodeWidth.XS, - value: [], - options: getOptionsFromEnum(ADRAdditionalNotesNumber), - validators: [], - }, - { - name: 'techRecord_adrDetails_adrTypeApprovalNo', - label: 'ADR type approval number', - value: '', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - groups: ['adr_details', 'dangerous_goods'], - hide: true, - validators: [{ name: ValidatorNames.MaxLength, args: 40 }], - }, - { - name: 'tankDetailsSectionTitle', - type: FormNodeTypes.TITLE, - label: 'Tank Details', - groups: ['tank_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankManufacturer', - label: 'Tank Make', - value: null, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XXL, - groups: ['tank_details', 'dangerous_goods'], - validators: [ - { name: ValidatorNames.MaxLength, args: 70 }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - }, - }, - ], - hide: true, - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_yearOfManufacture', - label: 'Tank Year of manufacture', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - width: FormNodeWidth.XS, - groups: ['tank_details', 'dangerous_goods'], - validators: [ - { name: ValidatorNames.Max, args: 9999 }, - { name: ValidatorNames.Min, args: 1000 }, - { name: ValidatorNames.PastYear }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - }, - }, - ], - hide: true, - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankManufacturerSerialNo', - label: 'Manufacturer serial number', - value: null, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - groups: ['tank_details', 'dangerous_goods'], - validators: [ - { name: ValidatorNames.MaxLength, args: 50 }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - }, - }, - ], - hide: true, - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankTypeAppNo', - label: 'Tank type approval number', - value: null, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - groups: ['tank_details', 'dangerous_goods'], - validators: [ - { name: ValidatorNames.MaxLength, args: 65 }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - }, - }, - ], - hide: true, - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankCode', - label: 'Code', - value: null, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - groups: ['tank_details', 'dangerous_goods'], - validators: [ - { name: ValidatorNames.MaxLength, args: 30 }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - }, - }, - ], - hide: true, - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_substancesPermitted', - label: 'Substances permitted', - width: FormNodeWidth.XS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: getOptionsFromEnum(ADRTankStatementSubstancePermitted), - groups: ['tank_details', 'dangerous_goods'], - hide: true, - validators: [ - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - }, - }, - { - name: ValidatorNames.ShowGroupsWhenEqualTo, - args: { - values: [ADRTankStatementSubstancePermitted.UNDER_UN_NUMBER], - groups: ['statement_select'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenEqualTo, - args: { - values: [ADRTankStatementSubstancePermitted.UNDER_TANK_CODE, null, undefined], - groups: ['statement_select', 'statement_select_hide'], - }, - }, - ], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_select', - label: 'Select', - width: FormNodeWidth.XS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - groups: ['statement_select', 'tank_details_hide', 'dangerous_goods'], - hide: true, - options: getOptionsFromEnum(ADRTankDetailsTankStatementSelect), - validators: [ - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - }, - }, - { - name: ValidatorNames.ShowGroupsWhenIncludes, - args: { - values: [ADRTankDetailsTankStatementSelect.STATEMENT], - groups: ['statement'], - }, - }, - { - name: ValidatorNames.ShowGroupsWhenIncludes, - args: { - values: [ADRTankDetailsTankStatementSelect.PRODUCT_LIST], - groups: ['productList'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenExcludes, - args: { - values: [ADRTankDetailsTankStatementSelect.STATEMENT], - groups: ['statement'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenExcludes, - args: { - values: [ADRTankDetailsTankStatementSelect.PRODUCT_LIST], - groups: ['productList'], - }, - }, - ], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_statement', - label: 'Reference number', - type: FormNodeTypes.CONTROL, - groups: ['statement', 'statement_select_hide', 'tank_details_hide', 'dangerous_goods'], - hide: true, - customErrorMessage: 'Reference number is required when selecting Statement', - validators: [ - { name: ValidatorNames.MaxLength, args: 1500 }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_tank_tankDetails_tankStatement_select', - value: [ADRTankDetailsTankStatementSelect.STATEMENT], - }, - }, - ], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo', - label: 'Reference number', - type: FormNodeTypes.CONTROL, - groups: ['productList', 'statement_select_hide', 'tank_details_hide', 'dangerous_goods'], - hide: true, - customErrorMessage: 'Reference number or UN number is required when selecting Product List', - validators: [ - { name: ValidatorNames.MaxLength, args: 1500 }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo', - value: [[], [null], [''], null, undefined], - }, - }, - ], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo', - label: 'UN number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CUSTOM, - viewType: FormNodeViewTypes.CUSTOM, - editComponent: AdrTankStatementUnNumberEditComponent, - viewComponent: AdrTankStatementUnNumberViewComponent, - groups: ['productList', 'statement_select_hide', 'tank_details_hide', 'dangerous_goods'], - hide: true, - customErrorMessage: 'Reference number or UN number is required when selecting Product List', - validators: [ - { - name: ValidatorNames.RequiredIfEquals, - args: { sibling: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo', value: [null, undefined, ''] }, - }, - ], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productList', - label: 'Additional Details', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXTAREA, - groups: ['productList', 'statement_select_hide', 'tank_details_hide', 'dangerous_goods'], - hide: true, - validators: [{ name: ValidatorNames.MaxLength, args: 1500 }], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_specialProvisions', - label: 'Special Provisions', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXTAREA, - hide: true, - validators: [{ name: ValidatorNames.MaxLength, args: 1024 }], - groups: ['dangerous_goods', 'tank_details'], - }, - { - name: 'tankInspectionsSectionTitle', - type: FormNodeTypes.TITLE, - label: 'Tank Inspections', - groups: ['tank_details', 'dangerous_goods'], - hide: true, - validators: [ - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - }, - }, - ], - }, - { - name: 'tankInspectionsInitialView', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.CUSTOM, - viewComponent: AdrTankDetailsInitialInspectionViewComponent, - groups: ['tank_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tc2Details_tc2Type', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - label: 'TC2: Inspection type', - value: TC2Types.INITIAL, - hide: true, - groups: ['tank_details', 'dangerous_goods'], - validators: [], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tc2Details_tc2IntermediateApprovalNo', - label: 'TC2: Certificate Number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - hide: true, - groups: ['tank_details', 'dangerous_goods'], - validators: [{ name: ValidatorNames.MaxLength, args: 70 }], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tc2Details_tc2IntermediateExpiryDate', - label: 'TC2: Expiry Date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - isoDate: false, - hide: true, - groups: ['tank_details', 'dangerous_goods'], - validators: [], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tc3Details', - label: 'Subsequent Inspections', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.CUSTOM, - viewComponent: AdrTankDetailsSubsequentInspectionsViewComponent, - editType: FormNodeEditTypes.CUSTOM, - editComponent: AdrTankDetailsSubsequentInspectionsEditComponent, - hide: true, - groups: ['tank_details', 'dangerous_goods'], - validators: [ - { - name: ValidatorNames.Tc3TestValidator, - args: { inspectionNumber: 0 }, - }, - ], - }, - { - name: 'techRecord_adrDetails_memosApply', - label: 'Memo 7/9 (3 month extension) applied', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CHECKBOXGROUP, - groups: ['tank_details', 'dangerous_goods'], - hide: true, - options: [{ value: '07/09 3mth leak ext ', label: 'Yes' }], - validators: [], - }, - { - name: 'techRecord_adrDetails_m145Statement', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.CUSTOM, - viewComponent: AdrTankDetailsM145ViewComponent, - editType: FormNodeEditTypes.CHECKBOX, - groups: ['tank_details', 'dangerous_goods'], - hide: true, - validators: [], - }, - { - name: 'techRecord_adrDetails_listStatementApplicable', - label: 'Battery List Applicable', - width: FormNodeWidth.XS, - value: false, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [ - { name: ValidatorNames.ShowGroupsWhenEqualTo, args: { values: [true], groups: ['battery_list_applicable'] } }, - { name: ValidatorNames.HideGroupsWhenEqualTo, args: { values: [false], groups: ['battery_list_applicable'] } }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery')) as string[], - }, - }, - ], - hide: true, - groups: ['dangerous_goods', 'battery_list'], - }, - { - name: 'techRecord_adrDetails_batteryListNumber', - label: 'Reference number', - value: null, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - groups: ['battery_list', 'battery_list_applicable', 'dangerous_goods'], - validators: [ - { name: ValidatorNames.MaxLength, args: 8 }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_listStatementApplicable', - value: [true], - }, - }, - ], - hide: true, - }, - { - name: 'DeclarationsSectionTitle', - label: 'Declarations seen', - type: FormNodeTypes.TITLE, - groups: ['declarations_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_brakeDeclarationsSeen', - label: 'Manufacturer brake declaration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CHECKBOX, - groups: ['declarations_details', 'dangerous_goods'], - value: false, - hide: true, - validators: [ - { - name: ValidatorNames.ShowGroupsWhenEqualTo, - args: { - values: [true], - groups: ['issuer_section'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenEqualTo, - args: { - values: [false], - groups: ['issuer_section', 'weight_section'], - }, - }, - ], - }, - { - name: 'techRecord_adrDetails_brakeDeclarationIssuer', - label: 'Issuer', - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['issuer_section', 'dangerous_goods'], - editType: FormNodeEditTypes.TEXTAREA, - validators: [{ name: ValidatorNames.MaxLength, args: 500 }], - }, - { - name: 'techRecord_adrDetails_brakeEndurance', - label: 'Brake endurance', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CHECKBOX, + name: 'adrSection', + type: FormNodeTypes.SECTION, + label: 'ADR', + children: [ + { + name: 'techRecord_adrDetails_dangerousGoods', + label: 'Able to carry dangerous goods', + width: FormNodeWidth.XS, + value: false, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [ + { name: ValidatorNames.ShowGroupsWhenEqualTo, args: { values: [true], groups: ['dangerous_goods'] } }, + { name: ValidatorNames.HideGroupsWhenEqualTo, args: { values: [false], groups: ['dangerous_goods'] } }, + { + name: ValidatorNames.AddWarningForAdrField, + args: 'By selecting this field it will delete all previous ADR field inputs', + }, + ], + }, + { + name: 'applicationDetailsSectionTitle', + type: FormNodeTypes.TITLE, + label: 'Applicant Details', + groups: ['applicant_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_applicantDetails_name', + label: 'Name', + value: null, + width: FormNodeWidth.XXL, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 150 }], + groups: ['applicant_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_applicantDetails_street', + label: 'Street', + value: null, + width: FormNodeWidth.XXL, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 150 }], + groups: ['applicant_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_applicantDetails_town', + label: 'Town', + value: null, + width: FormNodeWidth.XXL, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 100 }], + groups: ['applicant_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_applicantDetails_city', + label: 'City', + value: null, + width: FormNodeWidth.XL, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 100 }], + groups: ['applicant_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_applicantDetails_postcode', + label: 'Postcode', + value: null, + width: FormNodeWidth.L, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 25 }], + groups: ['applicant_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'adrDetailsSectionTitle', + type: FormNodeTypes.TITLE, + label: 'ADR Details', + groups: ['adr_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_vehicleDetails_type', + label: 'ADR body type', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + editType: FormNodeEditTypes.SELECT, + groups: ['adr_details', 'dangerous_goods'], + hide: true, + options: getOptionsFromEnum(ADRBodyType), + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'techRecord_adrDetails_dangerousGoods', value: [true] }, + }, + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + groups: ['tank_details'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + groups: ['tank_details', 'tank_details_hide'], + }, + }, + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: Object.values(ADRBodyType).filter((value) => value.includes('battery')) as string[], + groups: ['battery_list'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: Object.values(ADRBodyType).filter((value) => value.includes('battery')) as string[], + groups: ['battery_list'], + }, + }, + ], + }, + { + name: 'techRecord_adrDetails_vehicleDetails_usedOnInternationalJourneys', + label: 'Vehicle used on international journeys', + type: FormNodeTypes.CONTROL, + options: [ + { value: 'yes', label: 'Yes' }, + { value: 'no', label: 'No' }, + { value: 'n/a', label: 'Not applicable' }, + ], + hide: true, + groups: ['adr_details', 'dangerous_goods'], + }, + { + name: 'techRecord_adrDetails_vehicleDetails_approvalDate', + label: 'Date processed', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.DATE, + viewType: FormNodeViewTypes.DATE, + groups: ['adr_details', 'dangerous_goods'], + hide: true, + isoDate: false, + validators: [ + { name: ValidatorNames.PastDate }, + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'techRecord_adrDetails_dangerousGoods', value: [true] }, + }, + ], + }, + { + name: 'techRecord_adrDetails_permittedDangerousGoods', + label: 'Permitted dangerous goods', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CHECKBOXGROUP, + groups: ['adr_details', 'dangerous_goods'], + hide: true, + options: getOptionsFromEnum(ADRDangerousGood), + validators: [ + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], + groups: ['compatibility_group_j'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], + groups: ['compatibility_group_j'], + }, + }, + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'techRecord_adrDetails_dangerousGoods', value: [true] }, + }, + ], + }, + { + name: 'techRecord_adrDetails_compatibilityGroupJ', + label: 'Compatibility group J', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + groups: ['compatibility_group_j', 'adr_details', 'dangerous_goods'], + hide: true, + options: [ + { value: ADRCompatibilityGroupJ.I, label: 'Yes' }, + { value: ADRCompatibilityGroupJ.E, label: 'No' }, + ], + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_permittedDangerousGoods', + value: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], + }, + }, + ], + }, + { + name: 'techRecord_adrDetails_additionalNotes_number', + label: 'Guidance notes', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CHECKBOXGROUP, + groups: ['adr_details', 'dangerous_goods'], + hide: true, + width: FormNodeWidth.XS, + value: [], + options: getOptionsFromEnum(ADRAdditionalNotesNumber), + validators: [], + }, + { + name: 'techRecord_adrDetails_adrTypeApprovalNo', + label: 'ADR type approval number', + value: '', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + groups: ['adr_details', 'dangerous_goods'], + hide: true, + validators: [{ name: ValidatorNames.MaxLength, args: 40 }], + }, + { + name: 'tankDetailsSectionTitle', + type: FormNodeTypes.TITLE, + label: 'Tank Details', + groups: ['tank_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankManufacturer', + label: 'Tank Make', + value: null, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XXL, + groups: ['tank_details', 'dangerous_goods'], + validators: [ + { name: ValidatorNames.MaxLength, args: 70 }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + }, + }, + ], + hide: true, + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_yearOfManufacture', + label: 'Tank Year of manufacture', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + width: FormNodeWidth.XS, + groups: ['tank_details', 'dangerous_goods'], + validators: [ + { name: ValidatorNames.Max, args: 9999 }, + { name: ValidatorNames.Min, args: 1000 }, + { name: ValidatorNames.PastYear }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + }, + }, + ], + hide: true, + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankManufacturerSerialNo', + label: 'Manufacturer serial number', + value: null, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + groups: ['tank_details', 'dangerous_goods'], + validators: [ + { name: ValidatorNames.MaxLength, args: 50 }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + }, + }, + ], + hide: true, + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankTypeAppNo', + label: 'Tank type approval number', + value: null, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + groups: ['tank_details', 'dangerous_goods'], + validators: [ + { name: ValidatorNames.MaxLength, args: 65 }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + }, + }, + ], + hide: true, + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankCode', + label: 'Code', + value: null, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + groups: ['tank_details', 'dangerous_goods'], + validators: [ + { name: ValidatorNames.MaxLength, args: 30 }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + }, + }, + ], + hide: true, + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_substancesPermitted', + label: 'Substances permitted', + width: FormNodeWidth.XS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: getOptionsFromEnum(ADRTankStatementSubstancePermitted), + groups: ['tank_details', 'dangerous_goods'], + hide: true, + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + }, + }, + { + name: ValidatorNames.ShowGroupsWhenEqualTo, + args: { + values: [ADRTankStatementSubstancePermitted.UNDER_UN_NUMBER], + groups: ['statement_select'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenEqualTo, + args: { + values: [ADRTankStatementSubstancePermitted.UNDER_TANK_CODE, null, undefined], + groups: ['statement_select', 'statement_select_hide'], + }, + }, + ], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_select', + label: 'Select', + width: FormNodeWidth.XS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + groups: ['statement_select', 'tank_details_hide', 'dangerous_goods'], + hide: true, + options: getOptionsFromEnum(ADRTankDetailsTankStatementSelect), + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + }, + }, + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: [ADRTankDetailsTankStatementSelect.STATEMENT], + groups: ['statement'], + }, + }, + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: [ADRTankDetailsTankStatementSelect.PRODUCT_LIST], + groups: ['productList'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: [ADRTankDetailsTankStatementSelect.STATEMENT], + groups: ['statement'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: [ADRTankDetailsTankStatementSelect.PRODUCT_LIST], + groups: ['productList'], + }, + }, + ], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_statement', + label: 'Reference number', + type: FormNodeTypes.CONTROL, + groups: ['statement', 'statement_select_hide', 'tank_details_hide', 'dangerous_goods'], + hide: true, + customErrorMessage: 'Reference number is required when selecting Statement', + validators: [ + { name: ValidatorNames.MaxLength, args: 1500 }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_tank_tankDetails_tankStatement_select', + value: [ADRTankDetailsTankStatementSelect.STATEMENT], + }, + }, + ], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo', + label: 'Reference number', + type: FormNodeTypes.CONTROL, + groups: ['productList', 'statement_select_hide', 'tank_details_hide', 'dangerous_goods'], + hide: true, + customErrorMessage: 'Reference number or UN number is required when selecting Product List', + validators: [ + { name: ValidatorNames.MaxLength, args: 1500 }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo', + value: [[], [null], [''], null, undefined], + }, + }, + ], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo', + label: 'UN number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CUSTOM, + viewType: FormNodeViewTypes.CUSTOM, + editComponent: AdrTankStatementUnNumberEditComponent, + viewComponent: AdrTankStatementUnNumberViewComponent, + groups: ['productList', 'statement_select_hide', 'tank_details_hide', 'dangerous_goods'], + hide: true, + customErrorMessage: 'Reference number or UN number is required when selecting Product List', + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo', + value: [null, undefined, ''], + }, + }, + ], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productList', + label: 'Additional Details', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXTAREA, + groups: ['productList', 'statement_select_hide', 'tank_details_hide', 'dangerous_goods'], + hide: true, + validators: [{ name: ValidatorNames.MaxLength, args: 1500 }], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_specialProvisions', + label: 'Special Provisions', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXTAREA, + hide: true, + validators: [{ name: ValidatorNames.MaxLength, args: 1024 }], + groups: ['dangerous_goods', 'tank_details'], + }, + { + name: 'tankInspectionsSectionTitle', + type: FormNodeTypes.TITLE, + label: 'Tank Inspections', + groups: ['tank_details', 'dangerous_goods'], + hide: true, + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + }, + }, + ], + }, + { + name: 'tankInspectionsInitialView', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.CUSTOM, + viewComponent: AdrTankDetailsInitialInspectionViewComponent, + groups: ['tank_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tc2Details_tc2Type', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + label: 'TC2: Inspection type', + value: TC2Types.INITIAL, + hide: true, + groups: ['tank_details', 'dangerous_goods'], + validators: [], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tc2Details_tc2IntermediateApprovalNo', + label: 'TC2: Certificate Number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + hide: true, + groups: ['tank_details', 'dangerous_goods'], + validators: [{ name: ValidatorNames.MaxLength, args: 70 }], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tc2Details_tc2IntermediateExpiryDate', + label: 'TC2: Expiry Date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + isoDate: false, + hide: true, + groups: ['tank_details', 'dangerous_goods'], + validators: [], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tc3Details', + label: 'Subsequent Inspections', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.CUSTOM, + viewComponent: AdrTankDetailsSubsequentInspectionsViewComponent, + editType: FormNodeEditTypes.CUSTOM, + editComponent: AdrTankDetailsSubsequentInspectionsEditComponent, + hide: true, + groups: ['tank_details', 'dangerous_goods'], + validators: [ + { + name: ValidatorNames.Tc3TestValidator, + args: { inspectionNumber: 0 }, + }, + ], + }, + { + name: 'techRecord_adrDetails_memosApply', + label: 'Memo 7/9 (3 month extension) applied', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CHECKBOXGROUP, + groups: ['tank_details', 'dangerous_goods'], + hide: true, + options: [{ value: '07/09 3mth leak ext ', label: 'Yes' }], + validators: [], + }, + { + name: 'techRecord_adrDetails_m145Statement', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.CUSTOM, + viewComponent: AdrTankDetailsM145ViewComponent, + editType: FormNodeEditTypes.CHECKBOX, + groups: ['tank_details', 'dangerous_goods'], + hide: true, + validators: [], + }, + { + name: 'techRecord_adrDetails_listStatementApplicable', + label: 'Battery List Applicable', + width: FormNodeWidth.XS, + value: false, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [ + { name: ValidatorNames.ShowGroupsWhenEqualTo, args: { values: [true], groups: ['battery_list_applicable'] } }, + { name: ValidatorNames.HideGroupsWhenEqualTo, args: { values: [false], groups: ['battery_list_applicable'] } }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter((value) => value.includes('battery')) as string[], + }, + }, + ], + hide: true, + groups: ['dangerous_goods', 'battery_list'], + }, + { + name: 'techRecord_adrDetails_batteryListNumber', + label: 'Reference number', + value: null, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + groups: ['battery_list', 'battery_list_applicable', 'dangerous_goods'], + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_listStatementApplicable', + value: [true], + }, + }, + ], + hide: true, + }, + { + name: 'DeclarationsSectionTitle', + label: 'Declarations seen', + type: FormNodeTypes.TITLE, + groups: ['declarations_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_brakeDeclarationsSeen', + label: 'Manufacturer brake declaration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CHECKBOX, + groups: ['declarations_details', 'dangerous_goods'], + value: false, + hide: true, + validators: [ + { + name: ValidatorNames.ShowGroupsWhenEqualTo, + args: { + values: [true], + groups: ['issuer_section'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenEqualTo, + args: { + values: [false], + groups: ['issuer_section', 'weight_section'], + }, + }, + ], + }, + { + name: 'techRecord_adrDetails_brakeDeclarationIssuer', + label: 'Issuer', + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['issuer_section', 'dangerous_goods'], + editType: FormNodeEditTypes.TEXTAREA, + validators: [{ name: ValidatorNames.MaxLength, args: 500 }], + }, + { + name: 'techRecord_adrDetails_brakeEndurance', + label: 'Brake endurance', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CHECKBOX, - groups: ['issuer_section', 'dangerous_goods'], - hide: true, - validators: [ - { - name: ValidatorNames.ShowGroupsWhenEqualTo, - args: { - values: [true], - groups: ['weight_section'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenEqualTo, - args: { - values: [false, null, undefined], - groups: ['weight_section'], - }, - }, - ], - }, - { - name: 'techRecord_adrDetails_weight', - label: 'Weight (tonnes)', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - groups: ['weight_section', 'dangerous_goods'], - hide: true, - validators: [ - { name: ValidatorNames.Max, args: 999999999 }, - { - name: ValidatorNames.RequiredIfNotHidden, - }, - ], - }, - { - name: 'techRecord_adrDetails_declarationsSeen', - label: 'Owner/operator declaration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CHECKBOX, - groups: ['declarations_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'NewCertificateRequested', - label: 'New Certificate required', - type: FormNodeTypes.TITLE, - groups: ['dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_newCertificateRequested', - label: 'Yes', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CHECKBOX, - viewType: FormNodeViewTypes.CUSTOM, - viewComponent: AdrNewCertificateRequiredViewComponent, - value: false, - groups: ['dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_additionalExaminerNotes_note', - label: 'Additional Examiner Notes', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXTAREA, - groups: ['adr_details', 'dangerous_goods'], - hide: true, - validators: [{ name: ValidatorNames.MaxLength, args: 1024 }], - }, - { - name: 'techRecord_adrDetails_additionalExaminerNotes', - value: null, - label: 'Additional Examiner Notes History', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.CUSTOM, - viewComponent: AdrExaminerNotesHistoryViewComponent, - editType: FormNodeEditTypes.CUSTOM, - editComponent: AdrExaminerNotesHistoryEditComponent, - groups: ['adr_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_adrCertificateNotes', - label: 'ADR Certificate Notes', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXTAREA, - viewType: FormNodeViewTypes.STRING, - groups: ['adrDetails', 'dangerous_goods'], - hide: true, - validators: [{ name: ValidatorNames.MaxLength, args: 1500 }], - }, - ], + groups: ['issuer_section', 'dangerous_goods'], + hide: true, + validators: [ + { + name: ValidatorNames.ShowGroupsWhenEqualTo, + args: { + values: [true], + groups: ['weight_section'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenEqualTo, + args: { + values: [false, null, undefined], + groups: ['weight_section'], + }, + }, + ], + }, + { + name: 'techRecord_adrDetails_weight', + label: 'Weight (tonnes)', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + groups: ['weight_section', 'dangerous_goods'], + hide: true, + validators: [ + { name: ValidatorNames.Max, args: 999999999 }, + { + name: ValidatorNames.RequiredIfNotHidden, + }, + ], + }, + { + name: 'techRecord_adrDetails_declarationsSeen', + label: 'Owner/operator declaration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CHECKBOX, + groups: ['declarations_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'NewCertificateRequested', + label: 'New Certificate required', + type: FormNodeTypes.TITLE, + groups: ['dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_newCertificateRequested', + label: 'Yes', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CHECKBOX, + viewType: FormNodeViewTypes.CUSTOM, + viewComponent: AdrNewCertificateRequiredViewComponent, + value: false, + groups: ['dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_additionalExaminerNotes_note', + label: 'Additional Examiner Notes', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXTAREA, + groups: ['adr_details', 'dangerous_goods'], + hide: true, + validators: [{ name: ValidatorNames.MaxLength, args: 1024 }], + }, + { + name: 'techRecord_adrDetails_additionalExaminerNotes', + value: null, + label: 'Additional Examiner Notes History', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.CUSTOM, + viewComponent: AdrExaminerNotesHistoryViewComponent, + editType: FormNodeEditTypes.CUSTOM, + editComponent: AdrExaminerNotesHistoryEditComponent, + groups: ['adr_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_adrCertificateNotes', + label: 'ADR Certificate Notes', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXTAREA, + viewType: FormNodeViewTypes.STRING, + groups: ['adrDetails', 'dangerous_goods'], + hide: true, + validators: [{ name: ValidatorNames.MaxLength, args: 1500 }], + }, + ], }; diff --git a/src/app/forms/templates/general/adr.template.ts b/src/app/forms/templates/general/adr.template.ts index ecae0d5e90..79e51ea7da 100644 --- a/src/app/forms/templates/general/adr.template.ts +++ b/src/app/forms/templates/general/adr.template.ts @@ -1,830 +1,820 @@ -import { - ADRAdditionalNotesNumber, -} from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrAdditionalNotesNumber.enum.js'; +import { ADRAdditionalNotesNumber } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrAdditionalNotesNumber.enum.js'; import { ADRBodyType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrBodyType.enum.js'; -import { - ADRCompatibilityGroupJ, -} from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrCompatibilityGroupJ.enum.js'; +import { ADRCompatibilityGroupJ } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrCompatibilityGroupJ.enum.js'; import { ADRDangerousGood } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrDangerousGood.enum.js'; -import { - ADRTankDetailsTankStatementSelect, -} from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrTankDetailsTankStatementSelect.enum.js'; -import { - ADRTankStatementSubstancePermitted, -} from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrTankStatementSubstancePermitted.js'; -import { - AdrExaminerNotesHistoryEditComponent, -} from '@forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit'; -import { - AdrExaminerNotesHistoryViewComponent, -} from '@forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component'; -import { - AdrNewCertificateRequiredViewComponent, -} from '@forms/custom-sections/adr-new-certificate-required-view/adr-new-certificate-required-view.component'; -import { - AdrTankDetailsInitialInspectionViewComponent, -} from '@forms/custom-sections/adr-tank-details-initial-inspection-view/adr-tank-details-initial-inspection-view.component'; -import { - AdrTankDetailsM145ViewComponent, -} from '@forms/custom-sections/adr-tank-details-m145-view/adr-tank-details-m145-view.component'; -import { - AdrTankDetailsSubsequentInspectionsEditComponent, -} from '@forms/custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component'; -import { - AdrTankDetailsSubsequentInspectionsViewComponent, -} from '@forms/custom-sections/adr-tank-details-subsequent-inspections-view/adr-tank-details-subsequent-inspections-view.component'; -import { - AdrTankStatementUnNumberEditComponent, -} from '@forms/custom-sections/adr-tank-statement-un-number-edit/adr-tank-statement-un-number-edit.component'; -import { - AdrTankStatementUnNumberViewComponent, -} from '@forms/custom-sections/adr-tank-statement-un-number-view/adr-tank-statement-un-number-view.component'; +import { ADRTankDetailsTankStatementSelect } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrTankDetailsTankStatementSelect.enum.js'; +import { ADRTankStatementSubstancePermitted } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/adrTankStatementSubstancePermitted.js'; +import { AdrExaminerNotesHistoryEditComponent } from '@forms/custom-sections/adr-examiner-notes-history-edit/adr-examiner-notes-history.component-edit'; +import { AdrExaminerNotesHistoryViewComponent } from '@forms/custom-sections/adr-examiner-notes-history-view/adr-examiner-notes-history-view.component'; +import { AdrNewCertificateRequiredViewComponent } from '@forms/custom-sections/adr-new-certificate-required-view/adr-new-certificate-required-view.component'; +import { AdrTankDetailsInitialInspectionViewComponent } from '@forms/custom-sections/adr-tank-details-initial-inspection-view/adr-tank-details-initial-inspection-view.component'; +import { AdrTankDetailsM145ViewComponent } from '@forms/custom-sections/adr-tank-details-m145-view/adr-tank-details-m145-view.component'; +import { AdrTankDetailsSubsequentInspectionsEditComponent } from '@forms/custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component'; +import { AdrTankDetailsSubsequentInspectionsViewComponent } from '@forms/custom-sections/adr-tank-details-subsequent-inspections-view/adr-tank-details-subsequent-inspections-view.component'; +import { AdrTankStatementUnNumberEditComponent } from '@forms/custom-sections/adr-tank-statement-un-number-edit/adr-tank-statement-un-number-edit.component'; +import { AdrTankStatementUnNumberViewComponent } from '@forms/custom-sections/adr-tank-statement-un-number-view/adr-tank-statement-un-number-view.component'; import { ValidatorNames } from '@forms/models/validators.enum'; import { getOptionsFromEnum } from '@forms/utils/enum-map'; import { AdrValidators } from '@forms/validators/adr/adr.validators'; import { TC2Types } from '@models/adr.enum'; import { - FormNode, - FormNodeEditTypes, - FormNodeTypes, - FormNodeViewTypes, - FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '../../services/dynamic-form.types'; export const AdrTemplate: FormNode = { - name: 'adrSection', - type: FormNodeTypes.SECTION, - label: 'ADR', - children: [ - { - name: 'techRecord_adrDetails_dangerousGoods', - label: 'Able to carry dangerous goods', - width: FormNodeWidth.XS, - value: false, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [ - { name: ValidatorNames.ShowGroupsWhenEqualTo, args: { values: [true], groups: ['dangerous_goods'] } }, - { name: ValidatorNames.HideGroupsWhenEqualTo, args: { values: [false], groups: ['dangerous_goods', 'dangerous_goods_hide'] } }, - { name: ValidatorNames.AddWarningForAdrField, args: 'By selecting this field it will delete all previous ADR field inputs' }, - ], - }, - { - name: 'applicationDetailsSectionTitle', - type: FormNodeTypes.TITLE, - label: 'Applicant Details', - groups: ['applicant_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_applicantDetails_name', - label: 'Name', - value: null, - width: FormNodeWidth.XXL, - type: FormNodeTypes.CONTROL, - validators: [ - { name: ValidatorNames.MaxLength, args: 150 }, - ], - groups: ['applicant_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_applicantDetails_street', - label: 'Street', - value: null, - width: FormNodeWidth.XXL, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 150 }], - groups: ['applicant_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_applicantDetails_town', - label: 'Town', - value: null, - width: FormNodeWidth.XXL, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 100 }], - groups: ['applicant_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_applicantDetails_city', - label: 'City', - value: null, - width: FormNodeWidth.XL, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 100 }], - groups: ['applicant_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_applicantDetails_postcode', - label: 'Postcode', - value: null, - width: FormNodeWidth.L, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 25 }], - groups: ['applicant_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'adrDetailsSectionTitle', - type: FormNodeTypes.TITLE, - label: 'ADR Details', - groups: ['adr_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_vehicleDetails_type', - label: 'ADR body type', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - editType: FormNodeEditTypes.SELECT, - groups: ['adr_details', 'dangerous_goods'], - hide: true, - options: getOptionsFromEnum(ADRBodyType), - validators: [ - { name: ValidatorNames.RequiredIfEquals, args: { sibling: 'techRecord_adrDetails_dangerousGoods', value: [true] } }, - { - name: ValidatorNames.ShowGroupsWhenIncludes, - args: { - values: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - groups: ['tank_details'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenExcludes, - args: { - values: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - groups: ['tank_details', 'tank_details_hide'], - }, - }, - { - name: ValidatorNames.ShowGroupsWhenIncludes, - args: { - values: Object.values(ADRBodyType).filter((value) => value.includes('battery')) as string[], - groups: ['battery_list'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenExcludes, - args: { - values: Object.values(ADRBodyType).filter((value) => value.includes('battery')) as string[], - groups: ['battery_list', 'battery_list_hide'], - }, - }, - ], - }, - { - name: 'techRecord_adrDetails_vehicleDetails_usedOnInternationalJourneys', - label: 'Vehicle used on international journeys', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'yes', label: 'Yes' }, - { value: 'no', label: 'No' }, - { value: 'n/a', label: 'Not applicable' }, - ], - hide: true, - groups: ['adr_details', 'dangerous_goods'], - }, - { - name: 'techRecord_adrDetails_vehicleDetails_approvalDate', - label: 'Date processed', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.DATE, - viewType: FormNodeViewTypes.DATE, - groups: ['adr_details', 'dangerous_goods'], - hide: true, - isoDate: false, - validators: [ - { name: ValidatorNames.RequiredIfEquals, args: { sibling: 'techRecord_adrDetails_dangerousGoods', value: [true] } }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.DateIsInvalid }, - ], - }, - { - name: 'techRecord_adrDetails_permittedDangerousGoods', - label: 'Permitted dangerous goods', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CHECKBOXGROUP, - groups: ['adr_details', 'dangerous_goods'], - hide: true, - options: getOptionsFromEnum(ADRDangerousGood), - validators: [ - { - name: ValidatorNames.ShowGroupsWhenIncludes, - args: { - values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], - groups: ['compatibility_group_j'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenExcludes, - args: { - values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], - groups: ['compatibility_group_j'], - }, - }, - { name: ValidatorNames.RequiredIfEquals, args: { sibling: 'techRecord_adrDetails_dangerousGoods', value: [true] } }, - ], - }, - { - name: 'techRecord_adrDetails_compatibilityGroupJ', - label: 'Compatibility group J', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - groups: ['compatibility_group_j', 'adr_details', 'dangerous_goods'], - hide: true, - options: [ - { value: ADRCompatibilityGroupJ.I, label: 'Yes' }, - { value: ADRCompatibilityGroupJ.E, label: 'No' }, - ], - validators: [ - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_permittedDangerousGoods', - value: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], - }, - }, - ], - }, - { - name: 'techRecord_adrDetails_additionalNotes_number', - label: 'Guidance notes', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CHECKBOXGROUP, - groups: ['adr_details', 'dangerous_goods'], - hide: true, - width: FormNodeWidth.XS, - value: [], - options: getOptionsFromEnum(ADRAdditionalNotesNumber), - validators: [ - { name: ValidatorNames.RequiredIfEquals, args: { sibling: 'techRecord_adrDetails_dangerousGoods', value: [true] } }, - ], - }, - { - name: 'techRecord_adrDetails_adrTypeApprovalNo', - label: 'ADR type approval number', - value: '', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - groups: ['adr_details', 'dangerous_goods'], - hide: true, - validators: [ - { name: ValidatorNames.MaxLength, args: 40 }, - ], - }, - { - name: 'tankDetailsSectionTitle', - type: FormNodeTypes.TITLE, - label: 'Tank Details', - groups: ['tank_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankManufacturer', - label: 'Tank Make', - value: null, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XXL, - groups: ['tank_details', 'dangerous_goods'], - validators: [ - { name: ValidatorNames.MaxLength, args: 70 }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - }, - }, - ], - hide: true, - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_yearOfManufacture', - label: 'Tank Year of manufacture', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - width: FormNodeWidth.XS, - groups: ['tank_details', 'dangerous_goods'], - validators: [ - { name: ValidatorNames.Max, args: 9999 }, - { name: ValidatorNames.Min, args: 1000 }, - { name: ValidatorNames.PastYear }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - }, - }, - ], - hide: true, - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankManufacturerSerialNo', - label: 'Manufacturer serial number', - value: null, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - groups: ['tank_details', 'dangerous_goods'], - validators: [ - { name: ValidatorNames.MaxLength, args: 50 }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - }, - }, - ], - hide: true, - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankTypeAppNo', - label: 'Tank type approval number', - value: null, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - groups: ['tank_details', 'dangerous_goods'], - validators: [ - { name: ValidatorNames.MaxLength, args: 65 }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - }, - }, - ], - hide: true, - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankCode', - label: 'Code', - value: null, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - groups: ['tank_details', 'dangerous_goods'], - validators: [ - { name: ValidatorNames.MaxLength, args: 30 }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - }, - }, - ], - hide: true, - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_substancesPermitted', - label: 'Substances permitted', - width: FormNodeWidth.XS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: getOptionsFromEnum(ADRTankStatementSubstancePermitted), - groups: ['tank_details', 'dangerous_goods'], - hide: true, - validators: [ - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - }, - }, - { - name: ValidatorNames.ShowGroupsWhenEqualTo, - args: { - values: [ADRTankStatementSubstancePermitted.UNDER_UN_NUMBER], - groups: ['statement_select'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenEqualTo, - args: { - values: [ADRTankStatementSubstancePermitted.UNDER_TANK_CODE, null, undefined], - groups: ['statement_select', 'statement_select_hide'], - }, - }, - ], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_select', - label: 'Select', - width: FormNodeWidth.XS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - groups: ['statement_select', 'tank_details_hide', 'dangerous_goods'], - hide: true, - options: getOptionsFromEnum(ADRTankDetailsTankStatementSelect), - validators: [ - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_tank_tankDetails_tankStatement_substancesPermitted', - value: [ADRTankStatementSubstancePermitted.UNDER_UN_NUMBER], - }, - }, - { - name: ValidatorNames.ShowGroupsWhenIncludes, - args: { - values: [ADRTankDetailsTankStatementSelect.STATEMENT], - groups: ['statement'], - }, - }, - { - name: ValidatorNames.ShowGroupsWhenIncludes, - args: { - values: [ADRTankDetailsTankStatementSelect.PRODUCT_LIST], - groups: ['productList'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenExcludes, - args: { - values: [ADRTankDetailsTankStatementSelect.STATEMENT], - groups: ['statement'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenExcludes, - args: { - values: [ADRTankDetailsTankStatementSelect.PRODUCT_LIST], - groups: ['productList'], - }, - }, - ], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_statement', - label: 'Reference number', - type: FormNodeTypes.CONTROL, - groups: ['statement', 'statement_select_hide', 'tank_details_hide', 'dangerous_goods'], - hide: true, - validators: [ - { name: ValidatorNames.MaxLength, args: 1500 }, - ], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo', - label: 'Reference number', - type: FormNodeTypes.CONTROL, - groups: ['productList', 'statement_select_hide', 'tank_details_hide', 'dangerous_goods'], - hide: true, - validators: [ - { name: ValidatorNames.MaxLength, args: 1500 }, - { name: ValidatorNames.Custom, args: AdrValidators.validateProductListRefNo }], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo', - label: 'UN number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CUSTOM, - viewType: FormNodeViewTypes.CUSTOM, - editComponent: AdrTankStatementUnNumberEditComponent, - viewComponent: AdrTankStatementUnNumberViewComponent, - groups: ['productList', 'statement_select_hide', 'tank_details_hide', 'dangerous_goods'], - hide: true, - validators: [ - { name: ValidatorNames.Custom, args: AdrValidators.validateProductListUNNumbers }, - ], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productList', - label: 'Additional Details', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXTAREA, - groups: ['productList', 'statement_select_hide', 'tank_details_hide', 'dangerous_goods'], - hide: true, - validators: [ - { name: ValidatorNames.MaxLength, args: 1500 }, - ], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_specialProvisions', - label: 'Special Provisions', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXTAREA, - hide: true, - validators: [ - { name: ValidatorNames.MaxLength, args: 1024 }, - ], - groups: ['dangerous_goods', 'tank_details'], - }, - { - name: 'tankInspectionsSectionTitle', - type: FormNodeTypes.TITLE, - label: 'Tank Inspections', - groups: ['tank_details', 'dangerous_goods'], - hide: true, - validators: [ - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')) as string[], - }, - }, - ], - }, - { - name: 'tankInspectionsInitialView', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.CUSTOM, - viewComponent: AdrTankDetailsInitialInspectionViewComponent, - groups: ['tank_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tc2Details_tc2Type', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - label: 'TC2: Inspection type', - value: TC2Types.INITIAL, - hide: true, - groups: ['tank_details', 'dangerous_goods'], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tc2Details_tc2IntermediateApprovalNo', - label: 'TC2: Certificate Number', - viewType: FormNodeViewTypes.HIDDEN, - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['tank_details', 'dangerous_goods'], - validators: [ - { name: ValidatorNames.MaxLength, args: 70 }, - ], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tc2Details_tc2IntermediateExpiryDate', - label: 'TC2: Expiry Date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.DATE, - isoDate: false, - hide: true, - groups: ['tank_details', 'dangerous_goods'], - validators: [], - }, - { - name: 'techRecord_adrDetails_tank_tankDetails_tc3Details', - label: 'Subsequent Inspections', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.CUSTOM, - viewComponent: AdrTankDetailsSubsequentInspectionsViewComponent, - editType: FormNodeEditTypes.CUSTOM, - editComponent: AdrTankDetailsSubsequentInspectionsEditComponent, - hide: true, - groups: ['tank_details', 'dangerous_goods'], - validators: [ - { - name: ValidatorNames.Tc3TestValidator, - args: { inspectionNumber: 0 }, - }, - ], - }, - { - name: 'techRecord_adrDetails_memosApply', - label: 'Memo 7/9 (3 month extension) applied', - hint: 'Only applicable for vehicles used on national journeys', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CHECKBOXGROUP, - groups: ['tank_details', 'dangerous_goods'], - hide: true, - options: [ - { value: '07/09 3mth leak ext ', label: 'Yes' }, - ], - validators: [], - }, - { - name: 'M15Subtitle', - label: 'M145', - type: FormNodeTypes.SUBTITLE, - viewType: FormNodeViewTypes.HIDDEN, - groups: ['tank_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_m145Statement', - label: 'Yes', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.CUSTOM, - viewComponent: AdrTankDetailsM145ViewComponent, - editType: FormNodeEditTypes.CHECKBOX, - groups: ['tank_details', 'dangerous_goods'], - hide: true, - validators: [], - }, - { - name: 'techRecord_adrDetails_listStatementApplicable', - label: 'Battery List Applicable', - width: FormNodeWidth.XS, - value: false, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [ - { name: ValidatorNames.ShowGroupsWhenEqualTo, args: { values: [true], groups: ['battery_list_applicable'] } }, - { name: ValidatorNames.HideGroupsWhenEqualTo, args: { values: [false, undefined, null], groups: ['battery_list_applicable'] } }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_vehicleDetails_type', - value: Object.values(ADRBodyType).filter((value) => value.includes('battery')) as string[], - }, - }, - ], - hide: true, - groups: ['dangerous_goods', 'battery_list'], - }, - { - name: 'techRecord_adrDetails_batteryListNumber', - label: 'Reference number', - value: null, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - groups: ['battery_list_applicable', 'battery_list_hide', 'dangerous_goods'], - validators: [ - { name: ValidatorNames.MaxLength, args: 8 }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_adrDetails_listStatementApplicable', - value: [true], - }, - }, - ], - hide: true, - }, - { - name: 'DeclarationsSectionTitle', - label: 'Declarations seen', - type: FormNodeTypes.TITLE, - groups: ['declarations_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_brakeDeclarationsSeen', - label: 'Manufacturer brake declaration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CHECKBOX, - groups: ['declarations_details', 'dangerous_goods'], - value: false, - hide: true, - validators: [ - { - name: ValidatorNames.ShowGroupsWhenEqualTo, - args: { - values: [true], - groups: ['issuer_section'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenEqualTo, - args: { - values: [false], - groups: ['issuer_section', 'issuer_section_hide'], - }, - }, - ], - - }, - { - name: 'techRecord_adrDetails_brakeDeclarationIssuer', - label: 'Issuer', - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['issuer_section', 'dangerous_goods_hide'], - editType: FormNodeEditTypes.TEXTAREA, - validators: [ - { name: ValidatorNames.MaxLength, args: 500 }, - ], - }, - { - name: 'techRecord_adrDetails_brakeEndurance', - label: 'Brake endurance', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CHECKBOX, - groups: ['issuer_section', 'dangerous_goods_hide'], - hide: true, - validators: [ - { - name: ValidatorNames.ShowGroupsWhenEqualTo, - args: { - values: [true], - groups: ['weight_section'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenEqualTo, - args: { - values: [false, null, undefined], - groups: ['weight_section'], - }, - }, - ], - - }, - { - name: 'techRecord_adrDetails_weight', - label: 'Weight (tonnes)', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - enableDecimals: true, - width: FormNodeWidth.L, - groups: ['weight_section', 'issuer_section_hide', 'dangerous_goods_hide'], - hide: true, - validators: [ - { name: ValidatorNames.Max, args: 99999999 }, - { - name: ValidatorNames.RequiredIfNotHidden, - }, - { - name: ValidatorNames.CustomPattern, - args: ['^\\d*(\\.\\d{0,2})?$', 'Max 2 decimal places'], - }, - ], - }, - { - name: 'techRecord_adrDetails_declarationsSeen', - label: 'Owner/operator declaration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CHECKBOX, - groups: ['declarations_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'NewCertificateRequested', - label: 'New Certificate required', - type: FormNodeTypes.TITLE, - groups: ['dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_newCertificateRequested', - label: 'Yes', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.CUSTOM, - viewComponent: AdrNewCertificateRequiredViewComponent, - editType: FormNodeEditTypes.CHECKBOX, - value: false, - groups: ['dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_additionalExaminerNotes_note', - label: 'Additional Examiner Notes', - hint: 'Will not be present on the ADR certificate', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXTAREA, - viewType: FormNodeViewTypes.HIDDEN, - groups: ['adr_details', 'dangerous_goods'], - hide: true, - validators: [ - { name: ValidatorNames.MaxLength, args: 1024 }, - ], - }, - { - name: 'techRecord_adrDetails_additionalExaminerNotes', - value: null, - label: 'Additional Examiner Notes History', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.CUSTOM, - viewComponent: AdrExaminerNotesHistoryViewComponent, - editType: FormNodeEditTypes.CUSTOM, - editComponent: AdrExaminerNotesHistoryEditComponent, - groups: ['adr_details', 'dangerous_goods'], - hide: true, - }, - { - name: 'techRecord_adrDetails_adrCertificateNotes', - label: 'ADR Certificate Notes', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXTAREA, - viewType: FormNodeViewTypes.STRING, - groups: ['adrDetails', 'dangerous_goods'], - hide: true, - validators: [ - { name: ValidatorNames.MaxLength, args: 1500 }, - ], - }, - ], + name: 'adrSection', + type: FormNodeTypes.SECTION, + label: 'ADR', + children: [ + { + name: 'techRecord_adrDetails_dangerousGoods', + label: 'Able to carry dangerous goods', + width: FormNodeWidth.XS, + value: false, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [ + { name: ValidatorNames.ShowGroupsWhenEqualTo, args: { values: [true], groups: ['dangerous_goods'] } }, + { + name: ValidatorNames.HideGroupsWhenEqualTo, + args: { values: [false], groups: ['dangerous_goods', 'dangerous_goods_hide'] }, + }, + { + name: ValidatorNames.AddWarningForAdrField, + args: 'By selecting this field it will delete all previous ADR field inputs', + }, + ], + }, + { + name: 'applicationDetailsSectionTitle', + type: FormNodeTypes.TITLE, + label: 'Applicant Details', + groups: ['applicant_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_applicantDetails_name', + label: 'Name', + value: null, + width: FormNodeWidth.XXL, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 150 }], + groups: ['applicant_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_applicantDetails_street', + label: 'Street', + value: null, + width: FormNodeWidth.XXL, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 150 }], + groups: ['applicant_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_applicantDetails_town', + label: 'Town', + value: null, + width: FormNodeWidth.XXL, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 100 }], + groups: ['applicant_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_applicantDetails_city', + label: 'City', + value: null, + width: FormNodeWidth.XL, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 100 }], + groups: ['applicant_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_applicantDetails_postcode', + label: 'Postcode', + value: null, + width: FormNodeWidth.L, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 25 }], + groups: ['applicant_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'adrDetailsSectionTitle', + type: FormNodeTypes.TITLE, + label: 'ADR Details', + groups: ['adr_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_vehicleDetails_type', + label: 'ADR body type', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + editType: FormNodeEditTypes.SELECT, + groups: ['adr_details', 'dangerous_goods'], + hide: true, + options: getOptionsFromEnum(ADRBodyType), + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'techRecord_adrDetails_dangerousGoods', value: [true] }, + }, + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + groups: ['tank_details'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + groups: ['tank_details', 'tank_details_hide'], + }, + }, + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: Object.values(ADRBodyType).filter((value) => value.includes('battery')) as string[], + groups: ['battery_list'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: Object.values(ADRBodyType).filter((value) => value.includes('battery')) as string[], + groups: ['battery_list', 'battery_list_hide'], + }, + }, + ], + }, + { + name: 'techRecord_adrDetails_vehicleDetails_usedOnInternationalJourneys', + label: 'Vehicle used on international journeys', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'yes', label: 'Yes' }, + { value: 'no', label: 'No' }, + { value: 'n/a', label: 'Not applicable' }, + ], + hide: true, + groups: ['adr_details', 'dangerous_goods'], + }, + { + name: 'techRecord_adrDetails_vehicleDetails_approvalDate', + label: 'Date processed', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.DATE, + viewType: FormNodeViewTypes.DATE, + groups: ['adr_details', 'dangerous_goods'], + hide: true, + isoDate: false, + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'techRecord_adrDetails_dangerousGoods', value: [true] }, + }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.DateIsInvalid }, + ], + }, + { + name: 'techRecord_adrDetails_permittedDangerousGoods', + label: 'Permitted dangerous goods', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CHECKBOXGROUP, + groups: ['adr_details', 'dangerous_goods'], + hide: true, + options: getOptionsFromEnum(ADRDangerousGood), + validators: [ + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], + groups: ['compatibility_group_j'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], + groups: ['compatibility_group_j'], + }, + }, + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'techRecord_adrDetails_dangerousGoods', value: [true] }, + }, + ], + }, + { + name: 'techRecord_adrDetails_compatibilityGroupJ', + label: 'Compatibility group J', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + groups: ['compatibility_group_j', 'adr_details', 'dangerous_goods'], + hide: true, + options: [ + { value: ADRCompatibilityGroupJ.I, label: 'Yes' }, + { value: ADRCompatibilityGroupJ.E, label: 'No' }, + ], + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_permittedDangerousGoods', + value: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], + }, + }, + ], + }, + { + name: 'techRecord_adrDetails_additionalNotes_number', + label: 'Guidance notes', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CHECKBOXGROUP, + groups: ['adr_details', 'dangerous_goods'], + hide: true, + width: FormNodeWidth.XS, + value: [], + options: getOptionsFromEnum(ADRAdditionalNotesNumber), + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'techRecord_adrDetails_dangerousGoods', value: [true] }, + }, + ], + }, + { + name: 'techRecord_adrDetails_adrTypeApprovalNo', + label: 'ADR type approval number', + value: '', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + groups: ['adr_details', 'dangerous_goods'], + hide: true, + validators: [{ name: ValidatorNames.MaxLength, args: 40 }], + }, + { + name: 'tankDetailsSectionTitle', + type: FormNodeTypes.TITLE, + label: 'Tank Details', + groups: ['tank_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankManufacturer', + label: 'Tank Make', + value: null, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XXL, + groups: ['tank_details', 'dangerous_goods'], + validators: [ + { name: ValidatorNames.MaxLength, args: 70 }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + }, + }, + ], + hide: true, + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_yearOfManufacture', + label: 'Tank Year of manufacture', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + width: FormNodeWidth.XS, + groups: ['tank_details', 'dangerous_goods'], + validators: [ + { name: ValidatorNames.Max, args: 9999 }, + { name: ValidatorNames.Min, args: 1000 }, + { name: ValidatorNames.PastYear }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + }, + }, + ], + hide: true, + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankManufacturerSerialNo', + label: 'Manufacturer serial number', + value: null, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + groups: ['tank_details', 'dangerous_goods'], + validators: [ + { name: ValidatorNames.MaxLength, args: 50 }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + }, + }, + ], + hide: true, + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankTypeAppNo', + label: 'Tank type approval number', + value: null, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + groups: ['tank_details', 'dangerous_goods'], + validators: [ + { name: ValidatorNames.MaxLength, args: 65 }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + }, + }, + ], + hide: true, + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankCode', + label: 'Code', + value: null, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + groups: ['tank_details', 'dangerous_goods'], + validators: [ + { name: ValidatorNames.MaxLength, args: 30 }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + }, + }, + ], + hide: true, + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_substancesPermitted', + label: 'Substances permitted', + width: FormNodeWidth.XS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: getOptionsFromEnum(ADRTankStatementSubstancePermitted), + groups: ['tank_details', 'dangerous_goods'], + hide: true, + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + }, + }, + { + name: ValidatorNames.ShowGroupsWhenEqualTo, + args: { + values: [ADRTankStatementSubstancePermitted.UNDER_UN_NUMBER], + groups: ['statement_select'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenEqualTo, + args: { + values: [ADRTankStatementSubstancePermitted.UNDER_TANK_CODE, null, undefined], + groups: ['statement_select', 'statement_select_hide'], + }, + }, + ], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_select', + label: 'Select', + width: FormNodeWidth.XS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + groups: ['statement_select', 'tank_details_hide', 'dangerous_goods'], + hide: true, + options: getOptionsFromEnum(ADRTankDetailsTankStatementSelect), + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_tank_tankDetails_tankStatement_substancesPermitted', + value: [ADRTankStatementSubstancePermitted.UNDER_UN_NUMBER], + }, + }, + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: [ADRTankDetailsTankStatementSelect.STATEMENT], + groups: ['statement'], + }, + }, + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: [ADRTankDetailsTankStatementSelect.PRODUCT_LIST], + groups: ['productList'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: [ADRTankDetailsTankStatementSelect.STATEMENT], + groups: ['statement'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: [ADRTankDetailsTankStatementSelect.PRODUCT_LIST], + groups: ['productList'], + }, + }, + ], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_statement', + label: 'Reference number', + type: FormNodeTypes.CONTROL, + groups: ['statement', 'statement_select_hide', 'tank_details_hide', 'dangerous_goods'], + hide: true, + validators: [{ name: ValidatorNames.MaxLength, args: 1500 }], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo', + label: 'Reference number', + type: FormNodeTypes.CONTROL, + groups: ['productList', 'statement_select_hide', 'tank_details_hide', 'dangerous_goods'], + hide: true, + validators: [ + { name: ValidatorNames.MaxLength, args: 1500 }, + { name: ValidatorNames.Custom, args: AdrValidators.validateProductListRefNo }, + ], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo', + label: 'UN number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CUSTOM, + viewType: FormNodeViewTypes.CUSTOM, + editComponent: AdrTankStatementUnNumberEditComponent, + viewComponent: AdrTankStatementUnNumberViewComponent, + groups: ['productList', 'statement_select_hide', 'tank_details_hide', 'dangerous_goods'], + hide: true, + validators: [{ name: ValidatorNames.Custom, args: AdrValidators.validateProductListUNNumbers }], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productList', + label: 'Additional Details', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXTAREA, + groups: ['productList', 'statement_select_hide', 'tank_details_hide', 'dangerous_goods'], + hide: true, + validators: [{ name: ValidatorNames.MaxLength, args: 1500 }], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_specialProvisions', + label: 'Special Provisions', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXTAREA, + hide: true, + validators: [{ name: ValidatorNames.MaxLength, args: 1024 }], + groups: ['dangerous_goods', 'tank_details'], + }, + { + name: 'tankInspectionsSectionTitle', + type: FormNodeTypes.TITLE, + label: 'Tank Inspections', + groups: ['tank_details', 'dangerous_goods'], + hide: true, + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ) as string[], + }, + }, + ], + }, + { + name: 'tankInspectionsInitialView', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.CUSTOM, + viewComponent: AdrTankDetailsInitialInspectionViewComponent, + groups: ['tank_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tc2Details_tc2Type', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + label: 'TC2: Inspection type', + value: TC2Types.INITIAL, + hide: true, + groups: ['tank_details', 'dangerous_goods'], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tc2Details_tc2IntermediateApprovalNo', + label: 'TC2: Certificate Number', + viewType: FormNodeViewTypes.HIDDEN, + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['tank_details', 'dangerous_goods'], + validators: [{ name: ValidatorNames.MaxLength, args: 70 }], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tc2Details_tc2IntermediateExpiryDate', + label: 'TC2: Expiry Date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.DATE, + isoDate: false, + hide: true, + groups: ['tank_details', 'dangerous_goods'], + validators: [], + }, + { + name: 'techRecord_adrDetails_tank_tankDetails_tc3Details', + label: 'Subsequent Inspections', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.CUSTOM, + viewComponent: AdrTankDetailsSubsequentInspectionsViewComponent, + editType: FormNodeEditTypes.CUSTOM, + editComponent: AdrTankDetailsSubsequentInspectionsEditComponent, + hide: true, + groups: ['tank_details', 'dangerous_goods'], + validators: [ + { + name: ValidatorNames.Tc3TestValidator, + args: { inspectionNumber: 0 }, + }, + ], + }, + { + name: 'techRecord_adrDetails_memosApply', + label: 'Memo 7/9 (3 month extension) applied', + hint: 'Only applicable for vehicles used on national journeys', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CHECKBOXGROUP, + groups: ['tank_details', 'dangerous_goods'], + hide: true, + options: [{ value: '07/09 3mth leak ext ', label: 'Yes' }], + validators: [], + }, + { + name: 'M15Subtitle', + label: 'M145', + type: FormNodeTypes.SUBTITLE, + viewType: FormNodeViewTypes.HIDDEN, + groups: ['tank_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_m145Statement', + label: 'Yes', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.CUSTOM, + viewComponent: AdrTankDetailsM145ViewComponent, + editType: FormNodeEditTypes.CHECKBOX, + groups: ['tank_details', 'dangerous_goods'], + hide: true, + validators: [], + }, + { + name: 'techRecord_adrDetails_listStatementApplicable', + label: 'Battery List Applicable', + width: FormNodeWidth.XS, + value: false, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [ + { name: ValidatorNames.ShowGroupsWhenEqualTo, args: { values: [true], groups: ['battery_list_applicable'] } }, + { + name: ValidatorNames.HideGroupsWhenEqualTo, + args: { values: [false, undefined, null], groups: ['battery_list_applicable'] }, + }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_vehicleDetails_type', + value: Object.values(ADRBodyType).filter((value) => value.includes('battery')) as string[], + }, + }, + ], + hide: true, + groups: ['dangerous_goods', 'battery_list'], + }, + { + name: 'techRecord_adrDetails_batteryListNumber', + label: 'Reference number', + value: null, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + groups: ['battery_list_applicable', 'battery_list_hide', 'dangerous_goods'], + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_adrDetails_listStatementApplicable', + value: [true], + }, + }, + ], + hide: true, + }, + { + name: 'DeclarationsSectionTitle', + label: 'Declarations seen', + type: FormNodeTypes.TITLE, + groups: ['declarations_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_brakeDeclarationsSeen', + label: 'Manufacturer brake declaration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CHECKBOX, + groups: ['declarations_details', 'dangerous_goods'], + value: false, + hide: true, + validators: [ + { + name: ValidatorNames.ShowGroupsWhenEqualTo, + args: { + values: [true], + groups: ['issuer_section'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenEqualTo, + args: { + values: [false], + groups: ['issuer_section', 'issuer_section_hide'], + }, + }, + ], + }, + { + name: 'techRecord_adrDetails_brakeDeclarationIssuer', + label: 'Issuer', + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['issuer_section', 'dangerous_goods_hide'], + editType: FormNodeEditTypes.TEXTAREA, + validators: [{ name: ValidatorNames.MaxLength, args: 500 }], + }, + { + name: 'techRecord_adrDetails_brakeEndurance', + label: 'Brake endurance', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CHECKBOX, + groups: ['issuer_section', 'dangerous_goods_hide'], + hide: true, + validators: [ + { + name: ValidatorNames.ShowGroupsWhenEqualTo, + args: { + values: [true], + groups: ['weight_section'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenEqualTo, + args: { + values: [false, null, undefined], + groups: ['weight_section'], + }, + }, + ], + }, + { + name: 'techRecord_adrDetails_weight', + label: 'Weight (tonnes)', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + enableDecimals: true, + width: FormNodeWidth.L, + groups: ['weight_section', 'issuer_section_hide', 'dangerous_goods_hide'], + hide: true, + validators: [ + { name: ValidatorNames.Max, args: 99999999 }, + { + name: ValidatorNames.RequiredIfNotHidden, + }, + { + name: ValidatorNames.CustomPattern, + args: ['^\\d*(\\.\\d{0,2})?$', 'Max 2 decimal places'], + }, + ], + }, + { + name: 'techRecord_adrDetails_declarationsSeen', + label: 'Owner/operator declaration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CHECKBOX, + groups: ['declarations_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'NewCertificateRequested', + label: 'New Certificate required', + type: FormNodeTypes.TITLE, + groups: ['dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_newCertificateRequested', + label: 'Yes', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.CUSTOM, + viewComponent: AdrNewCertificateRequiredViewComponent, + editType: FormNodeEditTypes.CHECKBOX, + value: false, + groups: ['dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_additionalExaminerNotes_note', + label: 'Additional Examiner Notes', + hint: 'Will not be present on the ADR certificate', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXTAREA, + viewType: FormNodeViewTypes.HIDDEN, + groups: ['adr_details', 'dangerous_goods'], + hide: true, + validators: [{ name: ValidatorNames.MaxLength, args: 1024 }], + }, + { + name: 'techRecord_adrDetails_additionalExaminerNotes', + value: null, + label: 'Additional Examiner Notes History', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.CUSTOM, + viewComponent: AdrExaminerNotesHistoryViewComponent, + editType: FormNodeEditTypes.CUSTOM, + editComponent: AdrExaminerNotesHistoryEditComponent, + groups: ['adr_details', 'dangerous_goods'], + hide: true, + }, + { + name: 'techRecord_adrDetails_adrCertificateNotes', + label: 'ADR Certificate Notes', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXTAREA, + viewType: FormNodeViewTypes.STRING, + groups: ['adrDetails', 'dangerous_goods'], + hide: true, + validators: [{ name: ValidatorNames.MaxLength, args: 1500 }], + }, + ], }; diff --git a/src/app/forms/templates/general/applicant-details.template.ts b/src/app/forms/templates/general/applicant-details.template.ts index 926cd5d80f..7601205ed2 100644 --- a/src/app/forms/templates/general/applicant-details.template.ts +++ b/src/app/forms/templates/general/applicant-details.template.ts @@ -2,73 +2,73 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { FormNode, FormNodeTypes, FormNodeWidth } from '../../services/dynamic-form.types'; export const ApplicantDetails: FormNode = { - name: 'techRecord', - type: FormNodeTypes.GROUP, - label: 'Last Applicant', - children: [ - { - name: 'techRecord_applicantDetails_name', - label: 'Name or company', - value: null, - width: FormNodeWidth.XXL, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 150 }], - }, - { - name: 'techRecord_applicantDetails_address1', - label: 'Address line 1', - value: null, - width: FormNodeWidth.XXL, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 60 }], - }, - { - name: 'techRecord_applicantDetails_address2', - label: 'Address line 2', - value: null, - width: FormNodeWidth.XXL, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 60 }], - }, - { - name: 'techRecord_applicantDetails_postTown', - label: 'Town or City', - value: null, - width: FormNodeWidth.XL, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 60 }], - }, - { - name: 'techRecord_applicantDetails_address3', - label: 'County', - value: null, - width: FormNodeWidth.XL, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 60 }], - }, - { - name: 'techRecord_applicantDetails_postCode', - label: 'Postcode', - value: null, - width: FormNodeWidth.L, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 12 }], - }, - { - name: 'techRecord_applicantDetails_telephoneNumber', - label: 'Telephone number', - value: null, - width: FormNodeWidth.XL, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 25 }], - }, - { - name: 'techRecord_applicantDetails_emailAddress', - label: 'Email address', - value: null, - width: FormNodeWidth.XL, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 255 }, { name: ValidatorNames.Email }], - }, - ], + name: 'techRecord', + type: FormNodeTypes.GROUP, + label: 'Last Applicant', + children: [ + { + name: 'techRecord_applicantDetails_name', + label: 'Name or company', + value: null, + width: FormNodeWidth.XXL, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 150 }], + }, + { + name: 'techRecord_applicantDetails_address1', + label: 'Address line 1', + value: null, + width: FormNodeWidth.XXL, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 60 }], + }, + { + name: 'techRecord_applicantDetails_address2', + label: 'Address line 2', + value: null, + width: FormNodeWidth.XXL, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 60 }], + }, + { + name: 'techRecord_applicantDetails_postTown', + label: 'Town or City', + value: null, + width: FormNodeWidth.XL, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 60 }], + }, + { + name: 'techRecord_applicantDetails_address3', + label: 'County', + value: null, + width: FormNodeWidth.XL, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 60 }], + }, + { + name: 'techRecord_applicantDetails_postCode', + label: 'Postcode', + value: null, + width: FormNodeWidth.L, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 12 }], + }, + { + name: 'techRecord_applicantDetails_telephoneNumber', + label: 'Telephone number', + value: null, + width: FormNodeWidth.XL, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 25 }], + }, + { + name: 'techRecord_applicantDetails_emailAddress', + label: 'Email address', + value: null, + width: FormNodeWidth.XL, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 255 }, { name: ValidatorNames.Email }], + }, + ], }; diff --git a/src/app/forms/templates/general/approval-type.template.ts b/src/app/forms/templates/general/approval-type.template.ts index 81efd73b25..e148505851 100644 --- a/src/app/forms/templates/general/approval-type.template.ts +++ b/src/app/forms/templates/general/approval-type.template.ts @@ -3,74 +3,80 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { getOptionsFromEnum } from '@forms/utils/enum-map'; import { TagType } from '@shared/components/tag/tag.component'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeWidth, TagTypeLabels, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeWidth, + TagTypeLabels, } from '../../services/dynamic-form.types'; export const HgvAndTrlTypeApprovalTemplate: FormNode = { - name: 'approvalSection', - label: 'Type approval', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'techRecord_approvalType', - label: 'Approval type', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - options: getOptionsFromEnum(ApprovalType), - validators: [{ name: ValidatorNames.IsMemberOfEnum, args: { enum: ApprovalType, options: { allowFalsy: true } } }], - }, - { - name: 'techRecord_approvalTypeNumber', - label: 'Approval type number', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XL, - validators: [ - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_approvalType', - value: [ - 'NTA', - 'ECTA', - 'ECSSTA', - 'IVA', - 'NSSTA', - 'GB WVTA', - 'UKNI WVTA', - 'EU WVTA Pre 23', - 'EU WVTA 23 on', - 'QNIG', - 'Prov.GB WVTA', - 'Small series NKSXX', - 'Small series NKS', - 'IVA - VCA', - 'IVA - DVSA/NI', - ], - }, - }, - ], - }, - { - name: 'techRecord_ntaNumber', - label: 'National type number', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XXL, - validators: [{ name: ValidatorNames.MaxLength, args: 40 }], - }, - { - name: 'techRecord_variantNumber', - label: 'Variant number', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XL, - validators: [{ name: ValidatorNames.MaxLength, args: 25 }], - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_variantVersionNumber', - label: 'Variant version number', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XXL, - validators: [{ name: ValidatorNames.MaxLength, args: 35 }], - }, - ], + name: 'approvalSection', + label: 'Type approval', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'techRecord_approvalType', + label: 'Approval type', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: getOptionsFromEnum(ApprovalType), + validators: [ + { name: ValidatorNames.IsMemberOfEnum, args: { enum: ApprovalType, options: { allowFalsy: true } } }, + ], + }, + { + name: 'techRecord_approvalTypeNumber', + label: 'Approval type number', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XL, + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_approvalType', + value: [ + 'NTA', + 'ECTA', + 'ECSSTA', + 'IVA', + 'NSSTA', + 'GB WVTA', + 'UKNI WVTA', + 'EU WVTA Pre 23', + 'EU WVTA 23 on', + 'QNIG', + 'Prov.GB WVTA', + 'Small series NKSXX', + 'Small series NKS', + 'IVA - VCA', + 'IVA - DVSA/NI', + ], + }, + }, + ], + }, + { + name: 'techRecord_ntaNumber', + label: 'National type number', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XXL, + validators: [{ name: ValidatorNames.MaxLength, args: 40 }], + }, + { + name: 'techRecord_variantNumber', + label: 'Variant number', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XL, + validators: [{ name: ValidatorNames.MaxLength, args: 25 }], + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_variantVersionNumber', + label: 'Variant version number', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XXL, + validators: [{ name: ValidatorNames.MaxLength, args: 35 }], + }, + ], }; diff --git a/src/app/forms/templates/general/audit.template.ts b/src/app/forms/templates/general/audit.template.ts index a5d4c47122..4e0449c7b5 100644 --- a/src/app/forms/templates/general/audit.template.ts +++ b/src/app/forms/templates/general/audit.template.ts @@ -1,54 +1,54 @@ import { FormNode, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const Audit: FormNode = { - name: 'audit', - type: FormNodeTypes.GROUP, - label: 'Audit', - children: [ - { - name: 'techRecord_reasonForCreation', - label: 'Reason for creation', - value: '', - type: FormNodeTypes.CONTROL, - validators: [], - }, - { - name: 'techRecord_createdAt', - label: 'Created at', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATETIME, - }, - { - name: 'techRecord_createdByName', - label: 'Created by', - value: null, - type: FormNodeTypes.CONTROL, - }, - { - name: 'techRecord_createdById', - label: 'Created by ID', - value: null, - type: FormNodeTypes.CONTROL, - }, - { - name: 'techRecord_lastUpdatedAt', - label: 'Last updated at', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATETIME, - }, - { - name: 'techRecord_lastUpdatedByName', - label: 'Last updated by', - value: null, - type: FormNodeTypes.CONTROL, - }, - { - name: 'techRecord_lastUpdatedById', - label: 'Last updated by ID', - value: null, - type: FormNodeTypes.CONTROL, - }, - ], + name: 'audit', + type: FormNodeTypes.GROUP, + label: 'Audit', + children: [ + { + name: 'techRecord_reasonForCreation', + label: 'Reason for creation', + value: '', + type: FormNodeTypes.CONTROL, + validators: [], + }, + { + name: 'techRecord_createdAt', + label: 'Created at', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATETIME, + }, + { + name: 'techRecord_createdByName', + label: 'Created by', + value: null, + type: FormNodeTypes.CONTROL, + }, + { + name: 'techRecord_createdById', + label: 'Created by ID', + value: null, + type: FormNodeTypes.CONTROL, + }, + { + name: 'techRecord_lastUpdatedAt', + label: 'Last updated at', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATETIME, + }, + { + name: 'techRecord_lastUpdatedByName', + label: 'Last updated by', + value: null, + type: FormNodeTypes.CONTROL, + }, + { + name: 'techRecord_lastUpdatedById', + label: 'Last updated by ID', + value: null, + type: FormNodeTypes.CONTROL, + }, + ], }; diff --git a/src/app/forms/templates/general/defect.template.ts b/src/app/forms/templates/general/defect.template.ts index 2a1db1c9e4..2b4684d184 100644 --- a/src/app/forms/templates/general/defect.template.ts +++ b/src/app/forms/templates/general/defect.template.ts @@ -2,192 +2,192 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { FormNode, FormNodeEditTypes, FormNodeTypes } from '@forms/services/dynamic-form.types'; export const DefectsTpl: FormNode = { - name: 'defects', - label: 'Defects', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'defects', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'deficiencyRef', - label: 'Deficiency ref', - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'deficiencyCategory', - label: 'Deficiency category', - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'imNumber', - label: 'IM number', - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'imDescription', - label: 'IM description', - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'itemNumber', - label: 'Item No.', - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'itemDescription', - label: 'Item description', - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'deficiencyId', - label: 'Deficiency ID', - value: null, - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'deficiencySubId', - label: 'Deficiency sub ID', - value: null, - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'deficiencyText', - label: 'Deficiency text', - value: null, - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'additionalInformation', - label: 'Additional details', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'location', - label: 'Location', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'vertical', - label: 'Vertical', - value: null, - type: FormNodeTypes.CONTROL, - }, - { - name: 'horizontal', - label: 'Horizontal', - value: null, - type: FormNodeTypes.CONTROL, - }, - { - name: 'lateral', - label: 'Lateral', - value: null, - type: FormNodeTypes.CONTROL, - }, - { - name: 'longitudinal', - label: 'Longitudinal', - value: null, - type: FormNodeTypes.CONTROL, - }, - { - name: 'rowNumber', - label: 'Row number', - value: null, - type: FormNodeTypes.CONTROL, - }, - { - name: 'seatNumber', - label: 'Seat number', - value: null, - type: FormNodeTypes.CONTROL, - }, - { - name: 'axleNumber', - label: 'Axle number', - value: null, - type: FormNodeTypes.CONTROL, - }, - ], - }, - { - name: 'notes', - label: 'Notes', - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.ValidateDefectNotes }], - }, - ], - }, - { - name: 'prs', - label: 'PRS', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - }, - { - name: 'prohibitionIssued', - label: 'Prohibition issued', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [ - { - name: ValidatorNames.RequiredIfEquals, - args: { sibling: 'deficiencyCategory', value: ['dangerous'] }, - }, - { - name: ValidatorNames.ValidateProhibitionIssued, - }, - ], - }, - { - name: 'stdForProhibition', - label: 'STD for prohibition', - value: null, - type: FormNodeTypes.CONTROL, - disabled: true, - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], + name: 'defects', + label: 'Defects', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'defects', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'deficiencyRef', + label: 'Deficiency ref', + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'deficiencyCategory', + label: 'Deficiency category', + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'imNumber', + label: 'IM number', + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'imDescription', + label: 'IM description', + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'itemNumber', + label: 'Item No.', + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'itemDescription', + label: 'Item description', + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'deficiencyId', + label: 'Deficiency ID', + value: null, + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'deficiencySubId', + label: 'Deficiency sub ID', + value: null, + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'deficiencyText', + label: 'Deficiency text', + value: null, + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'additionalInformation', + label: 'Additional details', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'location', + label: 'Location', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'vertical', + label: 'Vertical', + value: null, + type: FormNodeTypes.CONTROL, + }, + { + name: 'horizontal', + label: 'Horizontal', + value: null, + type: FormNodeTypes.CONTROL, + }, + { + name: 'lateral', + label: 'Lateral', + value: null, + type: FormNodeTypes.CONTROL, + }, + { + name: 'longitudinal', + label: 'Longitudinal', + value: null, + type: FormNodeTypes.CONTROL, + }, + { + name: 'rowNumber', + label: 'Row number', + value: null, + type: FormNodeTypes.CONTROL, + }, + { + name: 'seatNumber', + label: 'Seat number', + value: null, + type: FormNodeTypes.CONTROL, + }, + { + name: 'axleNumber', + label: 'Axle number', + value: null, + type: FormNodeTypes.CONTROL, + }, + ], + }, + { + name: 'notes', + label: 'Notes', + value: null, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.ValidateDefectNotes }], + }, + ], + }, + { + name: 'prs', + label: 'PRS', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + }, + { + name: 'prohibitionIssued', + label: 'Prohibition issued', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'deficiencyCategory', value: ['dangerous'] }, + }, + { + name: ValidatorNames.ValidateProhibitionIssued, + }, + ], + }, + { + name: 'stdForProhibition', + label: 'STD for prohibition', + value: null, + type: FormNodeTypes.CONTROL, + disabled: true, + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/general/document-types.ts b/src/app/forms/templates/general/document-types.ts index 1eafede9b7..4dbffe83b6 100644 --- a/src/app/forms/templates/general/document-types.ts +++ b/src/app/forms/templates/general/document-types.ts @@ -1,165 +1,165 @@ import { FormNodeOption } from '@forms/services/dynamic-form.types'; export const DOCUMENT_TYPES: FormNodeOption[] = [ - { - value: 'AAV - HGV Annual Test', - label: 'AAV - HGV Annual Test', - }, - { - value: 'COIF Master', - label: 'COIF Master', - }, - { - value: 'Tempo 100 Sp Ord', - label: 'Tempo 100 Sp Ord', - }, - { - value: 'Deleted', - label: 'Deleted', - }, - { - value: 'XPT - Tr Plating Cert paid', - label: 'XPT - Tr Plating Cert paid', - }, + { + value: 'AAV - HGV Annual Test', + label: 'AAV - HGV Annual Test', + }, + { + value: 'COIF Master', + label: 'COIF Master', + }, + { + value: 'Tempo 100 Sp Ord', + label: 'Tempo 100 Sp Ord', + }, + { + value: 'Deleted', + label: 'Deleted', + }, + { + value: 'XPT - Tr Plating Cert paid', + label: 'XPT - Tr Plating Cert paid', + }, - { - value: 'FFV - HGV First Test', - label: 'FFV - HGV First Test', - }, - { - value: 'Repl Vitesse 100', - label: 'Repl Vitesse 100', - }, - { - value: 'TCV - HGV Test Cert', - label: 'TCV - HGV Test Cert', - }, - { - value: 'ZZZ - Miscellaneous', - label: 'ZZZ - Miscellaneous', - }, - { - value: 'Test Certificate', - label: 'Test Certificate', - }, - { - value: 'XCT - Trailer Test Cert free', - label: 'XCT - Trailer Test Cert free', - }, - { - value: 'C52 - COC and VTG52A', - label: 'C52 - COC and VTG52A', - }, - { - value: 'Tempo 100 Report', - label: 'Tempo 100 Report', - }, - { - value: 'Main File Amendment', - label: 'Main File Amendment', - }, - { - value: 'PSV Doc', - label: 'PSV Doc', - }, - { - value: 'PSV Repl COC', - label: 'PSV Repl COC', - }, - { - value: 'TAV - COC', - label: 'TAV - COC', - }, - { - value: 'NPT - Trailer Alteration', - label: 'NPT - Trailer Alteration', - }, - { - value: 'OMO Certificate', - label: 'OMO Certificate', - }, - { - value: 'PSV Repl COIF', - label: 'PSV Repl COIF', - }, - { - value: 'COIF Application', - label: 'COIF Application', - }, - { - value: 'XPV - HGV Plating Cert Free', - label: 'XPV - HGV Plating Cert Free', - }, - { - value: 'TCT - Trailer Test Cert', - label: 'TCT - Trailer Test Cert', - }, - { - value: 'Tempo 100 App', - label: 'Tempo 100 App', - }, - { - value: 'PSV Decision on N/ALT', - label: 'PSV Decision on N/ALT', - }, - { - value: 'Special Order PSV', - label: 'Special Order PSV', - }, - { - value: 'NPV - HGV Alteration', - label: 'NPV - HGV Alteration', - }, - { - value: 'No Description Found', - label: 'No Description Found', - }, - { - value: 'Vitesse 100 Sp Ord', - label: 'Vitesse 100 Sp Ord', - }, - { - value: 'Brake Test Details', - label: 'Brake Test Details', - }, - { - value: 'COIF Productional', - label: 'COIF Productional', - }, - { - value: 'RDT - Test Disc Paid', - label: 'RDT - Test Disc Paid', - }, - { - value: 'RCV - HGV Test Cert', - label: 'RCV - HGV Test Cert', - }, - { - value: 'FFT - Trailer First Test', - label: 'FFT - Trailer First Test', - }, - { - value: 'IPT - Trailer EEC Plate/Cert', - label: 'IPT - Trailer EEC Plate/Cert', - }, - { - value: 'XDT - Test Disc Free', - label: 'XDT - Test Disc Free', - }, - { - value: 'PRV - HGV Plating Cert paid', - label: 'PRV - HGV Plating Cert paid', - }, - { - value: 'COF Cert', - label: 'COF Cert', - }, - { - value: 'PRT - Tr Plating Cert paid', - label: 'PRT - Tr Plating Cert paid', - }, - { - value: 'Tempo 100 Permit', - label: 'Tempo 100 Permit', - }, + { + value: 'FFV - HGV First Test', + label: 'FFV - HGV First Test', + }, + { + value: 'Repl Vitesse 100', + label: 'Repl Vitesse 100', + }, + { + value: 'TCV - HGV Test Cert', + label: 'TCV - HGV Test Cert', + }, + { + value: 'ZZZ - Miscellaneous', + label: 'ZZZ - Miscellaneous', + }, + { + value: 'Test Certificate', + label: 'Test Certificate', + }, + { + value: 'XCT - Trailer Test Cert free', + label: 'XCT - Trailer Test Cert free', + }, + { + value: 'C52 - COC and VTG52A', + label: 'C52 - COC and VTG52A', + }, + { + value: 'Tempo 100 Report', + label: 'Tempo 100 Report', + }, + { + value: 'Main File Amendment', + label: 'Main File Amendment', + }, + { + value: 'PSV Doc', + label: 'PSV Doc', + }, + { + value: 'PSV Repl COC', + label: 'PSV Repl COC', + }, + { + value: 'TAV - COC', + label: 'TAV - COC', + }, + { + value: 'NPT - Trailer Alteration', + label: 'NPT - Trailer Alteration', + }, + { + value: 'OMO Certificate', + label: 'OMO Certificate', + }, + { + value: 'PSV Repl COIF', + label: 'PSV Repl COIF', + }, + { + value: 'COIF Application', + label: 'COIF Application', + }, + { + value: 'XPV - HGV Plating Cert Free', + label: 'XPV - HGV Plating Cert Free', + }, + { + value: 'TCT - Trailer Test Cert', + label: 'TCT - Trailer Test Cert', + }, + { + value: 'Tempo 100 App', + label: 'Tempo 100 App', + }, + { + value: 'PSV Decision on N/ALT', + label: 'PSV Decision on N/ALT', + }, + { + value: 'Special Order PSV', + label: 'Special Order PSV', + }, + { + value: 'NPV - HGV Alteration', + label: 'NPV - HGV Alteration', + }, + { + value: 'No Description Found', + label: 'No Description Found', + }, + { + value: 'Vitesse 100 Sp Ord', + label: 'Vitesse 100 Sp Ord', + }, + { + value: 'Brake Test Details', + label: 'Brake Test Details', + }, + { + value: 'COIF Productional', + label: 'COIF Productional', + }, + { + value: 'RDT - Test Disc Paid', + label: 'RDT - Test Disc Paid', + }, + { + value: 'RCV - HGV Test Cert', + label: 'RCV - HGV Test Cert', + }, + { + value: 'FFT - Trailer First Test', + label: 'FFT - Trailer First Test', + }, + { + value: 'IPT - Trailer EEC Plate/Cert', + label: 'IPT - Trailer EEC Plate/Cert', + }, + { + value: 'XDT - Test Disc Free', + label: 'XDT - Test Disc Free', + }, + { + value: 'PRV - HGV Plating Cert paid', + label: 'PRV - HGV Plating Cert paid', + }, + { + value: 'COF Cert', + label: 'COF Cert', + }, + { + value: 'PRT - Tr Plating Cert paid', + label: 'PRT - Tr Plating Cert paid', + }, + { + value: 'Tempo 100 Permit', + label: 'Tempo 100 Permit', + }, ]; diff --git a/src/app/forms/templates/general/documents.template.ts b/src/app/forms/templates/general/documents.template.ts index 6e6e90424b..a3cd51d7f6 100644 --- a/src/app/forms/templates/general/documents.template.ts +++ b/src/app/forms/templates/general/documents.template.ts @@ -1,32 +1,32 @@ -import { DOCUMENT_TYPES } from '@forms/templates/general/document-types'; import { ValidatorNames } from '@forms/models/validators.enum'; +import { DOCUMENT_TYPES } from '@forms/templates/general/document-types'; import { FormNode, FormNodeEditTypes, FormNodeTypes } from '../../services/dynamic-form.types'; export const DocumentsTemplate: FormNode = { - name: 'documentsSection', - label: 'Documents', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'techRecord_microfilm_microfilmDocumentType', - label: 'Microfilm document type', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.AUTOCOMPLETE, - options: DOCUMENT_TYPES, - }, - { - name: 'techRecord_microfilm_microfilmRollNumber', - label: 'Microfilm roll number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXT, - validators: [{ name: ValidatorNames.MaxLength, args: 5 }], - }, - { - name: 'techRecord_microfilm_microfilmSerialNumber', - label: 'Microfilm serial number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXT, - validators: [{ name: ValidatorNames.MaxLength, args: 4 }], - }, - ], + name: 'documentsSection', + label: 'Documents', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'techRecord_microfilm_microfilmDocumentType', + label: 'Microfilm document type', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.AUTOCOMPLETE, + options: DOCUMENT_TYPES, + }, + { + name: 'techRecord_microfilm_microfilmRollNumber', + label: 'Microfilm roll number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXT, + validators: [{ name: ValidatorNames.MaxLength, args: 5 }], + }, + { + name: 'techRecord_microfilm_microfilmSerialNumber', + label: 'Microfilm serial number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXT, + validators: [{ name: ValidatorNames.MaxLength, args: 4 }], + }, + ], }; diff --git a/src/app/forms/templates/general/hgv-trl-body.template.ts b/src/app/forms/templates/general/hgv-trl-body.template.ts index e097b75124..a22b12d789 100644 --- a/src/app/forms/templates/general/hgv-trl-body.template.ts +++ b/src/app/forms/templates/general/hgv-trl-body.template.ts @@ -2,85 +2,95 @@ import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; import { TagType } from '@shared/components/tag/tag.component'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, TagTypeLabels, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, + TagTypeLabels, } from '../../services/dynamic-form.types'; export const HgvAndTrlBodyTemplate: FormNode = { - name: 'bodySection', - label: 'Body', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'techRecord_brakes_dtpNumber', - label: 'DTp number', - value: null, - width: FormNodeWidth.L, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXT, - validators: [{ name: ValidatorNames.MaxLength, args: 6 }], - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_make', - label: 'Body make', - value: null, - width: FormNodeWidth.L, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXT, - validators: [{ name: ValidatorNames.MaxLength, args: 50 }], - asyncValidators: [{ name: AsyncValidatorNames.RequiredWhenCarryingDangerousGoods }], - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_model', - label: 'Body model', - value: null, - width: FormNodeWidth.L, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXT, - validators: [{ name: ValidatorNames.MaxLength, args: 30 }], - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_bodyType_description', - label: 'Body type', - value: null, - customId: 'techRecord_bodyType_description', - width: FormNodeWidth.L, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - validators: [{ name: ValidatorNames.Required }], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_bodyType_code', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'techRecord_functionCode', - label: 'Function code', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - width: FormNodeWidth.S, - options: [ - { value: 'r', label: 'R' }, - { value: 'a', label: 'A' }, - ], - validators: [{ name: ValidatorNames.MaxLength, args: 1 }], - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_conversionRefNo', - label: 'Conversion ref no', - value: null, - width: FormNodeWidth.L, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXT, - validators: [{ name: ValidatorNames.CustomPattern, args: ['^[A-Z0-9 ]{0,10}$', 'max length 10 uppercase letters or numbers'] }], - }, - ], + name: 'bodySection', + label: 'Body', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'techRecord_brakes_dtpNumber', + label: 'DTp number', + value: null, + width: FormNodeWidth.L, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXT, + validators: [{ name: ValidatorNames.MaxLength, args: 6 }], + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_make', + label: 'Body make', + value: null, + width: FormNodeWidth.L, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXT, + validators: [{ name: ValidatorNames.MaxLength, args: 50 }], + asyncValidators: [{ name: AsyncValidatorNames.RequiredWhenCarryingDangerousGoods }], + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_model', + label: 'Body model', + value: null, + width: FormNodeWidth.L, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXT, + validators: [{ name: ValidatorNames.MaxLength, args: 30 }], + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_bodyType_description', + label: 'Body type', + value: null, + customId: 'techRecord_bodyType_description', + width: FormNodeWidth.L, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + validators: [{ name: ValidatorNames.Required }], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_bodyType_code', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'techRecord_functionCode', + label: 'Function code', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + width: FormNodeWidth.S, + options: [ + { value: 'r', label: 'R' }, + { value: 'a', label: 'A' }, + ], + validators: [{ name: ValidatorNames.MaxLength, args: 1 }], + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_conversionRefNo', + label: 'Conversion ref no', + value: null, + width: FormNodeWidth.L, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXT, + validators: [ + { + name: ValidatorNames.CustomPattern, + args: ['^[A-Z0-9 ]{0,10}$', 'max length 10 uppercase letters or numbers'], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/general/letter-types.ts b/src/app/forms/templates/general/letter-types.ts index d793768d2d..655c3d66ec 100644 --- a/src/app/forms/templates/general/letter-types.ts +++ b/src/app/forms/templates/general/letter-types.ts @@ -1,12 +1,12 @@ import { FormNodeOption } from '@forms/services/dynamic-form.types'; export const LETTER_TYPES: FormNodeOption[] = [ - { - value: 'trailer acceptance', - label: 'Trailer acceptance', - }, - { - value: 'trailer rejection', - label: 'Trailer rejection', - }, + { + value: 'trailer acceptance', + label: 'Trailer acceptance', + }, + { + value: 'trailer rejection', + label: 'Trailer rejection', + }, ]; diff --git a/src/app/forms/templates/general/letters.template.ts b/src/app/forms/templates/general/letters.template.ts index d37b124cba..bfb8e5bbed 100644 --- a/src/app/forms/templates/general/letters.template.ts +++ b/src/app/forms/templates/general/letters.template.ts @@ -2,37 +2,37 @@ import { FormNode, FormNodeTypes, FormNodeViewTypes } from '../../services/dynam import { LETTER_TYPES } from './letter-types'; export const LettersTemplate: FormNode = { - name: 'lettersSection', - label: 'Letters', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'techRecord_letterOfAuth_letterIssuer', - label: 'Letter issuer', - type: FormNodeTypes.CONTROL, - options: LETTER_TYPES, - }, - { - name: 'techRecord_letterOfAuth_letterType', - label: 'Type of letter', - type: FormNodeTypes.CONTROL, - options: LETTER_TYPES, - }, - { - name: 'techRecord_letterOfAuth_letterDateRequested', - label: 'Date requested', - type: FormNodeTypes.CONTROL, - }, - { - name: 'techRecord_letterOfAuth_paragraphId', - label: 'Paragraph ID', - type: FormNodeTypes.CONTROL, - }, - { - name: 'techRecord_letterOfAuth_letterContents', - label: 'Content', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], + name: 'lettersSection', + label: 'Letters', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'techRecord_letterOfAuth_letterIssuer', + label: 'Letter issuer', + type: FormNodeTypes.CONTROL, + options: LETTER_TYPES, + }, + { + name: 'techRecord_letterOfAuth_letterType', + label: 'Type of letter', + type: FormNodeTypes.CONTROL, + options: LETTER_TYPES, + }, + { + name: 'techRecord_letterOfAuth_letterDateRequested', + label: 'Date requested', + type: FormNodeTypes.CONTROL, + }, + { + name: 'techRecord_letterOfAuth_paragraphId', + label: 'Paragraph ID', + type: FormNodeTypes.CONTROL, + }, + { + name: 'techRecord_letterOfAuth_letterContents', + label: 'Content', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], }; diff --git a/src/app/forms/templates/general/manufacturer.template.ts b/src/app/forms/templates/general/manufacturer.template.ts index 245eca5ff4..1631c1deeb 100644 --- a/src/app/forms/templates/general/manufacturer.template.ts +++ b/src/app/forms/templates/general/manufacturer.template.ts @@ -1,82 +1,80 @@ import { ValidatorNames } from '@forms/models/validators.enum'; -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeWidth, -} from '../../services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeWidth } from '../../services/dynamic-form.types'; export const ManufacturerTemplate: FormNode = { - name: 'manufacturerSection', - label: 'Manufacturer', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'techRecord_manufacturerDetails_name', - label: 'Name', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XXL, - validators: [{ name: ValidatorNames.MaxLength, args: 150 }], - }, - { - name: 'techRecord_manufacturerDetails_address1', - label: 'Address line 1', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XXL, - validators: [{ name: ValidatorNames.MaxLength, args: 60 }], - }, - { - name: 'techRecord_manufacturerDetails_address2', - label: 'Address line 2', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XXL, - validators: [{ name: ValidatorNames.MaxLength, args: 60 }], - }, - { - name: 'techRecord_manufacturerDetails_postTown', - label: 'Town or City', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XL, - validators: [{ name: ValidatorNames.MaxLength, args: 60 }], - }, - { - name: 'techRecord_manufacturerDetails_address3', - label: 'County', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XL, - validators: [{ name: ValidatorNames.MaxLength, args: 60 }], - }, - { - name: 'techRecord_manufacturerDetails_postCode', - label: 'Postcode', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - validators: [{ name: ValidatorNames.MaxLength, args: 12 }], - }, - { - name: 'techRecord_manufacturerDetails_telephoneNumber', - label: 'Telephone number', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XL, - validators: [{ name: ValidatorNames.MaxLength, args: 25 }], - }, - { - name: 'techRecord_manufacturerDetails_emailAddress', - label: 'Email address', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XL, - validators: [{ name: ValidatorNames.MaxLength, args: 255 }, { name: ValidatorNames.Email }], - }, - { - name: 'techRecord_manufacturerDetails_faxNumber', - label: 'Fax Number', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XL, - validators: [{ name: ValidatorNames.MaxLength, args: 25 }], - }, - { - name: 'techRecord_manufacturerDetails_manufacturerNotes', - label: 'Manufacturer Notes', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXTAREA, - validators: [{ name: ValidatorNames.MaxLength, args: 1024 }], - }, - ], + name: 'manufacturerSection', + label: 'Manufacturer', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'techRecord_manufacturerDetails_name', + label: 'Name', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XXL, + validators: [{ name: ValidatorNames.MaxLength, args: 150 }], + }, + { + name: 'techRecord_manufacturerDetails_address1', + label: 'Address line 1', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XXL, + validators: [{ name: ValidatorNames.MaxLength, args: 60 }], + }, + { + name: 'techRecord_manufacturerDetails_address2', + label: 'Address line 2', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XXL, + validators: [{ name: ValidatorNames.MaxLength, args: 60 }], + }, + { + name: 'techRecord_manufacturerDetails_postTown', + label: 'Town or City', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XL, + validators: [{ name: ValidatorNames.MaxLength, args: 60 }], + }, + { + name: 'techRecord_manufacturerDetails_address3', + label: 'County', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XL, + validators: [{ name: ValidatorNames.MaxLength, args: 60 }], + }, + { + name: 'techRecord_manufacturerDetails_postCode', + label: 'Postcode', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + validators: [{ name: ValidatorNames.MaxLength, args: 12 }], + }, + { + name: 'techRecord_manufacturerDetails_telephoneNumber', + label: 'Telephone number', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XL, + validators: [{ name: ValidatorNames.MaxLength, args: 25 }], + }, + { + name: 'techRecord_manufacturerDetails_emailAddress', + label: 'Email address', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XL, + validators: [{ name: ValidatorNames.MaxLength, args: 255 }, { name: ValidatorNames.Email }], + }, + { + name: 'techRecord_manufacturerDetails_faxNumber', + label: 'Fax Number', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XL, + validators: [{ name: ValidatorNames.MaxLength, args: 25 }], + }, + { + name: 'techRecord_manufacturerDetails_manufacturerNotes', + label: 'Manufacturer Notes', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXTAREA, + validators: [{ name: ValidatorNames.MaxLength, args: 1024 }], + }, + ], }; diff --git a/src/app/forms/templates/general/notes.template.ts b/src/app/forms/templates/general/notes.template.ts index a8121dc9a1..877fff80aa 100644 --- a/src/app/forms/templates/general/notes.template.ts +++ b/src/app/forms/templates/general/notes.template.ts @@ -1,19 +1,17 @@ import { ValidatorNames } from '@forms/models/validators.enum'; -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '../../services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '../../services/dynamic-form.types'; export const NotesTemplate: FormNode = { - name: 'notesSection', - label: 'Notes', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'techRecord_notes', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.FULLWIDTH, - editType: FormNodeEditTypes.TEXTAREA, - validators: [{ name: ValidatorNames.MaxLength, args: 1024 }], - }, - ], + name: 'notesSection', + label: 'Notes', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'techRecord_notes', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.FULLWIDTH, + editType: FormNodeEditTypes.TEXTAREA, + validators: [{ name: ValidatorNames.MaxLength, args: 1024 }], + }, + ], }; diff --git a/src/app/forms/templates/general/plates.template.ts b/src/app/forms/templates/general/plates.template.ts index 7a5b468d11..0d007a0669 100644 --- a/src/app/forms/templates/general/plates.template.ts +++ b/src/app/forms/templates/general/plates.template.ts @@ -1,58 +1,56 @@ import { getOptionsFromEnum } from '@forms/utils/enum-map'; import { PlateReasonForIssue } from '@models/vehicle-tech-record.model'; -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeWidth, -} from '../../services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeWidth } from '../../services/dynamic-form.types'; export const PlatesTemplate: FormNode = { - name: 'platesSection', - label: 'Plates', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'techRecord_plates', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'plateSerialNumber', - label: 'Plate serial number', - value: null, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - disabled: true, - }, - { - name: 'plateIssueDate', - label: 'Plate issue date', - value: null, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - disabled: true, - }, - { - name: 'plateReasonForIssue', - label: 'Plate reason for issue', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - options: getOptionsFromEnum(PlateReasonForIssue), - width: FormNodeWidth.L, - }, - { - name: 'plateIssuer', - label: 'Plate issuer', - value: null, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - disabled: true, - }, - ], - }, - ], - }, - ], + name: 'platesSection', + label: 'Plates', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'techRecord_plates', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'plateSerialNumber', + label: 'Plate serial number', + value: null, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + disabled: true, + }, + { + name: 'plateIssueDate', + label: 'Plate issue date', + value: null, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + disabled: true, + }, + { + name: 'plateReasonForIssue', + label: 'Plate reason for issue', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: getOptionsFromEnum(PlateReasonForIssue), + width: FormNodeWidth.L, + }, + { + name: 'plateIssuer', + label: 'Plate issuer', + value: null, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + disabled: true, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/general/reason-for-creation.template.ts b/src/app/forms/templates/general/reason-for-creation.template.ts index f20082f673..88bf70cd38 100644 --- a/src/app/forms/templates/general/reason-for-creation.template.ts +++ b/src/app/forms/templates/general/reason-for-creation.template.ts @@ -1,38 +1,41 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, - TagTypeLabels, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + TagTypeLabels, } from '@forms/services/dynamic-form.types'; import { TagType } from '@shared/components/tag/tag.component'; export const TechRecordReasonForCreationSection: FormNode = { - name: 'reasonForCreationSection', - label: 'Reason for creation', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'techRecord_reasonForCreation', - label: 'Reason for creation', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.TEXTAREA, - validators: [{ name: ValidatorNames.MaxLength, args: 500 }, { name: ValidatorNames.Required }], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - ], + name: 'reasonForCreationSection', + label: 'Reason for creation', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'techRecord_reasonForCreation', + label: 'Reason for creation', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.TEXTAREA, + validators: [{ name: ValidatorNames.MaxLength, args: 500 }, { name: ValidatorNames.Required }], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + ], }; export const TechRecordReasonForCreationHiddenSection: FormNode = { - name: 'requiredSection', - label: 'Reason for creation', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'techRecord_reasonForCreation', - label: 'Reason for creation', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - ], + name: 'requiredSection', + label: 'Reason for creation', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'techRecord_reasonForCreation', + label: 'Reason for creation', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + ], }; diff --git a/src/app/forms/templates/general/required-standards.template.ts b/src/app/forms/templates/general/required-standards.template.ts index beebdd561c..dcb9bda821 100644 --- a/src/app/forms/templates/general/required-standards.template.ts +++ b/src/app/forms/templates/general/required-standards.template.ts @@ -1,93 +1,93 @@ import { FormNode, FormNodeEditTypes, FormNodeTypes } from '@forms/services/dynamic-form.types'; export const RequiredStandardsTpl: FormNode = { - name: 'requiredStandards', - label: 'Required Standards', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'requiredStandards', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'sectionNumber', - label: 'Section number', - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'sectionDescription', - label: 'Section description', - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'rsNumber', - label: 'Required standard number', - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'requiredStandard', - label: 'Required standard description', - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'refCalculation', - label: 'Ref calculation', - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'additionalInfo', - label: 'Additional information', - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'inspectionTypes', - label: 'Inspection Types', - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'additionalNotes', - label: 'Notes', - value: null, - type: FormNodeTypes.CONTROL, - }, - { - name: 'prs', - label: 'PRS', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], + name: 'requiredStandards', + label: 'Required Standards', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'requiredStandards', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'sectionNumber', + label: 'Section number', + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'sectionDescription', + label: 'Section description', + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'rsNumber', + label: 'Required standard number', + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'requiredStandard', + label: 'Required standard description', + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'refCalculation', + label: 'Ref calculation', + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'additionalInfo', + label: 'Additional information', + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'inspectionTypes', + label: 'Inspection Types', + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'additionalNotes', + label: 'Notes', + value: null, + type: FormNodeTypes.CONTROL, + }, + { + name: 'prs', + label: 'PRS', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/hgv/hgv-dimensions.template.ts b/src/app/forms/templates/hgv/hgv-dimensions.template.ts index de3a2553ad..e65329446a 100644 --- a/src/app/forms/templates/hgv/hgv-dimensions.template.ts +++ b/src/app/forms/templates/hgv/hgv-dimensions.template.ts @@ -1,84 +1,82 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { TagType } from '@shared/components/tag/tag.component'; -import { - FormNode, FormNodeEditTypes, FormNodeTypes, TagTypeLabels, -} from '../../services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, TagTypeLabels } from '../../services/dynamic-form.types'; export const HgvDimensionsTemplate: FormNode = { - name: 'dimensionsSection', - label: 'Dimensions', - type: FormNodeTypes.SECTION, - children: [ - { - name: 'techRecord_dimensions_length', - label: 'Length (mm)', - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Max, args: 99999 }], - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_dimensions_width', - label: 'Width (mm)', - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Max, args: 99999 }], - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_dimensions_axleSpacing', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'value', - label: 'Axle to axle (mm)', - value: null, - editType: FormNodeEditTypes.NUMBER, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Max, args: 99999 }], - }, - ], - }, - ], - }, - { - name: 'techRecord_frontAxleToRearAxle', - label: 'Front axle to rear axle (mm)', - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Max, args: 99999 }], - }, - { - name: 'techRecord_frontVehicleTo5thWheelCouplingMin', - label: 'Minimum', - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Max, args: 99999 }], - }, - { - name: 'techRecord_frontVehicleTo5thWheelCouplingMax', - label: 'Maximum', - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Max, args: 99999 }], - }, - { - name: 'techRecord_frontAxleTo5thWheelMin', - label: 'Minimum', - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Max, args: 99999 }], - }, - { - name: 'techRecord_frontAxleTo5thWheelMax', - label: 'Maximum', - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Max, args: 99999 }], - }, - ], + name: 'dimensionsSection', + label: 'Dimensions', + type: FormNodeTypes.SECTION, + children: [ + { + name: 'techRecord_dimensions_length', + label: 'Length (mm)', + value: null, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Max, args: 99999 }], + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_dimensions_width', + label: 'Width (mm)', + value: null, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Max, args: 99999 }], + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_dimensions_axleSpacing', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'value', + label: 'Axle to axle (mm)', + value: null, + editType: FormNodeEditTypes.NUMBER, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Max, args: 99999 }], + }, + ], + }, + ], + }, + { + name: 'techRecord_frontAxleToRearAxle', + label: 'Front axle to rear axle (mm)', + value: null, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Max, args: 99999 }], + }, + { + name: 'techRecord_frontVehicleTo5thWheelCouplingMin', + label: 'Minimum', + value: null, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Max, args: 99999 }], + }, + { + name: 'techRecord_frontVehicleTo5thWheelCouplingMax', + label: 'Maximum', + value: null, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Max, args: 99999 }], + }, + { + name: 'techRecord_frontAxleTo5thWheelMin', + label: 'Minimum', + value: null, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Max, args: 99999 }], + }, + { + name: 'techRecord_frontAxleTo5thWheelMax', + label: 'Maximum', + value: null, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Max, args: 99999 }], + }, + ], }; diff --git a/src/app/forms/templates/hgv/hgv-tech-record.template.ts b/src/app/forms/templates/hgv/hgv-tech-record.template.ts index ca1eb60f57..33cf2e8a88 100644 --- a/src/app/forms/templates/hgv/hgv-tech-record.template.ts +++ b/src/app/forms/templates/hgv/hgv-tech-record.template.ts @@ -6,232 +6,239 @@ import { EmissionStandard } from '@models/test-types/emissions.enum'; import { FuelTypes } from '@models/vehicle-tech-record.model'; import { TagType } from '@shared/components/tag/tag.component'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, TagTypeLabels, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, + TagTypeLabels, } from '../../services/dynamic-form.types'; export const HgvTechRecord: FormNode = { - name: 'techRecordSummary', - type: FormNodeTypes.GROUP, - label: 'Vehicle Summary', - children: [ - { - name: 'techRecord_vehicleType', - label: 'Vehicle type', - value: '', - width: FormNodeWidth.XS, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.VEHICLETYPE, - disabled: true, - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_statusCode', - label: 'Record status', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_numberOfWheelsDriven', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'techRecord_regnDate', - label: 'Date of first registration', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - validators: [], - isoDate: false, - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_manufactureYear', - label: 'Year of manufacture', - value: null, - width: FormNodeWidth.XS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [ - { name: ValidatorNames.Max, args: 9999 }, - { name: ValidatorNames.Min, args: 1000 }, - { name: ValidatorNames.PastYear }, - ], - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_noOfAxles', - label: 'Number of axles', - value: null, - width: FormNodeWidth.XXS, - type: FormNodeTypes.CONTROL, - validators: [], - disabled: true, - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_speedLimiterMrk', - label: 'Speed limiter exempt', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Exempt' }, - { value: false, label: 'Not exempt' }, - ], - validators: [], - class: 'flex--half', - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_tachoExemptMrk', - label: 'Tacho exempt', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Exempt' }, - { value: false, label: 'Not exempt' }, - ], - validators: [], - class: 'flex--half', - }, - { - name: 'techRecord_euroStandard', - label: 'Euro standard', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [{ label: '0.10 g/kWh Euro III PM', value: '0.10 g/kWh Euro 3 PM' }, - ...getOptionsFromEnum(EmissionStandard), - ], - }, - { - name: 'techRecord_roadFriendly', - label: 'Road friendly suspension', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_fuelPropulsionSystem', - label: 'Fuel / propulsion system', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - options: getOptionsFromEnum(FuelTypes), - validators: [], - }, - { - name: 'techRecord_drawbarCouplingFitted', - label: 'Drawbar coupling fitted', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - }, - { - name: 'techRecord_vehicleClass_description', - label: 'Vehicle class', - value: '', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - options: [ - { label: 'heavy goods vehicle', value: 'heavy goods vehicle' }, - ], - validators: [{ name: ValidatorNames.Required }], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_vehicleConfiguration', - label: 'Vehicle configuration', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - options: getOptionsFromEnum(VehicleConfiguration), - validators: [{ name: ValidatorNames.UpdateFunctionCode }], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }, { colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_offRoad', - label: 'Off road vehicle', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - }, - { - name: 'techRecord_euVehicleCategory', - label: 'EU vehicle category', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - width: FormNodeWidth.S, - options: getOptionsFromEnum(EUVehicleCategory), - validators: [], - }, - { - name: 'techRecord_emissionsLimit', - label: 'Emission limit (m-1) (plate value)', - value: null, - width: FormNodeWidth.XXS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [ - { name: ValidatorNames.Max, args: 99 }, - { - name: ValidatorNames.CustomPattern, - args: ['^\\d*(\\.\\d{0,5})?$', 'Max 5 decimal places'], - }, - ], - enableDecimals: true, - }, - { - name: 'techRecord_departmentalVehicleMarker', - label: 'Departmental vehicle marker', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - }, - { - name: 'techRecord_alterationMarker', - label: 'Alteration marker', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - }, - { - name: 'techRecord_functionCode', - label: 'Function code', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], + name: 'techRecordSummary', + type: FormNodeTypes.GROUP, + label: 'Vehicle Summary', + children: [ + { + name: 'techRecord_vehicleType', + label: 'Vehicle type', + value: '', + width: FormNodeWidth.XS, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.VEHICLETYPE, + disabled: true, + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_statusCode', + label: 'Record status', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_numberOfWheelsDriven', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'techRecord_regnDate', + label: 'Date of first registration', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + validators: [], + isoDate: false, + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_manufactureYear', + label: 'Year of manufacture', + value: null, + width: FormNodeWidth.XS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [ + { name: ValidatorNames.Max, args: 9999 }, + { name: ValidatorNames.Min, args: 1000 }, + { name: ValidatorNames.PastYear }, + ], + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_noOfAxles', + label: 'Number of axles', + value: null, + width: FormNodeWidth.XXS, + type: FormNodeTypes.CONTROL, + validators: [], + disabled: true, + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_speedLimiterMrk', + label: 'Speed limiter exempt', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Exempt' }, + { value: false, label: 'Not exempt' }, + ], + validators: [], + class: 'flex--half', + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_tachoExemptMrk', + label: 'Tacho exempt', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Exempt' }, + { value: false, label: 'Not exempt' }, + ], + validators: [], + class: 'flex--half', + }, + { + name: 'techRecord_euroStandard', + label: 'Euro standard', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { label: '0.10 g/kWh Euro III PM', value: '0.10 g/kWh Euro 3 PM' }, + ...getOptionsFromEnum(EmissionStandard), + ], + }, + { + name: 'techRecord_roadFriendly', + label: 'Road friendly suspension', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_fuelPropulsionSystem', + label: 'Fuel / propulsion system', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: getOptionsFromEnum(FuelTypes), + validators: [], + }, + { + name: 'techRecord_drawbarCouplingFitted', + label: 'Drawbar coupling fitted', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + }, + { + name: 'techRecord_vehicleClass_description', + label: 'Vehicle class', + value: '', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: [{ label: 'heavy goods vehicle', value: 'heavy goods vehicle' }], + validators: [{ name: ValidatorNames.Required }], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_vehicleConfiguration', + label: 'Vehicle configuration', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: getOptionsFromEnum(VehicleConfiguration), + validators: [{ name: ValidatorNames.UpdateFunctionCode }], + customTags: [ + { colour: TagType.RED, label: TagTypeLabels.REQUIRED }, + { colour: TagType.PURPLE, label: TagTypeLabels.PLATES }, + ], + }, + { + name: 'techRecord_offRoad', + label: 'Off road vehicle', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + }, + { + name: 'techRecord_euVehicleCategory', + label: 'EU vehicle category', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + width: FormNodeWidth.S, + options: getOptionsFromEnum(EUVehicleCategory), + validators: [], + }, + { + name: 'techRecord_emissionsLimit', + label: 'Emission limit (m-1) (plate value)', + value: null, + width: FormNodeWidth.XXS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [ + { name: ValidatorNames.Max, args: 99 }, + { + name: ValidatorNames.CustomPattern, + args: ['^\\d*(\\.\\d{0,5})?$', 'Max 5 decimal places'], + }, + ], + enableDecimals: true, + }, + { + name: 'techRecord_departmentalVehicleMarker', + label: 'Departmental vehicle marker', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + }, + { + name: 'techRecord_alterationMarker', + label: 'Alteration marker', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + }, + { + name: 'techRecord_functionCode', + label: 'Function code', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], }; diff --git a/src/app/forms/templates/hgv/hgv-tyres.template.ts b/src/app/forms/templates/hgv/hgv-tyres.template.ts index c025cbc04c..70664e3d2d 100644 --- a/src/app/forms/templates/hgv/hgv-tyres.template.ts +++ b/src/app/forms/templates/hgv/hgv-tyres.template.ts @@ -1,98 +1,109 @@ import { TyreUseCode } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/tyreUseCodeHgv.enum.js'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, - FormNodeEditTypes, - FormNodeTypes, - FormNodeWidth, - TagTypeLabels, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeWidth, + TagTypeLabels, } from '@forms/services/dynamic-form.types'; import { getOptionsFromEnum } from '@forms/utils/enum-map'; import { TagType } from '@shared/components/tag/tag.component'; export const tyresTemplateHgv: FormNode = { - name: 'tyreSection', - type: FormNodeTypes.GROUP, - label: 'Tyres', - children: [ - { - name: 'techRecord_tyreUseCode', - label: 'Tyre use code', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - width: FormNodeWidth.UNSET, - options: getOptionsFromEnum(TyreUseCode), - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_axles', - value: '', - type: FormNodeTypes.ARRAY, - validators: [{ - name: ValidatorNames.MinArrayLengthIfNotEmpty, args: { minimumLength: 2, message: 'You cannot submit a HGV with less than 2 axles.' }, - }], - children: [ - { - name: '0', - label: 'Axle', - value: '', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'axleNumber', - label: 'Axle Number', - type: FormNodeTypes.CONTROL, - }, - { - name: 'tyres_tyreCode', - label: 'Tyre Code', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [{ name: ValidatorNames.Numeric }, { name: ValidatorNames.Max, args: 99999 }, { name: ValidatorNames.Min, args: 0 }], - }, - { - name: 'tyres_tyreSize', - label: 'Tyre Size', - value: null, - type: FormNodeTypes.CONTROL, - disabled: true, - validators: [ - { name: ValidatorNames.MaxLength, args: 12 }, - { name: ValidatorNames.Min, args: 0 }, - ], - }, - { - name: 'tyres_plyRating', - label: 'Ply Rating', - value: null, - type: FormNodeTypes.CONTROL, - disabled: true, - validators: [ - { name: ValidatorNames.MaxLength, args: 2 }, - { name: ValidatorNames.Min, args: 0 }, - ], - }, - { - name: 'tyres_fitmentCode', - label: 'Fitment code', - value: null, - type: FormNodeTypes.CONTROL, - validators: [], - }, - { - name: 'tyres_dataTrAxles', - label: 'Load index', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - disabled: true, - validators: [{ name: ValidatorNames.Numeric }, { name: ValidatorNames.Max, args: 999 }, { name: ValidatorNames.Min, args: 0 }], - }, - ], - }, - ], - }, - ], + name: 'tyreSection', + type: FormNodeTypes.GROUP, + label: 'Tyres', + children: [ + { + name: 'techRecord_tyreUseCode', + label: 'Tyre use code', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + width: FormNodeWidth.UNSET, + options: getOptionsFromEnum(TyreUseCode), + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_axles', + value: '', + type: FormNodeTypes.ARRAY, + validators: [ + { + name: ValidatorNames.MinArrayLengthIfNotEmpty, + args: { minimumLength: 2, message: 'You cannot submit a HGV with less than 2 axles.' }, + }, + ], + children: [ + { + name: '0', + label: 'Axle', + value: '', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'axleNumber', + label: 'Axle Number', + type: FormNodeTypes.CONTROL, + }, + { + name: 'tyres_tyreCode', + label: 'Tyre Code', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [ + { name: ValidatorNames.Numeric }, + { name: ValidatorNames.Max, args: 99999 }, + { name: ValidatorNames.Min, args: 0 }, + ], + }, + { + name: 'tyres_tyreSize', + label: 'Tyre Size', + value: null, + type: FormNodeTypes.CONTROL, + disabled: true, + validators: [ + { name: ValidatorNames.MaxLength, args: 12 }, + { name: ValidatorNames.Min, args: 0 }, + ], + }, + { + name: 'tyres_plyRating', + label: 'Ply Rating', + value: null, + type: FormNodeTypes.CONTROL, + disabled: true, + validators: [ + { name: ValidatorNames.MaxLength, args: 2 }, + { name: ValidatorNames.Min, args: 0 }, + ], + }, + { + name: 'tyres_fitmentCode', + label: 'Fitment code', + value: null, + type: FormNodeTypes.CONTROL, + validators: [], + }, + { + name: 'tyres_dataTrAxles', + label: 'Load index', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + disabled: true, + validators: [ + { name: ValidatorNames.Numeric }, + { name: ValidatorNames.Max, args: 999 }, + { name: ValidatorNames.Min, args: 0 }, + ], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/hgv/hgv-weight.template.ts b/src/app/forms/templates/hgv/hgv-weight.template.ts index 12d02ef858..9fa08e91d6 100644 --- a/src/app/forms/templates/hgv/hgv-weight.template.ts +++ b/src/app/forms/templates/hgv/hgv-weight.template.ts @@ -1,179 +1,177 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { TagType } from '@shared/components/tag/tag.component'; -import { - FormNode, FormNodeEditTypes, FormNodeTypes, TagTypeLabels, -} from '../../services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, TagTypeLabels } from '../../services/dynamic-form.types'; const requiredValidation = [ - { name: ValidatorNames.Numeric, args: 99999 }, - { name: ValidatorNames.Max, args: 99999 }, - { name: ValidatorNames.Min, args: 0 }, + { name: ValidatorNames.Numeric, args: 99999 }, + { name: ValidatorNames.Max, args: 99999 }, + { name: ValidatorNames.Min, args: 0 }, ]; const optionalValidation = [ - { name: ValidatorNames.Numeric, args: 99999 }, - { name: ValidatorNames.Max, args: 99999 }, - { name: ValidatorNames.Min, args: 0 }, + { name: ValidatorNames.Numeric, args: 99999 }, + { name: ValidatorNames.Max, args: 99999 }, + { name: ValidatorNames.Min, args: 0 }, ]; export const HgvWeight: FormNode = { - name: 'weightsSection', - label: 'Weights', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'grossSection', - label: 'Gross vehicle weight', - value: '', - type: FormNodeTypes.SECTION, - }, - { - name: 'techRecord_grossGbWeight', - label: 'GB', - customValidatorErrorName: 'Gross GB Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_grossEecWeight', - label: 'EEC (optional)', - customValidatorErrorName: 'Gross EEC Weight', - value: null, - editType: FormNodeEditTypes.NUMBER, - type: FormNodeTypes.CONTROL, - validators: optionalValidation, - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_grossDesignWeight', - label: 'Design', - customValidatorErrorName: 'Gross Design Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'grossTrainSection', - label: 'Gross train weight', - value: null, - type: FormNodeTypes.SECTION, - }, - { - name: 'techRecord_trainGbWeight', - label: 'GB', - customValidatorErrorName: 'Train GB Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_trainEecWeight', - label: 'EEC (optional)', - customValidatorErrorName: 'Train EEC Weight', - value: null, - editType: FormNodeEditTypes.NUMBER, - type: FormNodeTypes.CONTROL, - validators: optionalValidation, - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_trainDesignWeight', - label: 'Design (optional)', - customValidatorErrorName: 'Train Design Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: optionalValidation, - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'maxTrainSection', - label: 'Max train weight', - value: null, - type: FormNodeTypes.SECTION, - }, - { - name: 'techRecord_maxTrainGbWeight', - label: 'GB', - customValidatorErrorName: 'Max Train GB Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_maxTrainEecWeight', - label: 'EEC (optional)', - customValidatorErrorName: 'Max Train EEC Weight', - value: null, - editType: FormNodeEditTypes.NUMBER, - type: FormNodeTypes.CONTROL, - validators: optionalValidation, - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_maxTrainDesignWeight', - label: 'Design (optional)', - customValidatorErrorName: 'Max Train Design Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: optionalValidation, - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'axleSection', - label: 'Axle weights', - value: '', - type: FormNodeTypes.SECTION, - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_axles', - value: '', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', - label: 'Axle', - value: '', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'axleNumber', - label: 'Axle Number', - type: FormNodeTypes.CONTROL, - }, - { - name: 'weights_gbWeight', - label: 'GB weight', - customValidatorErrorName: 'Axle GB Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - }, - { - name: 'weights_eecWeight', - label: 'EEC (optional)', - customValidatorErrorName: 'Axle EEC Weight', - value: null, - editType: FormNodeEditTypes.NUMBER, - type: FormNodeTypes.CONTROL, - validators: optionalValidation, - }, - { - name: 'weights_designWeight', - label: 'Design weight', - customValidatorErrorName: 'Axle Design Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - }, - ], - }, - ], - }, - ], + name: 'weightsSection', + label: 'Weights', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'grossSection', + label: 'Gross vehicle weight', + value: '', + type: FormNodeTypes.SECTION, + }, + { + name: 'techRecord_grossGbWeight', + label: 'GB', + customValidatorErrorName: 'Gross GB Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_grossEecWeight', + label: 'EEC (optional)', + customValidatorErrorName: 'Gross EEC Weight', + value: null, + editType: FormNodeEditTypes.NUMBER, + type: FormNodeTypes.CONTROL, + validators: optionalValidation, + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_grossDesignWeight', + label: 'Design', + customValidatorErrorName: 'Gross Design Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'grossTrainSection', + label: 'Gross train weight', + value: null, + type: FormNodeTypes.SECTION, + }, + { + name: 'techRecord_trainGbWeight', + label: 'GB', + customValidatorErrorName: 'Train GB Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_trainEecWeight', + label: 'EEC (optional)', + customValidatorErrorName: 'Train EEC Weight', + value: null, + editType: FormNodeEditTypes.NUMBER, + type: FormNodeTypes.CONTROL, + validators: optionalValidation, + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_trainDesignWeight', + label: 'Design (optional)', + customValidatorErrorName: 'Train Design Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: optionalValidation, + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'maxTrainSection', + label: 'Max train weight', + value: null, + type: FormNodeTypes.SECTION, + }, + { + name: 'techRecord_maxTrainGbWeight', + label: 'GB', + customValidatorErrorName: 'Max Train GB Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_maxTrainEecWeight', + label: 'EEC (optional)', + customValidatorErrorName: 'Max Train EEC Weight', + value: null, + editType: FormNodeEditTypes.NUMBER, + type: FormNodeTypes.CONTROL, + validators: optionalValidation, + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_maxTrainDesignWeight', + label: 'Design (optional)', + customValidatorErrorName: 'Max Train Design Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: optionalValidation, + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'axleSection', + label: 'Axle weights', + value: '', + type: FormNodeTypes.SECTION, + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_axles', + value: '', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + label: 'Axle', + value: '', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'axleNumber', + label: 'Axle Number', + type: FormNodeTypes.CONTROL, + }, + { + name: 'weights_gbWeight', + label: 'GB weight', + customValidatorErrorName: 'Axle GB Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + }, + { + name: 'weights_eecWeight', + label: 'EEC (optional)', + customValidatorErrorName: 'Axle EEC Weight', + value: null, + editType: FormNodeEditTypes.NUMBER, + type: FormNodeTypes.CONTROL, + validators: optionalValidation, + }, + { + name: 'weights_designWeight', + label: 'Design weight', + customValidatorErrorName: 'Axle Design Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/lgv/lgv-tech-record.template.ts b/src/app/forms/templates/lgv/lgv-tech-record.template.ts index 2c12a75724..657f282f8e 100644 --- a/src/app/forms/templates/lgv/lgv-tech-record.template.ts +++ b/src/app/forms/templates/lgv/lgv-tech-record.template.ts @@ -2,98 +2,103 @@ import { EUVehicleCategory } from '@dvsa/cvs-type-definitions/types/v3/tech-reco import { VehicleConfiguration } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleConfigurationLightVehicle.enum.js'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, TagTypeLabels, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, + TagTypeLabels, } from '@forms/services/dynamic-form.types'; import { getOptionsFromEnum } from '@forms/utils/enum-map'; import { VehicleSubclass } from '@models/vehicle-tech-record.model'; import { TagType } from '@shared/components/tag/tag.component'; export const LgvTechRecord: FormNode = { - name: 'techRecordSummary', - type: FormNodeTypes.GROUP, - label: 'Vehicle Summary', - children: [ - { - name: 'techRecord_vehicleType', - label: 'Vehicle type', - value: '', - width: FormNodeWidth.XS, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.VEHICLETYPE, - disabled: true, - validators: [], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_statusCode', - label: 'Record status', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_regnDate', - label: 'Date of first registration', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - validators: [], - isoDate: false, - }, - { - name: 'techRecord_manufactureYear', - label: 'Year of manufacture', - value: null, - width: FormNodeWidth.XS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [ - { name: ValidatorNames.Max, args: 9999 }, - { name: ValidatorNames.Min, args: 1000 }, - { name: ValidatorNames.PastYear }, - ], - }, - { - name: 'techRecord_noOfAxles', - label: 'Number of axles', - width: FormNodeWidth.XXS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - value: 2, - validators: [{ name: ValidatorNames.Max, args: 99 }], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_vehicleSubclass', - label: 'Vehicle Subclass', - width: FormNodeWidth.XXS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CHECKBOXGROUP, - options: getOptionsFromEnum(VehicleSubclass), - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_vehicleConfiguration', - label: 'Vehicle configuration', - value: VehicleConfiguration.OTHER, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - options: getOptionsFromEnum(VehicleConfiguration), - validators: [{ name: ValidatorNames.Required }], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_euVehicleCategory', - label: 'EU vehicle category', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - width: FormNodeWidth.S, - options: getOptionsFromEnum(EUVehicleCategory), - validators: [], - }, - ], + name: 'techRecordSummary', + type: FormNodeTypes.GROUP, + label: 'Vehicle Summary', + children: [ + { + name: 'techRecord_vehicleType', + label: 'Vehicle type', + value: '', + width: FormNodeWidth.XS, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.VEHICLETYPE, + disabled: true, + validators: [], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_statusCode', + label: 'Record status', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_regnDate', + label: 'Date of first registration', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + validators: [], + isoDate: false, + }, + { + name: 'techRecord_manufactureYear', + label: 'Year of manufacture', + value: null, + width: FormNodeWidth.XS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [ + { name: ValidatorNames.Max, args: 9999 }, + { name: ValidatorNames.Min, args: 1000 }, + { name: ValidatorNames.PastYear }, + ], + }, + { + name: 'techRecord_noOfAxles', + label: 'Number of axles', + width: FormNodeWidth.XXS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + value: 2, + validators: [{ name: ValidatorNames.Max, args: 99 }], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_vehicleSubclass', + label: 'Vehicle Subclass', + width: FormNodeWidth.XXS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CHECKBOXGROUP, + options: getOptionsFromEnum(VehicleSubclass), + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_vehicleConfiguration', + label: 'Vehicle configuration', + value: VehicleConfiguration.OTHER, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: getOptionsFromEnum(VehicleConfiguration), + validators: [{ name: ValidatorNames.Required }], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_euVehicleCategory', + label: 'EU vehicle category', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + width: FormNodeWidth.S, + options: getOptionsFromEnum(EUVehicleCategory), + validators: [], + }, + ], }; diff --git a/src/app/forms/templates/motorcycle/motorcycle-tech-record.template.ts b/src/app/forms/templates/motorcycle/motorcycle-tech-record.template.ts index be8854368f..d17d4a31f7 100644 --- a/src/app/forms/templates/motorcycle/motorcycle-tech-record.template.ts +++ b/src/app/forms/templates/motorcycle/motorcycle-tech-record.template.ts @@ -2,122 +2,133 @@ import { EUVehicleCategory } from '@dvsa/cvs-type-definitions/types/v3/tech-reco import { VehicleConfiguration } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleConfigurationLightVehicle.enum.js'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, TagTypeLabels, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, + TagTypeLabels, } from '@forms/services/dynamic-form.types'; import { getOptionsFromEnum } from '@forms/utils/enum-map'; import { TagType } from '@shared/components/tag/tag.component'; export const MotorcycleTechRecord: FormNode = { - name: 'techRecordSummary', - type: FormNodeTypes.GROUP, - label: 'Vehicle Summary', - children: [ - { - name: 'techRecord_vehicleType', - label: 'Vehicle type', - value: '', - width: FormNodeWidth.M, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.VEHICLETYPE, - disabled: true, - validators: [], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_statusCode', - label: 'Record status', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_regnDate', - label: 'Date of first registration', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - validators: [], - isoDate: false, - }, - { - name: 'techRecord_manufactureYear', - label: 'Year of manufacture', - value: null, - width: FormNodeWidth.XS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [ - { name: ValidatorNames.Max, args: 9999 }, - { name: ValidatorNames.Min, args: 1000 }, - { name: ValidatorNames.PastYear }, - ], - }, - { - name: 'techRecord_noOfAxles', - label: 'Number of axles', - width: FormNodeWidth.XXS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - value: 2, - validators: [{ name: ValidatorNames.Max, args: 99 }], - }, - { - name: 'techRecord_vehicleClass_description', - label: 'Vehicle class', - value: '', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - editType: FormNodeEditTypes.SELECT, - options: [ - { label: 'motorbikes over 200cc or with a sidecar', value: 'motorbikes over 200cc or with a sidecar' }, - { label: 'not applicable', value: 'not applicable' }, - { label: 'small psv (ie: less than or equal to 22 passengers)', value: 'small psv (ie: less than or equal to 22 seats)' }, - { label: 'motorbikes up to 200cc', value: 'motorbikes up to 200cc' }, - { label: 'trailer', value: 'trailer' }, - { label: 'large psv(ie: greater than or equal to 23 passengers)', value: 'large psv(ie: greater than 23 seats)' }, - { label: '3 wheelers', value: '3 wheelers' }, - { label: 'heavy goods vehicle', value: 'heavy goods vehicle' }, - { label: 'MOT class 4', value: 'MOT class 4' }, - { label: 'MOT class 7', value: 'MOT class 7' }, - { label: 'MOT class 5', value: 'MOT class 5' }, - ], - class: '.govuk-input--width-10', - validators: [{ name: ValidatorNames.Required }], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_vehicleConfiguration', - label: 'Vehicle configuration', - value: VehicleConfiguration.OTHER, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - options: getOptionsFromEnum(VehicleConfiguration), - validators: [{ name: ValidatorNames.Required }], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_euVehicleCategory', - label: 'EU vehicle category', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - width: FormNodeWidth.S, - options: getOptionsFromEnum(EUVehicleCategory), - validators: [], - }, - { - name: 'techRecord_numberOfWheelsDriven', - label: 'Number of wheels', - value: null, - width: FormNodeWidth.XXS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [{ name: ValidatorNames.Max, args: 9999 }], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - ], + name: 'techRecordSummary', + type: FormNodeTypes.GROUP, + label: 'Vehicle Summary', + children: [ + { + name: 'techRecord_vehicleType', + label: 'Vehicle type', + value: '', + width: FormNodeWidth.M, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.VEHICLETYPE, + disabled: true, + validators: [], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_statusCode', + label: 'Record status', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_regnDate', + label: 'Date of first registration', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + validators: [], + isoDate: false, + }, + { + name: 'techRecord_manufactureYear', + label: 'Year of manufacture', + value: null, + width: FormNodeWidth.XS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [ + { name: ValidatorNames.Max, args: 9999 }, + { name: ValidatorNames.Min, args: 1000 }, + { name: ValidatorNames.PastYear }, + ], + }, + { + name: 'techRecord_noOfAxles', + label: 'Number of axles', + width: FormNodeWidth.XXS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + value: 2, + validators: [{ name: ValidatorNames.Max, args: 99 }], + }, + { + name: 'techRecord_vehicleClass_description', + label: 'Vehicle class', + value: '', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.SELECT, + options: [ + { label: 'motorbikes over 200cc or with a sidecar', value: 'motorbikes over 200cc or with a sidecar' }, + { label: 'not applicable', value: 'not applicable' }, + { + label: 'small psv (ie: less than or equal to 22 passengers)', + value: 'small psv (ie: less than or equal to 22 seats)', + }, + { label: 'motorbikes up to 200cc', value: 'motorbikes up to 200cc' }, + { label: 'trailer', value: 'trailer' }, + { + label: 'large psv(ie: greater than or equal to 23 passengers)', + value: 'large psv(ie: greater than 23 seats)', + }, + { label: '3 wheelers', value: '3 wheelers' }, + { label: 'heavy goods vehicle', value: 'heavy goods vehicle' }, + { label: 'MOT class 4', value: 'MOT class 4' }, + { label: 'MOT class 7', value: 'MOT class 7' }, + { label: 'MOT class 5', value: 'MOT class 5' }, + ], + class: '.govuk-input--width-10', + validators: [{ name: ValidatorNames.Required }], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_vehicleConfiguration', + label: 'Vehicle configuration', + value: VehicleConfiguration.OTHER, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: getOptionsFromEnum(VehicleConfiguration), + validators: [{ name: ValidatorNames.Required }], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_euVehicleCategory', + label: 'EU vehicle category', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + width: FormNodeWidth.S, + options: getOptionsFromEnum(EUVehicleCategory), + validators: [], + }, + { + name: 'techRecord_numberOfWheelsDriven', + label: 'Number of wheels', + value: null, + width: FormNodeWidth.XXS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [{ name: ValidatorNames.Max, args: 9999 }], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + ], }; diff --git a/src/app/forms/templates/psv/psv-approval-type.template.ts b/src/app/forms/templates/psv/psv-approval-type.template.ts index 74bc2fbe9f..53e053b6f4 100644 --- a/src/app/forms/templates/psv/psv-approval-type.template.ts +++ b/src/app/forms/templates/psv/psv-approval-type.template.ts @@ -2,99 +2,103 @@ import { ApprovalType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/en import { ValidatorNames } from '@forms/models/validators.enum'; import { getOptionsFromEnum } from '@forms/utils/enum-map'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '../../services/dynamic-form.types'; export const PsvTypeApprovalTemplate: FormNode = { - name: 'approvalSection', - label: 'Type approval', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'techRecord_approvalType', - label: 'Approval type', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - options: getOptionsFromEnum(ApprovalType), - validators: [{ name: ValidatorNames.IsMemberOfEnum, args: { enum: ApprovalType, options: { allowFalsy: true } } }], - }, - { - name: 'techRecord_approvalTypeNumber', - label: 'Approval type number', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XL, - validators: [ - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'techRecord_approvalType', - value: [ - 'NTA', - 'ECTA', - 'ECSSTA', - 'IVA', - 'NSSTA', - 'GB WVTA', - 'UKNI WVTA', - 'EU WVTA Pre 23', - 'EU WVTA 23 on', - 'QNIG', - 'Prov.GB WVTA', - 'Small series NKSXX', - 'Small series NKS', - 'IVA - VCA', - 'IVA - DVSA/NI', - ], - }, - }, - ], - }, - { - name: 'techRecord_ntaNumber', - label: 'National type number', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XL, - validators: [{ name: ValidatorNames.MaxLength, args: 40 }], - }, - { - name: 'techRecord_coifSerialNumber', - label: 'COIF Serial number', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.M, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }], - }, - { - name: 'techRecord_coifCertifierName', - label: 'COIF Certifier name', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XL, - validators: [{ name: ValidatorNames.MaxLength, args: 20 }], - }, - { - name: 'techRecord_coifDate', - label: 'COIF Certifier date', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - validators: [ - { name: ValidatorNames.PastDate }, - ], - isoDate: false, - }, - { - name: 'techRecord_variantNumber', - label: 'Variant number', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XL, - validators: [{ name: ValidatorNames.MaxLength, args: 25 }], - }, - { - name: 'techRecord_variantVersionNumber', - label: 'Variant version number', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XL, - validators: [{ name: ValidatorNames.MaxLength, args: 35 }], - }, - ], + name: 'approvalSection', + label: 'Type approval', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'techRecord_approvalType', + label: 'Approval type', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: getOptionsFromEnum(ApprovalType), + validators: [ + { name: ValidatorNames.IsMemberOfEnum, args: { enum: ApprovalType, options: { allowFalsy: true } } }, + ], + }, + { + name: 'techRecord_approvalTypeNumber', + label: 'Approval type number', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XL, + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'techRecord_approvalType', + value: [ + 'NTA', + 'ECTA', + 'ECSSTA', + 'IVA', + 'NSSTA', + 'GB WVTA', + 'UKNI WVTA', + 'EU WVTA Pre 23', + 'EU WVTA 23 on', + 'QNIG', + 'Prov.GB WVTA', + 'Small series NKSXX', + 'Small series NKS', + 'IVA - VCA', + 'IVA - DVSA/NI', + ], + }, + }, + ], + }, + { + name: 'techRecord_ntaNumber', + label: 'National type number', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XL, + validators: [{ name: ValidatorNames.MaxLength, args: 40 }], + }, + { + name: 'techRecord_coifSerialNumber', + label: 'COIF Serial number', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.M, + validators: [{ name: ValidatorNames.MaxLength, args: 8 }], + }, + { + name: 'techRecord_coifCertifierName', + label: 'COIF Certifier name', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XL, + validators: [{ name: ValidatorNames.MaxLength, args: 20 }], + }, + { + name: 'techRecord_coifDate', + label: 'COIF Certifier date', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + validators: [{ name: ValidatorNames.PastDate }], + isoDate: false, + }, + { + name: 'techRecord_variantNumber', + label: 'Variant number', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XL, + validators: [{ name: ValidatorNames.MaxLength, args: 25 }], + }, + { + name: 'techRecord_variantVersionNumber', + label: 'Variant version number', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XL, + validators: [{ name: ValidatorNames.MaxLength, args: 35 }], + }, + ], }; diff --git a/src/app/forms/templates/psv/psv-body.template.ts b/src/app/forms/templates/psv/psv-body.template.ts index 0e233c7a38..3e9451eac8 100644 --- a/src/app/forms/templates/psv/psv-body.template.ts +++ b/src/app/forms/templates/psv/psv-body.template.ts @@ -1,98 +1,107 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { TagType } from '@shared/components/tag/tag.component'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeWidth, TagTypeLabels, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeWidth, + TagTypeLabels, } from '../../services/dynamic-form.types'; export const PsvBodyTemplate: FormNode = { - name: 'bodySection', - label: 'Body', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'techRecord_brakes_dtpNumber', - label: 'DTP number', - value: null, - width: FormNodeWidth.S, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.AUTOCOMPLETE, - validators: [{ name: ValidatorNames.Required }], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_modelLiteral', - label: 'Model literal', - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 30 }], - }, - { - name: 'techRecord_chassisMake', - label: 'Chassis make', - value: '', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 30 }], - disabled: true, - }, - { - name: 'techRecord_chassisModel', - label: 'Chassis model', - value: '', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 20 }], - disabled: true, - }, - { - name: 'techRecord_bodyMake', - label: 'Body make', - value: '', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 20 }], - disabled: true, - }, - { - name: 'techRecord_bodyModel', - label: 'Body model', - value: '', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 20 }], - }, - { - name: 'techRecord_bodyType_description', - label: 'Body type', - value: '', - customId: 'bodyType', - type: FormNodeTypes.CONTROL, - disabled: true, - validators: [{ name: ValidatorNames.Required }], - }, - { - name: 'techRecord_functionCode', - label: 'Function code', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - options: [ - { value: 'r', label: 'R' }, - { value: 'a', label: 'A' }, - ], - validators: [{ name: ValidatorNames.MaxLength, args: 1 }], - }, - { - name: 'techRecord_conversionRefNo', - label: 'Conversion ref no', - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.CustomPattern, args: ['^[A-Z0-9 ]{0,10}$', 'max length 10 uppercase letters or numbers'] }], - }, - { - name: 'techRecord_modelLiteral', - label: 'Model literal', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.MaxLength, args: 30 }], - width: FormNodeWidth.L, - }, - ], + name: 'bodySection', + label: 'Body', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'techRecord_brakes_dtpNumber', + label: 'DTP number', + value: null, + width: FormNodeWidth.S, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.AUTOCOMPLETE, + validators: [{ name: ValidatorNames.Required }], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_modelLiteral', + label: 'Model literal', + value: null, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 30 }], + }, + { + name: 'techRecord_chassisMake', + label: 'Chassis make', + value: '', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 30 }], + disabled: true, + }, + { + name: 'techRecord_chassisModel', + label: 'Chassis model', + value: '', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 20 }], + disabled: true, + }, + { + name: 'techRecord_bodyMake', + label: 'Body make', + value: '', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 20 }], + disabled: true, + }, + { + name: 'techRecord_bodyModel', + label: 'Body model', + value: '', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 20 }], + }, + { + name: 'techRecord_bodyType_description', + label: 'Body type', + value: '', + customId: 'bodyType', + type: FormNodeTypes.CONTROL, + disabled: true, + validators: [{ name: ValidatorNames.Required }], + }, + { + name: 'techRecord_functionCode', + label: 'Function code', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: [ + { value: 'r', label: 'R' }, + { value: 'a', label: 'A' }, + ], + validators: [{ name: ValidatorNames.MaxLength, args: 1 }], + }, + { + name: 'techRecord_conversionRefNo', + label: 'Conversion ref no', + value: null, + type: FormNodeTypes.CONTROL, + validators: [ + { + name: ValidatorNames.CustomPattern, + args: ['^[A-Z0-9 ]{0,10}$', 'max length 10 uppercase letters or numbers'], + }, + ], + }, + { + name: 'techRecord_modelLiteral', + label: 'Model literal', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.MaxLength, args: 30 }], + width: FormNodeWidth.L, + }, + ], }; diff --git a/src/app/forms/templates/psv/psv-brakes.template.ts b/src/app/forms/templates/psv/psv-brakes.template.ts index a006bc67e7..ce7ecfdf1e 100644 --- a/src/app/forms/templates/psv/psv-brakes.template.ts +++ b/src/app/forms/templates/psv/psv-brakes.template.ts @@ -2,82 +2,82 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { FormNode, FormNodeTypes } from '../../services/dynamic-form.types'; export const PsvBrakesTemplate: FormNode = { - name: 'psvBrakesSection', - label: 'Brakes', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'techRecord_brakes_brakeCodeOriginal', - label: 'Brake code', - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 6 }], - }, - { - name: 'techRecord_brakes_brakeCode', - label: 'Brake code', - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 6 }], - }, - { - name: 'techRecord_brakes_dataTrBrakeOne', - label: 'Service *', - value: null, - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'techRecord_brakes_dataTrBrakeTwo', - label: 'Secondary *', - value: null, - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'techRecord_brakes_dataTrBrakeThree', - label: 'Parking *', - value: null, - type: FormNodeTypes.CONTROL, - disabled: true, - }, - { - name: 'techRecord_brakes_retarderBrakeOne', - label: 'Retarder 1', - value: null, - type: FormNodeTypes.CONTROL, - }, - { - name: 'techRecord_brakes_retarderBrakeTwo', - label: 'Retarder 2', - value: null, - type: FormNodeTypes.CONTROL, - }, - { - name: 'techRecord_axles', - value: '', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', - label: 'Axle', - value: '', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'axleNumber', - label: 'Axle Number', - type: FormNodeTypes.CONTROL, - }, - { - name: 'parkingBrakeMrk', - label: 'Parking Brake', - value: false, - type: FormNodeTypes.CONTROL, - }, - ], - }, - ], - }, - ], + name: 'psvBrakesSection', + label: 'Brakes', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'techRecord_brakes_brakeCodeOriginal', + label: 'Brake code', + value: null, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 6 }], + }, + { + name: 'techRecord_brakes_brakeCode', + label: 'Brake code', + value: null, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 6 }], + }, + { + name: 'techRecord_brakes_dataTrBrakeOne', + label: 'Service *', + value: null, + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'techRecord_brakes_dataTrBrakeTwo', + label: 'Secondary *', + value: null, + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'techRecord_brakes_dataTrBrakeThree', + label: 'Parking *', + value: null, + type: FormNodeTypes.CONTROL, + disabled: true, + }, + { + name: 'techRecord_brakes_retarderBrakeOne', + label: 'Retarder 1', + value: null, + type: FormNodeTypes.CONTROL, + }, + { + name: 'techRecord_brakes_retarderBrakeTwo', + label: 'Retarder 2', + value: null, + type: FormNodeTypes.CONTROL, + }, + { + name: 'techRecord_axles', + value: '', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + label: 'Axle', + value: '', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'axleNumber', + label: 'Axle Number', + type: FormNodeTypes.CONTROL, + }, + { + name: 'parkingBrakeMrk', + label: 'Parking Brake', + value: false, + type: FormNodeTypes.CONTROL, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/psv/psv-dda.template.ts b/src/app/forms/templates/psv/psv-dda.template.ts index 147fe404da..943ddfa05c 100644 --- a/src/app/forms/templates/psv/psv-dda.template.ts +++ b/src/app/forms/templates/psv/psv-dda.template.ts @@ -2,105 +2,105 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { FormNode, FormNodeEditTypes, FormNodeTypes } from '../../services/dynamic-form.types'; export const PsvDdaTemplate: FormNode = { - name: 'dda', - type: FormNodeTypes.GROUP, - label: 'Disability Discrimination Act', - children: [ - { - name: 'techRecord_dda_certificateIssued', - label: 'DDA certificate issued', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - { value: null, label: 'I do not know' }, - ], - }, - { - name: 'techRecord_dda_wheelchairCapacity', - label: 'Wheelchair capacity', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [{ name: ValidatorNames.Max, args: 99 }], - }, - { - name: 'techRecord_dda_wheelchairFittings', - label: 'Wheelchair fittings', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXTAREA, - validators: [{ name: ValidatorNames.MaxLength, args: 250 }], - }, - { - name: 'techRecord_dda_wheelchairLiftPresent', - label: 'Wheelchair lift present', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - { value: null, label: 'I do not know' }, - ], - }, - { - name: 'techRecord_dda_wheelchairLiftInformation', - label: 'Wheelchair lift information', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXTAREA, - validators: [{ name: ValidatorNames.MaxLength, args: 250 }], - }, - { - name: 'techRecord_dda_wheelchairRampPresent', - label: 'Wheelchair ramp present', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - { value: null, label: 'I do not know' }, - ], - }, - { - name: 'techRecord_dda_wheelchairRampInformation', - label: 'Wheelchair ramp information', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXTAREA, - validators: [{ name: ValidatorNames.MaxLength, args: 250 }], - }, - { - name: 'techRecord_dda_minEmergencyExits', - label: 'Minimum emergency exits needed', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [{ name: ValidatorNames.Max, args: 99 }], - }, - { - name: 'techRecord_dda_outswing', - label: 'Outswing', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXTAREA, - validators: [{ name: ValidatorNames.MaxLength, args: 250 }], - }, - { - name: 'techRecord_dda_ddaSchedules', - label: 'DDA schedules', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXTAREA, - validators: [{ name: ValidatorNames.MaxLength, args: 250 }], - }, - { - name: 'techRecord_dda_seatbeltsFitted', - label: 'Seatbelts fitted', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [{ name: ValidatorNames.Max, args: 999 }], - }, - { - name: 'techRecord_dda_ddaNotes', - label: 'DDA notes', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXTAREA, - validators: [{ name: ValidatorNames.MaxLength, args: 1024 }], - }, - ], + name: 'dda', + type: FormNodeTypes.GROUP, + label: 'Disability Discrimination Act', + children: [ + { + name: 'techRecord_dda_certificateIssued', + label: 'DDA certificate issued', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + { value: null, label: 'I do not know' }, + ], + }, + { + name: 'techRecord_dda_wheelchairCapacity', + label: 'Wheelchair capacity', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [{ name: ValidatorNames.Max, args: 99 }], + }, + { + name: 'techRecord_dda_wheelchairFittings', + label: 'Wheelchair fittings', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXTAREA, + validators: [{ name: ValidatorNames.MaxLength, args: 250 }], + }, + { + name: 'techRecord_dda_wheelchairLiftPresent', + label: 'Wheelchair lift present', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + { value: null, label: 'I do not know' }, + ], + }, + { + name: 'techRecord_dda_wheelchairLiftInformation', + label: 'Wheelchair lift information', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXTAREA, + validators: [{ name: ValidatorNames.MaxLength, args: 250 }], + }, + { + name: 'techRecord_dda_wheelchairRampPresent', + label: 'Wheelchair ramp present', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + { value: null, label: 'I do not know' }, + ], + }, + { + name: 'techRecord_dda_wheelchairRampInformation', + label: 'Wheelchair ramp information', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXTAREA, + validators: [{ name: ValidatorNames.MaxLength, args: 250 }], + }, + { + name: 'techRecord_dda_minEmergencyExits', + label: 'Minimum emergency exits needed', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [{ name: ValidatorNames.Max, args: 99 }], + }, + { + name: 'techRecord_dda_outswing', + label: 'Outswing', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXTAREA, + validators: [{ name: ValidatorNames.MaxLength, args: 250 }], + }, + { + name: 'techRecord_dda_ddaSchedules', + label: 'DDA schedules', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXTAREA, + validators: [{ name: ValidatorNames.MaxLength, args: 250 }], + }, + { + name: 'techRecord_dda_seatbeltsFitted', + label: 'Seatbelts fitted', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [{ name: ValidatorNames.Max, args: 999 }], + }, + { + name: 'techRecord_dda_ddaNotes', + label: 'DDA notes', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXTAREA, + validators: [{ name: ValidatorNames.MaxLength, args: 1024 }], + }, + ], }; diff --git a/src/app/forms/templates/psv/psv-dimensions.template.ts b/src/app/forms/templates/psv/psv-dimensions.template.ts index 069cfe3a99..2fad617a7c 100644 --- a/src/app/forms/templates/psv/psv-dimensions.template.ts +++ b/src/app/forms/templates/psv/psv-dimensions.template.ts @@ -2,37 +2,37 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { FormNode, FormNodeTypes } from '../../services/dynamic-form.types'; export const PsvDimensionsTemplate: FormNode = { - name: 'dimensionsSection', - label: 'Dimensions', - type: FormNodeTypes.SECTION, - children: [ - { - name: 'techRecord_dimensions_height', - label: 'Height (mm)', - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Max, args: 99999 }], - }, - { - name: 'techRecord_dimensions_length', - label: 'Length (mm)', - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Max, args: 99999 }], - }, - { - name: 'techRecord_dimensions_width', - label: 'Width (mm)', - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Max, args: 99999 }], - }, - { - name: 'techRecord_frontAxleToRearAxle', - label: 'Front axle to rear axle (mm)', - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Max, args: 99999 }], - }, - ], + name: 'dimensionsSection', + label: 'Dimensions', + type: FormNodeTypes.SECTION, + children: [ + { + name: 'techRecord_dimensions_height', + label: 'Height (mm)', + value: null, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Max, args: 99999 }], + }, + { + name: 'techRecord_dimensions_length', + label: 'Length (mm)', + value: null, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Max, args: 99999 }], + }, + { + name: 'techRecord_dimensions_width', + label: 'Width (mm)', + value: null, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Max, args: 99999 }], + }, + { + name: 'techRecord_frontAxleToRearAxle', + label: 'Front axle to rear axle (mm)', + value: null, + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Max, args: 99999 }], + }, + ], }; diff --git a/src/app/forms/templates/psv/psv-notes.template.ts b/src/app/forms/templates/psv/psv-notes.template.ts index f1f1235d6b..dfce3af85d 100644 --- a/src/app/forms/templates/psv/psv-notes.template.ts +++ b/src/app/forms/templates/psv/psv-notes.template.ts @@ -1,28 +1,26 @@ import { ValidatorNames } from '@forms/models/validators.enum'; -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '../../services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '../../services/dynamic-form.types'; export const PsvNotes: FormNode = { - name: 'notesSection', - label: 'Notes', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'techRecord_remarks', - label: 'Notes', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - editType: FormNodeEditTypes.TEXTAREA, - validators: [{ name: ValidatorNames.MaxLength, args: 1024 }], - }, - { - name: 'techRecord_dispensations', - type: FormNodeTypes.CONTROL, - label: 'Dispensations', - viewType: FormNodeViewTypes.STRING, - editType: FormNodeEditTypes.TEXTAREA, - validators: [{ name: ValidatorNames.MaxLength, args: 160 }], - }, - ], + name: 'notesSection', + label: 'Notes', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'techRecord_remarks', + label: 'Notes', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.TEXTAREA, + validators: [{ name: ValidatorNames.MaxLength, args: 1024 }], + }, + { + name: 'techRecord_dispensations', + type: FormNodeTypes.CONTROL, + label: 'Dispensations', + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.TEXTAREA, + validators: [{ name: ValidatorNames.MaxLength, args: 160 }], + }, + ], }; diff --git a/src/app/forms/templates/psv/psv-tech-record.template.ts b/src/app/forms/templates/psv/psv-tech-record.template.ts index 9524d51634..4232786c73 100644 --- a/src/app/forms/templates/psv/psv-tech-record.template.ts +++ b/src/app/forms/templates/psv/psv-tech-record.template.ts @@ -7,283 +7,293 @@ import { VehicleSize } from '@models/vehicle-size.enum'; import { FuelTypes } from '@models/vehicle-tech-record.model'; import { TagType } from '@shared/components/tag/tag.component'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, TagTypeLabels, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, + TagTypeLabels, } from '../../services/dynamic-form.types'; export const PsvTechRecord: FormNode = { - name: 'techRecordSummary', - type: FormNodeTypes.GROUP, - label: 'Vehicle Summary', - children: [ - { - name: 'techRecord_vehicleType', - label: 'Vehicle type', - value: '', - width: FormNodeWidth.XS, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.VEHICLETYPE, - disabled: true, - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_statusCode', - label: 'Record status', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_numberOfWheelsDriven', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'techRecord_regnDate', - label: 'Date of first registration', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - validators: [], - isoDate: false, - }, - { - name: 'techRecord_manufactureYear', - label: 'Year of manufacture', - value: null, - width: FormNodeWidth.XS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [ - { name: ValidatorNames.Max, args: 9999 }, - { name: ValidatorNames.Min, args: 1000 }, - { name: ValidatorNames.PastYear }, - ], - }, - { - name: 'techRecord_noOfAxles', - label: 'Number of axles', - value: null, - width: FormNodeWidth.XXS, - type: FormNodeTypes.CONTROL, - validators: [], - disabled: true, - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_speedLimiterMrk', - label: 'Speed limiter exempt', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Exempt' }, - { value: false, label: 'Not exempt' }, - ], - validators: [], - class: 'flex--half', - }, - { - name: 'techRecord_tachoExemptMrk', - label: 'Tacho exempt', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Exempt' }, - { value: false, label: 'Not exempt' }, - ], - validators: [], - class: 'flex--half', - }, - { - name: 'techRecord_euroStandard', - label: 'Euro standard', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [{ label: '0.10 g/kWh Euro III PM', value: '0.10 g/kWh Euro 3 PM' }, - ...getOptionsFromEnum(EmissionStandard), - ], - }, - { - name: 'techRecord_fuelPropulsionSystem', - label: 'Fuel / propulsion system', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - editType: FormNodeEditTypes.SELECT, - options: getOptionsFromEnum(FuelTypes), - validators: [], - }, - { - name: 'techRecord_vehicleConfiguration', - label: 'Vehicle configuration', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - options: getOptionsFromEnum(VehicleConfiguration), - validators: [{ name: ValidatorNames.UpdateFunctionCode }], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_euVehicleCategory', - label: 'EU vehicle category', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - width: FormNodeWidth.S, - options: getOptionsFromEnum(EUVehicleCategory), - validators: [], - }, - { - name: 'techRecord_emissionsLimit', - label: 'Emission limit (m-1) (plate value)', - value: null, - width: FormNodeWidth.XXS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [ - { name: ValidatorNames.Max, args: 99 }, - { - name: ValidatorNames.CustomPattern, - args: ['^\\d*(\\.\\d{0,5})?$', 'Max 5 decimal places'], - }, - ], - enableDecimals: true, - }, - { name: 'seatsTitle', label: 'Seats:', type: FormNodeTypes.TITLE }, - { - name: 'techRecord_seatsUpperDeck', - label: 'Upper deck', - value: null, - width: FormNodeWidth.M, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [ - { name: ValidatorNames.Max, args: 99 }, - { - name: ValidatorNames.HandlePsvPassengersChange, - args: { passengersOne: 'techRecord_seatsLowerDeck', passengersTwo: 'techRecord_standingCapacity' }, - }, - ], - class: 'flex--half', - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_seatsLowerDeck', - label: 'Lower deck', - value: null, - width: FormNodeWidth.M, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [ - { name: ValidatorNames.Max, args: 999 }, - { - name: ValidatorNames.HandlePsvPassengersChange, - args: { passengersOne: 'techRecord_standingCapacity', passengersTwo: 'techRecord_seatsUpperDeck' }, - }, - ], - class: 'flex--half', - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_standingCapacity', - label: 'Standing capacity', - value: null, - width: FormNodeWidth.XXS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [ - { name: ValidatorNames.Max, args: 999 }, - { - name: ValidatorNames.HandlePsvPassengersChange, - args: { passengersOne: 'techRecord_seatsLowerDeck', passengersTwo: 'techRecord_seatsUpperDeck' }, - }, - ], - }, - { - name: 'techRecord_vehicleClass_description', - label: 'Vehicle class', - value: null, - hint: 'The Vehicle Class is calculated automatically based on the number of seats and standing capacity. Only change the Class if you need to', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - editType: FormNodeEditTypes.SELECT, - options: [ - { label: 'small psv (ie: less than or equal to 22 passengers)', value: 'small psv (ie: less than or equal to 22 seats)' }, - { label: 'large psv(ie: greater than or equal to 23 passengers)', value: 'large psv(ie: greater than 23 seats)' }, - ], - class: '.govuk-input--width-10', - validators: [{ name: ValidatorNames.Required }], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_vehicleSize', - label: 'Vehicle size', - value: null, - hint: 'The Vehicle Size is calculated automatically based on the number of seats and standing capacity. Only change the Size if you need to', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: getOptionsFromEnum(VehicleSize), - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_numberOfSeatbelts', - label: 'Number of seat belts', - value: null, - width: FormNodeWidth.XXS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.Max, args: 99 }], - }, - { - name: 'techRecord_seatbeltInstallationApprovalDate', - label: 'Seatbelt installation approval date / type approved', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - isoDate: false, - validators: [ - { name: ValidatorNames.PastDate }, - ], - }, - { - name: 'techRecord_departmentalVehicleMarker', - label: 'Departmental vehicle marker', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [], - }, - { - name: 'techRecord_alterationMarker', - label: 'Alteration marker', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [], - }, - { - name: 'techRecord_functionCode', - label: 'Function code', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], + name: 'techRecordSummary', + type: FormNodeTypes.GROUP, + label: 'Vehicle Summary', + children: [ + { + name: 'techRecord_vehicleType', + label: 'Vehicle type', + value: '', + width: FormNodeWidth.XS, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.VEHICLETYPE, + disabled: true, + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_statusCode', + label: 'Record status', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_numberOfWheelsDriven', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'techRecord_regnDate', + label: 'Date of first registration', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + validators: [], + isoDate: false, + }, + { + name: 'techRecord_manufactureYear', + label: 'Year of manufacture', + value: null, + width: FormNodeWidth.XS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [ + { name: ValidatorNames.Max, args: 9999 }, + { name: ValidatorNames.Min, args: 1000 }, + { name: ValidatorNames.PastYear }, + ], + }, + { + name: 'techRecord_noOfAxles', + label: 'Number of axles', + value: null, + width: FormNodeWidth.XXS, + type: FormNodeTypes.CONTROL, + validators: [], + disabled: true, + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_speedLimiterMrk', + label: 'Speed limiter exempt', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Exempt' }, + { value: false, label: 'Not exempt' }, + ], + validators: [], + class: 'flex--half', + }, + { + name: 'techRecord_tachoExemptMrk', + label: 'Tacho exempt', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Exempt' }, + { value: false, label: 'Not exempt' }, + ], + validators: [], + class: 'flex--half', + }, + { + name: 'techRecord_euroStandard', + label: 'Euro standard', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { label: '0.10 g/kWh Euro III PM', value: '0.10 g/kWh Euro 3 PM' }, + ...getOptionsFromEnum(EmissionStandard), + ], + }, + { + name: 'techRecord_fuelPropulsionSystem', + label: 'Fuel / propulsion system', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.SELECT, + options: getOptionsFromEnum(FuelTypes), + validators: [], + }, + { + name: 'techRecord_vehicleConfiguration', + label: 'Vehicle configuration', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: getOptionsFromEnum(VehicleConfiguration), + validators: [{ name: ValidatorNames.UpdateFunctionCode }], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_euVehicleCategory', + label: 'EU vehicle category', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + width: FormNodeWidth.S, + options: getOptionsFromEnum(EUVehicleCategory), + validators: [], + }, + { + name: 'techRecord_emissionsLimit', + label: 'Emission limit (m-1) (plate value)', + value: null, + width: FormNodeWidth.XXS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [ + { name: ValidatorNames.Max, args: 99 }, + { + name: ValidatorNames.CustomPattern, + args: ['^\\d*(\\.\\d{0,5})?$', 'Max 5 decimal places'], + }, + ], + enableDecimals: true, + }, + { name: 'seatsTitle', label: 'Seats:', type: FormNodeTypes.TITLE }, + { + name: 'techRecord_seatsUpperDeck', + label: 'Upper deck', + value: null, + width: FormNodeWidth.M, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [ + { name: ValidatorNames.Max, args: 99 }, + { + name: ValidatorNames.HandlePsvPassengersChange, + args: { passengersOne: 'techRecord_seatsLowerDeck', passengersTwo: 'techRecord_standingCapacity' }, + }, + ], + class: 'flex--half', + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_seatsLowerDeck', + label: 'Lower deck', + value: null, + width: FormNodeWidth.M, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [ + { name: ValidatorNames.Max, args: 999 }, + { + name: ValidatorNames.HandlePsvPassengersChange, + args: { passengersOne: 'techRecord_standingCapacity', passengersTwo: 'techRecord_seatsUpperDeck' }, + }, + ], + class: 'flex--half', + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_standingCapacity', + label: 'Standing capacity', + value: null, + width: FormNodeWidth.XXS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [ + { name: ValidatorNames.Max, args: 999 }, + { + name: ValidatorNames.HandlePsvPassengersChange, + args: { passengersOne: 'techRecord_seatsLowerDeck', passengersTwo: 'techRecord_seatsUpperDeck' }, + }, + ], + }, + { + name: 'techRecord_vehicleClass_description', + label: 'Vehicle class', + value: null, + hint: 'The Vehicle Class is calculated automatically based on the number of seats and standing capacity. Only change the Class if you need to', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.SELECT, + options: [ + { + label: 'small psv (ie: less than or equal to 22 passengers)', + value: 'small psv (ie: less than or equal to 22 seats)', + }, + { + label: 'large psv(ie: greater than or equal to 23 passengers)', + value: 'large psv(ie: greater than 23 seats)', + }, + ], + class: '.govuk-input--width-10', + validators: [{ name: ValidatorNames.Required }], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_vehicleSize', + label: 'Vehicle size', + value: null, + hint: 'The Vehicle Size is calculated automatically based on the number of seats and standing capacity. Only change the Size if you need to', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: getOptionsFromEnum(VehicleSize), + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_numberOfSeatbelts', + label: 'Number of seat belts', + value: null, + width: FormNodeWidth.XXS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [{ name: ValidatorNames.Max, args: 99 }], + }, + { + name: 'techRecord_seatbeltInstallationApprovalDate', + label: 'Seatbelt installation approval date / type approved', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + isoDate: false, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'techRecord_departmentalVehicleMarker', + label: 'Departmental vehicle marker', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [], + }, + { + name: 'techRecord_alterationMarker', + label: 'Alteration marker', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [], + }, + { + name: 'techRecord_functionCode', + label: 'Function code', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], }; diff --git a/src/app/forms/templates/psv/psv-tyres.template.ts b/src/app/forms/templates/psv/psv-tyres.template.ts index 0b51ee6874..7fcb0a6963 100644 --- a/src/app/forms/templates/psv/psv-tyres.template.ts +++ b/src/app/forms/templates/psv/psv-tyres.template.ts @@ -2,94 +2,109 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { FormNode, FormNodeEditTypes, FormNodeTypes } from '@forms/services/dynamic-form.types'; export const PsvTyresTemplate: FormNode = { - name: 'tyreSection', - type: FormNodeTypes.GROUP, - label: 'Tyres', - children: [ - { - name: 'techRecord_speedRestriction', - label: 'Speed Restriction', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [{ name: ValidatorNames.Numeric }, { name: ValidatorNames.Max, args: 99 }, { name: ValidatorNames.Min, args: 0 }], - }, - { - name: 'techRecord_axles', - value: '', - type: FormNodeTypes.ARRAY, - validators: [{ - name: ValidatorNames.MinArrayLengthIfNotEmpty, args: { minimumLength: 2, message: 'You cannot submit a PSV with less than 2 axles.' }, - }], - children: [ - { - name: '0', - label: 'Axle', - value: '', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'axleNumber', - label: 'Axle Number', - type: FormNodeTypes.CONTROL, - }, + name: 'tyreSection', + type: FormNodeTypes.GROUP, + label: 'Tyres', + children: [ + { + name: 'techRecord_speedRestriction', + label: 'Speed Restriction', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [ + { name: ValidatorNames.Numeric }, + { name: ValidatorNames.Max, args: 99 }, + { name: ValidatorNames.Min, args: 0 }, + ], + }, + { + name: 'techRecord_axles', + value: '', + type: FormNodeTypes.ARRAY, + validators: [ + { + name: ValidatorNames.MinArrayLengthIfNotEmpty, + args: { minimumLength: 2, message: 'You cannot submit a PSV with less than 2 axles.' }, + }, + ], + children: [ + { + name: '0', + label: 'Axle', + value: '', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'axleNumber', + label: 'Axle Number', + type: FormNodeTypes.CONTROL, + }, - { - name: 'tyres_tyreCode', - label: 'Tyre Code', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [{ name: ValidatorNames.Numeric }, { name: ValidatorNames.Max, args: 99999 }, { name: ValidatorNames.Min, args: 0 }], - }, - { - name: 'tyres_tyreSize', - label: 'Tyre Size', - value: null, - type: FormNodeTypes.CONTROL, - disabled: true, - validators: [ - { name: ValidatorNames.MaxLength, args: 12 }, - { name: ValidatorNames.Min, args: 0 }, - ], - }, - { - name: 'tyres_plyRating', - label: 'Ply Rating', - value: null, - type: FormNodeTypes.CONTROL, - disabled: true, - validators: [ - { name: ValidatorNames.MaxLength, args: 2 }, - { name: ValidatorNames.Min, args: 0 }, - ], - }, - { - name: 'tyres_speedCategorySymbol', - label: 'Speed category symbol', - value: null, - type: FormNodeTypes.CONTROL, - validators: [], - }, - { - name: 'tyres_fitmentCode', - label: 'Fitment code', - value: null, - type: FormNodeTypes.CONTROL, - validators: [], - }, - { - name: 'tyres_dataTrAxles', - label: 'Load index', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - disabled: true, - validators: [{ name: ValidatorNames.Numeric }, { name: ValidatorNames.Max, args: 999 }, { name: ValidatorNames.Min, args: 0 }], - }, - ], - }, - ], - }, - ], + { + name: 'tyres_tyreCode', + label: 'Tyre Code', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [ + { name: ValidatorNames.Numeric }, + { name: ValidatorNames.Max, args: 99999 }, + { name: ValidatorNames.Min, args: 0 }, + ], + }, + { + name: 'tyres_tyreSize', + label: 'Tyre Size', + value: null, + type: FormNodeTypes.CONTROL, + disabled: true, + validators: [ + { name: ValidatorNames.MaxLength, args: 12 }, + { name: ValidatorNames.Min, args: 0 }, + ], + }, + { + name: 'tyres_plyRating', + label: 'Ply Rating', + value: null, + type: FormNodeTypes.CONTROL, + disabled: true, + validators: [ + { name: ValidatorNames.MaxLength, args: 2 }, + { name: ValidatorNames.Min, args: 0 }, + ], + }, + { + name: 'tyres_speedCategorySymbol', + label: 'Speed category symbol', + value: null, + type: FormNodeTypes.CONTROL, + validators: [], + }, + { + name: 'tyres_fitmentCode', + label: 'Fitment code', + value: null, + type: FormNodeTypes.CONTROL, + validators: [], + }, + { + name: 'tyres_dataTrAxles', + label: 'Load index', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + disabled: true, + validators: [ + { name: ValidatorNames.Numeric }, + { name: ValidatorNames.Max, args: 999 }, + { name: ValidatorNames.Min, args: 0 }, + ], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/psv/psv-weight.template.ts b/src/app/forms/templates/psv/psv-weight.template.ts index 433a32b761..2fdcca4cc9 100644 --- a/src/app/forms/templates/psv/psv-weight.template.ts +++ b/src/app/forms/templates/psv/psv-weight.template.ts @@ -2,145 +2,145 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { FormNode, FormNodeTypes } from '../../services/dynamic-form.types'; const requiredValidation = [ - { name: ValidatorNames.Numeric, args: 99999 }, - { name: ValidatorNames.Max, args: 99999 }, - { name: ValidatorNames.Min, args: 0 }, + { name: ValidatorNames.Numeric, args: 99999 }, + { name: ValidatorNames.Max, args: 99999 }, + { name: ValidatorNames.Min, args: 0 }, ]; const optionalValidation = [ - { name: ValidatorNames.Numeric, args: 99999 }, - { name: ValidatorNames.Max, args: 99999 }, - { name: ValidatorNames.Min, args: 0 }, + { name: ValidatorNames.Numeric, args: 99999 }, + { name: ValidatorNames.Max, args: 99999 }, + { name: ValidatorNames.Min, args: 0 }, ]; export const PsvWeightsTemplate: FormNode = { - name: 'weightsSection', - label: 'Weights', - type: FormNodeTypes.SECTION, - children: [ - { - name: 'techRecord_grossSection', - label: 'Gross vehicle weight', - value: null, - type: FormNodeTypes.SECTION, - }, - { - name: 'techRecord_grossKerbWeight', - label: 'Kerb', - customValidatorErrorName: 'Gross Kerb Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - }, - { - name: 'techRecord_grossLadenWeight', - label: 'Laden', - customValidatorErrorName: 'Gross Laden Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - }, - { - name: 'techRecord_grossGbWeight', - label: 'GB', - customValidatorErrorName: 'Gross GB Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - }, - { - name: 'techRecord_grossDesignWeight', - label: 'Design', - customValidatorErrorName: 'Gross Design Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - }, - { - name: 'techRecord_unladenWeight', - label: 'Unladen weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - }, - { - name: 'techRecord_trainSection', - label: 'Train weight', - value: null, - type: FormNodeTypes.SECTION, - }, - { - name: 'techRecord_maxTrainGbWeight', - label: 'Max train GB', - value: null, - type: FormNodeTypes.CONTROL, - validators: optionalValidation, - }, - { - name: 'techRecord_trainDesignWeight', - label: 'Train design', - value: null, - type: FormNodeTypes.CONTROL, - validators: optionalValidation, - }, - { - name: 'axleSection', - label: 'Axle weights', - value: '', - type: FormNodeTypes.SECTION, - }, - { - name: 'techRecord_axles', - value: '', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', - label: 'Axle', - value: '', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'axleNumber', - label: 'Axle Number', - type: FormNodeTypes.CONTROL, - }, + name: 'weightsSection', + label: 'Weights', + type: FormNodeTypes.SECTION, + children: [ + { + name: 'techRecord_grossSection', + label: 'Gross vehicle weight', + value: null, + type: FormNodeTypes.SECTION, + }, + { + name: 'techRecord_grossKerbWeight', + label: 'Kerb', + customValidatorErrorName: 'Gross Kerb Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + }, + { + name: 'techRecord_grossLadenWeight', + label: 'Laden', + customValidatorErrorName: 'Gross Laden Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + }, + { + name: 'techRecord_grossGbWeight', + label: 'GB', + customValidatorErrorName: 'Gross GB Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + }, + { + name: 'techRecord_grossDesignWeight', + label: 'Design', + customValidatorErrorName: 'Gross Design Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + }, + { + name: 'techRecord_unladenWeight', + label: 'Unladen weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + }, + { + name: 'techRecord_trainSection', + label: 'Train weight', + value: null, + type: FormNodeTypes.SECTION, + }, + { + name: 'techRecord_maxTrainGbWeight', + label: 'Max train GB', + value: null, + type: FormNodeTypes.CONTROL, + validators: optionalValidation, + }, + { + name: 'techRecord_trainDesignWeight', + label: 'Train design', + value: null, + type: FormNodeTypes.CONTROL, + validators: optionalValidation, + }, + { + name: 'axleSection', + label: 'Axle weights', + value: '', + type: FormNodeTypes.SECTION, + }, + { + name: 'techRecord_axles', + value: '', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + label: 'Axle', + value: '', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'axleNumber', + label: 'Axle Number', + type: FormNodeTypes.CONTROL, + }, - { - name: 'weights_kerbWeight', - label: 'Kerb weight', - customValidatorErrorName: 'Axle Kerb Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - }, - { - name: 'weights_ladenWeight', - label: 'Laden weight', - customValidatorErrorName: 'Axle Laden Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - }, - { - name: 'weights_gbWeight', - label: 'GB weight', - customValidatorErrorName: 'Axle GB Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - }, - { - name: 'weights_designWeight', - label: 'Design weight', - customValidatorErrorName: 'Axle Design Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - }, - ], - }, - ], - }, - ], + { + name: 'weights_kerbWeight', + label: 'Kerb weight', + customValidatorErrorName: 'Axle Kerb Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + }, + { + name: 'weights_ladenWeight', + label: 'Laden weight', + customValidatorErrorName: 'Axle Laden Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + }, + { + name: 'weights_gbWeight', + label: 'GB weight', + customValidatorErrorName: 'Axle GB Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + }, + { + name: 'weights_designWeight', + label: 'Design weight', + customValidatorErrorName: 'Axle Design Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/search/single-search-result.template.ts b/src/app/forms/templates/search/single-search-result.template.ts index 9e53fa0cfa..9ea4bb66a8 100644 --- a/src/app/forms/templates/search/single-search-result.template.ts +++ b/src/app/forms/templates/search/single-search-result.template.ts @@ -2,63 +2,67 @@ import { Params } from '@angular/router'; import { ValidatorNames } from '@forms/models/validators.enum'; import { FormNode, FormNodeTypes, FormNodeViewTypes } from '../../services/dynamic-form.types'; -export function createSingleSearchResult(systemNumber: string, createdTimestamp: string, queryParams?: Params): FormNode { - return { - name: 'singleSearchResult', - type: FormNodeTypes.GROUP, - label: 'Technical Record', - viewType: FormNodeViewTypes.SUBHEADING, - subHeadingLink: { - label: 'Select technical record', - url: `/tech-records/${systemNumber}/${createdTimestamp}`, - queryParams, - }, - children: [ - { - name: 'vin', - label: 'Vehicle identification number (VIN)', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - }, - { - name: 'vrm', - label: 'Vehicle registration mark (VRM)', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.VRM, - }, - { - name: 'trailerId', - label: 'Trailer ID', - type: FormNodeTypes.CONTROL, - }, - { - name: 'vehicleType', - label: 'Vehicle type', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - validators: [ - { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'trailerId', value: 'TRL' } }, - { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'vrm', value: ['HGV', 'PSV'] } }, - ], - }, - { - name: 'manufactureYear', - label: 'Year of manufacture', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - }, - { - name: 'make', - label: 'Make', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - }, - { - name: 'model', - label: 'Model', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - }, - ], - }; +export function createSingleSearchResult( + systemNumber: string, + createdTimestamp: string, + queryParams?: Params +): FormNode { + return { + name: 'singleSearchResult', + type: FormNodeTypes.GROUP, + label: 'Technical Record', + viewType: FormNodeViewTypes.SUBHEADING, + subHeadingLink: { + label: 'Select technical record', + url: `/tech-records/${systemNumber}/${createdTimestamp}`, + queryParams, + }, + children: [ + { + name: 'vin', + label: 'Vehicle identification number (VIN)', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + }, + { + name: 'vrm', + label: 'Vehicle registration mark (VRM)', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.VRM, + }, + { + name: 'trailerId', + label: 'Trailer ID', + type: FormNodeTypes.CONTROL, + }, + { + name: 'vehicleType', + label: 'Vehicle type', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + validators: [ + { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'trailerId', value: 'TRL' } }, + { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'vrm', value: ['HGV', 'PSV'] } }, + ], + }, + { + name: 'manufactureYear', + label: 'Year of manufacture', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + }, + { + name: 'make', + label: 'Make', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + }, + { + name: 'model', + label: 'Model', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + }, + ], + }; } diff --git a/src/app/forms/templates/small-trailer/small-trailer-tech-record.template.ts b/src/app/forms/templates/small-trailer/small-trailer-tech-record.template.ts index 640e9a1ba1..fddd9ead07 100644 --- a/src/app/forms/templates/small-trailer/small-trailer-tech-record.template.ts +++ b/src/app/forms/templates/small-trailer/small-trailer-tech-record.template.ts @@ -1,112 +1,123 @@ +import { EUVehicleCategory } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/euVehicleCategory.enum.js'; +import { VehicleConfiguration } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleConfigurationLightVehicle.enum.js'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, TagTypeLabels, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, + TagTypeLabels, } from '@forms/services/dynamic-form.types'; import { getOptionsFromEnum } from '@forms/utils/enum-map'; import { VehicleSubclass } from '@models/vehicle-tech-record.model'; import { TagType } from '@shared/components/tag/tag.component'; -import { EUVehicleCategory } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/euVehicleCategory.enum.js'; -import { VehicleConfiguration } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleConfigurationLightVehicle.enum.js'; export const SmallTrailerTechRecord: FormNode = { - name: 'techRecordSummary', - type: FormNodeTypes.GROUP, - label: 'Vehicle Summary', - children: [ - { - name: 'techRecord_vehicleType', - label: 'Vehicle type', - value: '', - width: FormNodeWidth.S, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.VEHICLETYPE, - disabled: true, - validators: [], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_statusCode', - label: 'Record status', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_manufactureYear', - label: 'Year of manufacture', - value: null, - width: FormNodeWidth.XS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [ - { name: ValidatorNames.Max, args: 9999 }, - { name: ValidatorNames.Min, args: 1000 }, - { name: ValidatorNames.PastYear }, - ], - }, - { - name: 'techRecord_noOfAxles', - label: 'Number of axles', - value: null, - width: FormNodeWidth.XXS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [{ name: ValidatorNames.Max, args: 99 }], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - customId: 'vehicleClassDescription', - name: 'techRecord_vehicleClass_description', - label: 'Vehicle class', - value: '', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - options: [ - { label: 'motorbikes over 200cc or with a sidecar', value: 'motorbikes over 200cc or with a sidecar' }, - { label: 'not applicable', value: 'not applicable' }, - { label: 'small psv (ie: less than or equal to 22 passengers)', value: 'small psv (ie: less than or equal to 22 seats)' }, - { label: 'motorbikes up to 200cc', value: 'motorbikes up to 200cc' }, - { label: 'trailer', value: 'trailer' }, - { label: 'large psv(ie: greater than or equal to 23 passengers)', value: 'large psv(ie: greater than 23 seats)' }, - { label: '3 wheelers', value: '3 wheelers' }, - { label: 'heavy goods vehicle', value: 'heavy goods vehicle' }, - { label: 'MOT class 4', value: 'MOT class 4' }, - { label: 'MOT class 7', value: 'MOT class 7' }, - { label: 'MOT class 5', value: 'MOT class 5' }, - ], - validators: [{ name: ValidatorNames.Required }], - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_vehicleSubclass', - label: 'Vehicle Subclass', - width: FormNodeWidth.XXS, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.CHECKBOXGROUP, - options: getOptionsFromEnum(VehicleSubclass), - }, - { - name: 'techRecord_vehicleConfiguration', - label: 'Vehicle configuration', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - options: getOptionsFromEnum(VehicleConfiguration), - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - { - name: 'techRecord_euVehicleCategory', - label: 'EU vehicle category', - value: EUVehicleCategory.O1, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - width: FormNodeWidth.S, - options: getOptionsFromEnum(EUVehicleCategory).filter( - (option) => option.value === EUVehicleCategory.O1 || option.value === EUVehicleCategory.O2, - ), - customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], - }, - ], + name: 'techRecordSummary', + type: FormNodeTypes.GROUP, + label: 'Vehicle Summary', + children: [ + { + name: 'techRecord_vehicleType', + label: 'Vehicle type', + value: '', + width: FormNodeWidth.S, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.VEHICLETYPE, + disabled: true, + validators: [], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_statusCode', + label: 'Record status', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_manufactureYear', + label: 'Year of manufacture', + value: null, + width: FormNodeWidth.XS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [ + { name: ValidatorNames.Max, args: 9999 }, + { name: ValidatorNames.Min, args: 1000 }, + { name: ValidatorNames.PastYear }, + ], + }, + { + name: 'techRecord_noOfAxles', + label: 'Number of axles', + value: null, + width: FormNodeWidth.XXS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [{ name: ValidatorNames.Max, args: 99 }], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + customId: 'vehicleClassDescription', + name: 'techRecord_vehicleClass_description', + label: 'Vehicle class', + value: '', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: [ + { label: 'motorbikes over 200cc or with a sidecar', value: 'motorbikes over 200cc or with a sidecar' }, + { label: 'not applicable', value: 'not applicable' }, + { + label: 'small psv (ie: less than or equal to 22 passengers)', + value: 'small psv (ie: less than or equal to 22 seats)', + }, + { label: 'motorbikes up to 200cc', value: 'motorbikes up to 200cc' }, + { label: 'trailer', value: 'trailer' }, + { + label: 'large psv(ie: greater than or equal to 23 passengers)', + value: 'large psv(ie: greater than 23 seats)', + }, + { label: '3 wheelers', value: '3 wheelers' }, + { label: 'heavy goods vehicle', value: 'heavy goods vehicle' }, + { label: 'MOT class 4', value: 'MOT class 4' }, + { label: 'MOT class 7', value: 'MOT class 7' }, + { label: 'MOT class 5', value: 'MOT class 5' }, + ], + validators: [{ name: ValidatorNames.Required }], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_vehicleSubclass', + label: 'Vehicle Subclass', + width: FormNodeWidth.XXS, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.CHECKBOXGROUP, + options: getOptionsFromEnum(VehicleSubclass), + }, + { + name: 'techRecord_vehicleConfiguration', + label: 'Vehicle configuration', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: getOptionsFromEnum(VehicleConfiguration), + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_euVehicleCategory', + label: 'EU vehicle category', + value: EUVehicleCategory.O1, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + width: FormNodeWidth.S, + options: getOptionsFromEnum(EUVehicleCategory).filter( + (option) => option.value === EUVehicleCategory.O1 || option.value === EUVehicleCategory.O2 + ), + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + ], }; diff --git a/src/app/forms/templates/tech-records/vehicle-summary.template.ts b/src/app/forms/templates/tech-records/vehicle-summary.template.ts index f07ac223e1..5ce6be3ef7 100644 --- a/src/app/forms/templates/tech-records/vehicle-summary.template.ts +++ b/src/app/forms/templates/tech-records/vehicle-summary.template.ts @@ -1,53 +1,51 @@ -import { - FormNode, FormNodeTypes, FormNodeViewTypes, FormNodeEditTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const VehicleSummary: FormNode = { - name: 'vehicleSummary', - label: 'Vehicle Summary', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'vin', - label: 'Vehicle identification number (VIN)', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - editType: FormNodeEditTypes.TEXT, - }, - { - name: 'primaryVrm', - label: 'Vehicle registration mark (VRM)', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - editType: FormNodeEditTypes.TEXT, - }, - { - name: 'techRecord_vehicleType', - label: 'Vehicle type', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - editType: FormNodeEditTypes.TEXT, - }, - { - name: 'techRecord_manufactureYear', - label: 'Year of manufacture', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - editType: FormNodeEditTypes.TEXT, - }, - { - name: 'techRecord_make', - label: 'Make', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - editType: FormNodeEditTypes.TEXT, - }, - { - name: 'techRecord_model', - label: 'Model', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - editType: FormNodeEditTypes.TEXT, - }, - ], + name: 'vehicleSummary', + label: 'Vehicle Summary', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'vin', + label: 'Vehicle identification number (VIN)', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.TEXT, + }, + { + name: 'primaryVrm', + label: 'Vehicle registration mark (VRM)', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.TEXT, + }, + { + name: 'techRecord_vehicleType', + label: 'Vehicle type', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.TEXT, + }, + { + name: 'techRecord_manufactureYear', + label: 'Year of manufacture', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.TEXT, + }, + { + name: 'techRecord_make', + label: 'Make', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.TEXT, + }, + { + name: 'techRecord_model', + label: 'Model', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.TEXT, + }, + ], }; 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 15650b22a6..af7c51f37b 100644 --- a/src/app/forms/templates/test-records/create-master.template.ts +++ b/src/app/forms/templates/test-records/create-master.template.ts @@ -9,7 +9,10 @@ import { DeskBasedEmissionsSection } from './section-templates/emissions/desk-ba 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 { + reasonForCreationHiddenSection, + reasonForCreationSection, +} from './section-templates/reasonForCreation/reasonForCreation.template'; import { CreateRequiredSectionHgvTrl } from './section-templates/required/contingency-required-hidden-section-hgv-trl.template'; import { CreateRequiredSectionLgvCar } from './section-templates/required/contingency-required-hidden-section-lgv-car.template'; import { CreateRequiredSectionMotorcycle } from './section-templates/required/contingency-required-hidden-section-motorcycle.template'; @@ -22,29 +25,23 @@ import { SeatbeltHiddenSection } from './section-templates/required/seatbelt-hid import { SpecialistRequiredSectionLgvCarSmallTrl } from './section-templates/required/specialist-required-hidden-section-lgv-car.template'; import { SeatbeltSection } from './section-templates/seatbelt/seatbelt-section.template'; import { ContingencyTestSectionGroup1 } from './section-templates/test/contingency/contingency-test-section-group1.template'; -import { ContingencyTestSectionGroup12and14 } from './section-templates/test/contingency/contingency-test-section-group12and14.template'; -import { ContingencyTestSectionGroup15and16 } from './section-templates/test/contingency/contingency-test-section-group15and16.template'; import { ContingencyTestSectionGroup3And4And8 } from './section-templates/test/contingency/contingency-test-section-group3And4And8.template'; import { ContingencyTestSectionGroup5And13 } from './section-templates/test/contingency/contingency-test-section-group5And13.template'; import { ContingencyTestSectionGroup6And11 } from './section-templates/test/contingency/contingency-test-section-group6And11.template'; import { ContingencyTestSectionGroup7 } from './section-templates/test/contingency/contingency-test-section-group7.template'; import { ContingencyTestSectionGroup8Notifiable } from './section-templates/test/contingency/contingency-test-section-group8Notifiable.template'; import { ContingencyTestSectionGroup9And10 } from './section-templates/test/contingency/contingency-test-section-group9And10.template'; -import { - ContingencyTestSectionGroup9And10CentralDocs, -} from './section-templates/test/contingency/contingency-test-section-group9And10CentralDocs.template'; +import { ContingencyTestSectionGroup9And10CentralDocs } from './section-templates/test/contingency/contingency-test-section-group9And10CentralDocs.template'; +import { ContingencyTestSectionGroup12and14 } from './section-templates/test/contingency/contingency-test-section-group12and14.template'; +import { ContingencyTestSectionGroup15and16 } from './section-templates/test/contingency/contingency-test-section-group15and16.template'; import { ContingencyTestSectionSpecialistGroup1 } from './section-templates/test/contingency/contingency-test-section-specialist-group1.template'; import { ContingencyTestSectionSpecialistGroup2 } from './section-templates/test/contingency/contingency-test-section-specialist-group2.template'; -import { - ContingencyTestSectionSpecialistGroup3And4, -} from './section-templates/test/contingency/contingency-test-section-specialist-group3And4.template'; +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, -} from './section-templates/test/desk-based/desk-based-test-section-group1And4-HGV-TRL.template'; +import { DeskBasedTestSectionGroup1And4HgvTrl as DeskBasedTestSectionGroup1And4And5HgvTrl } from './section-templates/test/desk-based/desk-based-test-section-group1And4-HGV-TRL.template'; import { DeskBasedTestSectionGroup2And5 } from './section-templates/test/desk-based/desk-based-test-section-group2.template'; import { DeskBasedTestSectionGroup3 } from './section-templates/test/desk-based/desk-based-test-section-group3.template'; import { DeskBasedTestSectionGroup4Psv } from './section-templates/test/desk-based/desk-based-test-section-group4-PSV.template'; @@ -57,9 +54,7 @@ import { ContingencyVehicleSectionDefaultTrl } from './section-templates/vehicle import { ContingencyIvaMsvaVehicleSection } from './section-templates/vehicle/contingency-iva-msva-vehicle-section.template'; import { DeskBasedVehicleSectionDefaultPsvHgv } from './section-templates/vehicle/desk-based-default-psv-hgv-vehicle-section.template'; import { DeskBasedVehicleSectionDefaultTrl } from './section-templates/vehicle/desk-based-default-trl-vehicle-section.template'; -import { - DeskBasedVehicleSectionHgvGroup1And2And4 as DeskBasedVehicleSectionHgvGroup1And2And4And5, -} from './section-templates/vehicle/desk-based-test-hgv-vehicle-section-group1And2And4.template'; +import { DeskBasedVehicleSectionHgvGroup1And2And4 as DeskBasedVehicleSectionHgvGroup1And2And4And5 } from './section-templates/vehicle/desk-based-test-hgv-vehicle-section-group1And2And4.template'; import { DeskBasedVehicleSectionGroup4LGV } from './section-templates/vehicle/desk-based-vehicle-section-group4-lgv.template'; import { DeskBasedVehicleSectionGroup5Lgv } from './section-templates/vehicle/desk-based-vehicle-section-group5-lgv.template'; import { VehicleSectionGroup3 } from './section-templates/vehicle/group-3-light-vehicle-section.template'; @@ -67,741 +62,744 @@ import { ContingencyVisitSection } from './section-templates/visit/contingency-v import { VisitSection } from './section-templates/visit/visit-section.template'; const groups1and2Template: Record = { - required: CreateRequiredSection, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: ContingencyTestSectionGroup1, - seatbelts: SeatbeltSection, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, + required: CreateRequiredSection, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: ContingencyTestSectionGroup1, + seatbelts: SeatbeltSection, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, }; -export const contingencyTestTemplates: Record>>> = { - psv: { - default: { - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: TestSection, - seatbelts: SeatbeltSection, - emissions: EmissionsSection, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsSection, - required: CreateRequiredSection, - }, - testTypesGroup1: groups1and2Template, - testTypesGroup2: groups1and2Template, - testTypesGroup3And4And8: { - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: ContingencyTestSectionGroup3And4And8, - visit: ContingencyVisitSection, - seatbelts: SeatbeltHiddenSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSection, - }, - testTypesGroup8Notifiable: { - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: ContingencyTestSectionGroup8Notifiable, - visit: ContingencyVisitSection, - seatbelts: SeatbeltHiddenSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSection, - }, - testTypesGroup15And16: { - required: CreateRequiredSection, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: ContingencyTestSectionGroup15and16, - emissions: EmissionsSection, - seatbelts: SeatbeltHiddenSection, - visit: ContingencyVisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup1: { - vehicle: ContingencyIvaMsvaVehicleSection, - test: ContingencyTestSectionSpecialistGroup1, - seatbelts: SeatbeltHiddenSection, - visit: ContingencyVisitSection, - notes: NotesSection, - requiredStandards: RequiredStandardsTpl, - defects: defectsHiddenSection, - customDefects: AdditionalDefectsSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSection, - }, - testTypesSpecialistGroup1OldIVAorMSVA: { - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: OldIVAContingencyTestSectionSpecialistGroup1, - seatbelts: SeatbeltHiddenSection, - visit: ContingencyVisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSection, - }, - testTypesSpecialistGroup2: { - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: ContingencyTestSectionSpecialistGroup2, - seatbelts: SeatbeltSection, - visit: ContingencyVisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSection, - }, - testTypesSpecialistGroup3: { - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: ContingencyTestSectionSpecialistGroup3And4, - seatbelts: SeatbeltHiddenSection, - visit: ContingencyVisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSection, - }, - testTypesSpecialistGroup4: { - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: ContingencyTestSectionSpecialistGroup3And4, - seatbelts: SeatbeltSection, - visit: ContingencyVisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSection, - }, - testTypesSpecialistGroup5: { - vehicle: ContingencyIvaMsvaVehicleSection, - test: ContingencyTestSectionSpecialistGroup5, - seatbelts: SeatbeltHiddenSection, - visit: ContingencyVisitSection, - notes: NotesSection, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSection, - }, - testTypesSpecialistGroup5OldIVAorMSVA: { - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: OldIVAContingencyTestSectionSpecialistGroup5, - seatbelts: SeatbeltHiddenSection, - visit: ContingencyVisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSection, - }, - testTypesDeskBasedGroup1: { - required: CreateRequiredSection, - vehicle: DeskBasedVehicleSectionDefaultPsvHgv, - test: DeskBasedTestSectionGroup1Psv, - seatbelts: SeatbeltHiddenSection, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationHiddenSection, - }, - testTypesDeskBasedGroup2: { - vehicle: DeskBasedVehicleSectionDefaultPsvHgv, - required: CreateRequiredSection, - test: DeskBasedTestSectionGroup2And5, - seatbelts: SeatbeltHiddenSection, - emissions: DeskBasedEmissionsSection, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationHiddenSection, - }, - testTypesDeskBasedGroup3: { - required: CreateRequiredSection, - vehicle: DeskBasedVehicleSectionDefaultPsvHgv, - test: DeskBasedTestSectionGroup3, - seatbelts: SeatbeltHiddenSection, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationHiddenSection, - }, - testTypesDeskBasedGroup4: { - required: CreateRequiredSection, - vehicle: DeskBasedVehicleSectionDefaultPsvHgv, - test: DeskBasedTestSectionGroup4Psv, - seatbelts: SeatbeltHiddenSection, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationHiddenSection, - }, - }, - hgv: { - default: { - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: TestSection, - visit: VisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsSection, - required: CreateRequiredSectionHgvTrl, - }, - testTypesGroup3And4And8: { - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: ContingencyTestSectionGroup3And4And8, - visit: ContingencyVisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSectionHgvTrl, - }, - testTypesGroup8Notifiable: { - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: ContingencyTestSectionGroup8Notifiable, - visit: ContingencyVisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSectionHgvTrl, - }, - testTypesGroup5And13: { - required: CreateRequiredSectionHgvTrl, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: ContingencyTestSectionGroup5And13, - visit: ContingencyVisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesGroup6And11: { - required: CreateRequiredSectionHgvTrl, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: ContingencyTestSectionGroup6And11, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesGroup7: { - required: CreateRequiredSectionHgvTrl, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: ContingencyTestSectionGroup7, - visit: ContingencyVisitSection, - notes: AdrNotesSection, - customDefects: CustomDefectsSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesGroup9And10: { - required: CreateRequiredSectionHgvTrl, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: ContingencyTestSectionGroup9And10, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesGroup9And10CentralDocs: { - required: CreateRequiredSectionHgvTrl, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: ContingencyTestSectionGroup9And10CentralDocs, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesGroup12And14: { - required: CreateRequiredSectionHgvTrl, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: ContingencyTestSectionGroup12and14, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup1: { - vehicle: ContingencyIvaMsvaVehicleSection, - test: ContingencyTestSectionSpecialistGroup1, - visit: ContingencyVisitSection, - notes: NotesSection, - requiredStandards: RequiredStandardsTpl, - defects: defectsHiddenSection, - customDefects: AdditionalDefectsSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSectionHgvTrl, - }, - testTypesSpecialistGroup1OldIVAorMSVA: { - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: OldIVAContingencyTestSectionSpecialistGroup1, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSectionHgvTrl, - }, - testTypesSpecialistGroup5: { - vehicle: ContingencyIvaMsvaVehicleSection, - test: ContingencyTestSectionSpecialistGroup5, - visit: ContingencyVisitSection, - notes: NotesSection, - requiredStandards: RequiredStandardsTpl, - defects: defectsHiddenSection, - customDefects: AdditionalDefectsSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSectionHgvTrl, - }, - testTypesSpecialistGroup5OldIVAorMSVA: { - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: OldIVAContingencyTestSectionSpecialistGroup5, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSectionHgvTrl, - }, - testTypesGroup15And16: { - required: CreateRequiredSectionHgvTrl, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: ContingencyTestSectionGroup15and16, - emissions: EmissionsSection, - visit: ContingencyVisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup1: { - required: CreateRequiredSectionHgvTrl, - vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, - test: DeskBasedTestSectionGroup1And4And5HgvTrl, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationHiddenSection, - }, - testTypesDeskBasedGroup2: { - required: CreateRequiredSectionHgvTrl, - vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, - test: DeskBasedTestSectionGroup2And5, - emissions: DeskBasedEmissionsSection, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationHiddenSection, - }, - testTypesDeskBasedGroup3: { - required: CreateRequiredSectionHgvTrl, - vehicle: DeskBasedVehicleSectionDefaultPsvHgv, - test: DeskBasedTestSectionGroup3, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationHiddenSection, - }, - testTypesDeskBasedGroup4: { - required: CreateRequiredSectionHgvTrl, - vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, - test: DeskBasedTestSectionGroup1And4And5HgvTrl, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationHiddenSection, - }, - testTypesDeskBasedGroup5: { - required: CreateRequiredSectionHgvTrl, - vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, - test: DeskBasedTestSectionGroup2And5, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationHiddenSection, - }, - }, - trl: { - default: { - vehicle: ContingencyVehicleSectionDefaultTrl, - test: TestSection, - visit: VisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsSection, - required: CreateRequiredSectionHgvTrl, - }, - testTypesGroup3And4And8: { - vehicle: ContingencyVehicleSectionDefaultTrl, - test: ContingencyTestSectionGroup3And4And8, - visit: ContingencyVisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSectionHgvTrl, - }, - testTypesGroup8Notifiable: { - vehicle: ContingencyVehicleSectionDefaultTrl, - test: ContingencyTestSectionGroup8Notifiable, - visit: ContingencyVisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSectionHgvTrl, - }, - testTypesGroup5And13: { - required: CreateRequiredSectionHgvTrl, - vehicle: ContingencyVehicleSectionDefaultTrl, - test: ContingencyTestSectionGroup5And13, - visit: ContingencyVisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesGroup6And11: { - required: CreateRequiredSectionHgvTrl, - vehicle: ContingencyVehicleSectionDefaultTrl, - test: ContingencyTestSectionGroup6And11, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesGroup7: { - required: CreateRequiredSectionHgvTrl, - vehicle: ContingencyVehicleSectionDefaultTrl, - test: ContingencyTestSectionGroup7, - visit: ContingencyVisitSection, - notes: AdrNotesSection, - customDefects: CustomDefectsSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesGroup9And10: { - required: CreateRequiredSectionHgvTrl, - vehicle: ContingencyVehicleSectionDefaultTrl, - test: ContingencyTestSectionGroup9And10, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesGroup9And10CentralDocs: { - required: CreateRequiredSectionHgvTrl, - vehicle: ContingencyVehicleSectionDefaultTrl, - test: ContingencyTestSectionGroup9And10CentralDocs, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesGroup12And14: { - required: CreateRequiredSectionHgvTrl, - vehicle: ContingencyVehicleSectionDefaultTrl, - test: ContingencyTestSectionGroup12and14, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup1: { - vehicle: ContingencyVehicleSectionDefaultTrl, - test: ContingencyTestSectionSpecialistGroup1, - visit: ContingencyVisitSection, - notes: NotesSection, - requiredStandards: RequiredStandardsTpl, - defects: defectsHiddenSection, - customDefects: AdditionalDefectsSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSectionHgvTrl, - }, - testTypesSpecialistGroup1OldIVAorMSVA: { - vehicle: ContingencyVehicleSectionDefaultTrl, - test: OldIVAContingencyTestSectionSpecialistGroup1, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSectionHgvTrl, - }, - testTypesSpecialistGroup5: { - vehicle: ContingencyVehicleSectionDefaultTrl, - test: ContingencyTestSectionSpecialistGroup5, - visit: ContingencyVisitSection, - notes: NotesSection, - requiredStandards: RequiredStandardsTpl, - defects: defectsHiddenSection, - customDefects: AdditionalDefectsSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSectionHgvTrl, - }, - testTypesSpecialistGroup5OldIVAorMSVA: { - vehicle: ContingencyVehicleSectionDefaultTrl, - test: OldIVAContingencyTestSectionSpecialistGroup5, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: CreateRequiredSectionHgvTrl, - }, - testTypesDeskBasedGroup1: { - required: CreateRequiredSectionHgvTrl, - vehicle: DeskBasedVehicleSectionDefaultTrl, - test: DeskBasedTestSectionGroup1And4And5HgvTrl, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationHiddenSection, - }, - testTypesDeskBasedGroup2: { - required: CreateRequiredSectionHgvTrl, - vehicle: DeskBasedVehicleSectionDefaultTrl, - test: DeskBasedTestSectionGroup2And5, - emissions: DeskBasedEmissionsSection, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationHiddenSection, - }, - testTypesDeskBasedGroup3: { - required: CreateRequiredSectionHgvTrl, - vehicle: DeskBasedVehicleSectionDefaultTrl, - test: DeskBasedTestSectionGroup3, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationHiddenSection, - }, - testTypesDeskBasedGroup4: { - required: CreateRequiredSectionHgvTrl, - vehicle: DeskBasedVehicleSectionDefaultTrl, - test: DeskBasedTestSectionGroup1And4And5HgvTrl, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationHiddenSection, - }, - }, - lgv: { - default: { - required: CreateRequiredSectionLgvCar, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: TestSection, - defects: defectsHiddenSection, - visit: ContingencyVisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup1: { - required: CreateRequiredSectionLgvCar, - vehicle: ContingencyIvaMsvaVehicleSection, - test: ContingencyTestSectionSpecialistGroup1, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - visit: ContingencyVisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup1OldIVAorMSVA: { - required: CreateRequiredSectionLgvCar, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: OldIVAContingencyTestSectionSpecialistGroup1, - customDefects: CustomDefectsSection, - visit: ContingencyVisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup4: { - required: DeskBasedRequiredHiddenSectionGroup4And5Lgv, - vehicle: DeskBasedVehicleSectionGroup4LGV, - test: DeskBasedTestSectionGroup4LgvCarMotorcycle, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup5: { - required: CreateRequiredSectionLgvCar, - vehicle: ContingencyIvaMsvaVehicleSection, - test: ContingencyTestSectionSpecialistGroup5, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - visit: ContingencyVisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup5OldIVAorMSVA: { - required: CreateRequiredSectionLgvCar, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: OldIVAContingencyTestSectionSpecialistGroup5, - customDefects: CustomDefectsSection, - visit: ContingencyVisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup5: { - required: DeskBasedRequiredHiddenSectionGroup4And5Lgv, - vehicle: DeskBasedVehicleSectionGroup5Lgv, - test: DeskBasedTestSectionLgvGroup5, - visit: ContingencyVisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - }, - car: { - default: { - required: CreateRequiredSectionLgvCar, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: TestSection, - defects: defectsHiddenSection, - visit: ContingencyVisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup1: { - required: CreateRequiredSectionLgvCar, - vehicle: ContingencyIvaMsvaVehicleSection, - test: ContingencyTestSectionSpecialistGroup1, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - visit: ContingencyVisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup1OldIVAorMSVA: { - required: CreateRequiredSectionLgvCar, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: OldIVAContingencyTestSectionSpecialistGroup1, - customDefects: CustomDefectsSection, - visit: ContingencyVisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup4: { - required: DeskBasedRequiredHiddenSectionGroup4And5Lgv, - vehicle: DeskBasedVehicleSectionGroup4LGV, - test: DeskBasedTestSectionGroup4LgvCarMotorcycle, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup5: { - required: CreateRequiredSectionLgvCar, - vehicle: ContingencyIvaMsvaVehicleSection, - test: ContingencyTestSectionSpecialistGroup5, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - visit: ContingencyVisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup5OldIVAorMSVA: { - required: CreateRequiredSectionLgvCar, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: OldIVAContingencyTestSectionSpecialistGroup5, - customDefects: CustomDefectsSection, - visit: ContingencyVisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - }, - 'small trl': { - default: { - required: CreateRequiredSection, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: TestSection, - defects: defectsHiddenSection, - visit: ContingencyVisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup3: { - required: SpecialistRequiredSectionLgvCarSmallTrl, - vehicle: VehicleSectionGroup3, - test: SpecialistTestSectionGroup3, - customDefects: CustomDefectsHiddenSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - }, - motorcycle: { - default: { - required: CreateRequiredSection, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: TestSection, - defects: defectsHiddenSection, - visit: ContingencyVisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup1: { - required: CreateRequiredSectionMotorcycle, - vehicle: ContingencyIvaMsvaVehicleSection, - test: ContingencyTestSectionSpecialistGroup1, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - visit: ContingencyVisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup1OldIVAorMSVA: { - required: CreateRequiredSectionMotorcycle, - vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, - test: OldIVAContingencyTestSectionSpecialistGroup1, - customDefects: CustomDefectsSection, - visit: ContingencyVisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup4: { - required: DeskBasedRequiredHiddenSectionGroup4Motorcyle, - vehicle: DeskBasedVehicleSectionGroup4LGV, - test: DeskBasedTestSectionGroup4LgvCarMotorcycle, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - }, +export const contingencyTestTemplates: Record< + VehicleTypes, + Partial>> +> = { + psv: { + default: { + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: TestSection, + seatbelts: SeatbeltSection, + emissions: EmissionsSection, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsSection, + required: CreateRequiredSection, + }, + testTypesGroup1: groups1and2Template, + testTypesGroup2: groups1and2Template, + testTypesGroup3And4And8: { + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: ContingencyTestSectionGroup3And4And8, + visit: ContingencyVisitSection, + seatbelts: SeatbeltHiddenSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSection, + }, + testTypesGroup8Notifiable: { + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: ContingencyTestSectionGroup8Notifiable, + visit: ContingencyVisitSection, + seatbelts: SeatbeltHiddenSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSection, + }, + testTypesGroup15And16: { + required: CreateRequiredSection, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: ContingencyTestSectionGroup15and16, + emissions: EmissionsSection, + seatbelts: SeatbeltHiddenSection, + visit: ContingencyVisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup1: { + vehicle: ContingencyIvaMsvaVehicleSection, + test: ContingencyTestSectionSpecialistGroup1, + seatbelts: SeatbeltHiddenSection, + visit: ContingencyVisitSection, + notes: NotesSection, + requiredStandards: RequiredStandardsTpl, + defects: defectsHiddenSection, + customDefects: AdditionalDefectsSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSection, + }, + testTypesSpecialistGroup1OldIVAorMSVA: { + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: OldIVAContingencyTestSectionSpecialistGroup1, + seatbelts: SeatbeltHiddenSection, + visit: ContingencyVisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSection, + }, + testTypesSpecialistGroup2: { + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: ContingencyTestSectionSpecialistGroup2, + seatbelts: SeatbeltSection, + visit: ContingencyVisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSection, + }, + testTypesSpecialistGroup3: { + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: ContingencyTestSectionSpecialistGroup3And4, + seatbelts: SeatbeltHiddenSection, + visit: ContingencyVisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSection, + }, + testTypesSpecialistGroup4: { + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: ContingencyTestSectionSpecialistGroup3And4, + seatbelts: SeatbeltSection, + visit: ContingencyVisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSection, + }, + testTypesSpecialistGroup5: { + vehicle: ContingencyIvaMsvaVehicleSection, + test: ContingencyTestSectionSpecialistGroup5, + seatbelts: SeatbeltHiddenSection, + visit: ContingencyVisitSection, + notes: NotesSection, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSection, + }, + testTypesSpecialistGroup5OldIVAorMSVA: { + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: OldIVAContingencyTestSectionSpecialistGroup5, + seatbelts: SeatbeltHiddenSection, + visit: ContingencyVisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSection, + }, + testTypesDeskBasedGroup1: { + required: CreateRequiredSection, + vehicle: DeskBasedVehicleSectionDefaultPsvHgv, + test: DeskBasedTestSectionGroup1Psv, + seatbelts: SeatbeltHiddenSection, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationHiddenSection, + }, + testTypesDeskBasedGroup2: { + vehicle: DeskBasedVehicleSectionDefaultPsvHgv, + required: CreateRequiredSection, + test: DeskBasedTestSectionGroup2And5, + seatbelts: SeatbeltHiddenSection, + emissions: DeskBasedEmissionsSection, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationHiddenSection, + }, + testTypesDeskBasedGroup3: { + required: CreateRequiredSection, + vehicle: DeskBasedVehicleSectionDefaultPsvHgv, + test: DeskBasedTestSectionGroup3, + seatbelts: SeatbeltHiddenSection, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationHiddenSection, + }, + testTypesDeskBasedGroup4: { + required: CreateRequiredSection, + vehicle: DeskBasedVehicleSectionDefaultPsvHgv, + test: DeskBasedTestSectionGroup4Psv, + seatbelts: SeatbeltHiddenSection, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationHiddenSection, + }, + }, + hgv: { + default: { + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: TestSection, + visit: VisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsSection, + required: CreateRequiredSectionHgvTrl, + }, + testTypesGroup3And4And8: { + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: ContingencyTestSectionGroup3And4And8, + visit: ContingencyVisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSectionHgvTrl, + }, + testTypesGroup8Notifiable: { + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: ContingencyTestSectionGroup8Notifiable, + visit: ContingencyVisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSectionHgvTrl, + }, + testTypesGroup5And13: { + required: CreateRequiredSectionHgvTrl, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: ContingencyTestSectionGroup5And13, + visit: ContingencyVisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesGroup6And11: { + required: CreateRequiredSectionHgvTrl, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: ContingencyTestSectionGroup6And11, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesGroup7: { + required: CreateRequiredSectionHgvTrl, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: ContingencyTestSectionGroup7, + visit: ContingencyVisitSection, + notes: AdrNotesSection, + customDefects: CustomDefectsSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesGroup9And10: { + required: CreateRequiredSectionHgvTrl, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: ContingencyTestSectionGroup9And10, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesGroup9And10CentralDocs: { + required: CreateRequiredSectionHgvTrl, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: ContingencyTestSectionGroup9And10CentralDocs, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesGroup12And14: { + required: CreateRequiredSectionHgvTrl, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: ContingencyTestSectionGroup12and14, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup1: { + vehicle: ContingencyIvaMsvaVehicleSection, + test: ContingencyTestSectionSpecialistGroup1, + visit: ContingencyVisitSection, + notes: NotesSection, + requiredStandards: RequiredStandardsTpl, + defects: defectsHiddenSection, + customDefects: AdditionalDefectsSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSectionHgvTrl, + }, + testTypesSpecialistGroup1OldIVAorMSVA: { + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: OldIVAContingencyTestSectionSpecialistGroup1, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSectionHgvTrl, + }, + testTypesSpecialistGroup5: { + vehicle: ContingencyIvaMsvaVehicleSection, + test: ContingencyTestSectionSpecialistGroup5, + visit: ContingencyVisitSection, + notes: NotesSection, + requiredStandards: RequiredStandardsTpl, + defects: defectsHiddenSection, + customDefects: AdditionalDefectsSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSectionHgvTrl, + }, + testTypesSpecialistGroup5OldIVAorMSVA: { + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: OldIVAContingencyTestSectionSpecialistGroup5, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSectionHgvTrl, + }, + testTypesGroup15And16: { + required: CreateRequiredSectionHgvTrl, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: ContingencyTestSectionGroup15and16, + emissions: EmissionsSection, + visit: ContingencyVisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup1: { + required: CreateRequiredSectionHgvTrl, + vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, + test: DeskBasedTestSectionGroup1And4And5HgvTrl, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationHiddenSection, + }, + testTypesDeskBasedGroup2: { + required: CreateRequiredSectionHgvTrl, + vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, + test: DeskBasedTestSectionGroup2And5, + emissions: DeskBasedEmissionsSection, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationHiddenSection, + }, + testTypesDeskBasedGroup3: { + required: CreateRequiredSectionHgvTrl, + vehicle: DeskBasedVehicleSectionDefaultPsvHgv, + test: DeskBasedTestSectionGroup3, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationHiddenSection, + }, + testTypesDeskBasedGroup4: { + required: CreateRequiredSectionHgvTrl, + vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, + test: DeskBasedTestSectionGroup1And4And5HgvTrl, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationHiddenSection, + }, + testTypesDeskBasedGroup5: { + required: CreateRequiredSectionHgvTrl, + vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, + test: DeskBasedTestSectionGroup2And5, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationHiddenSection, + }, + }, + trl: { + default: { + vehicle: ContingencyVehicleSectionDefaultTrl, + test: TestSection, + visit: VisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsSection, + required: CreateRequiredSectionHgvTrl, + }, + testTypesGroup3And4And8: { + vehicle: ContingencyVehicleSectionDefaultTrl, + test: ContingencyTestSectionGroup3And4And8, + visit: ContingencyVisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSectionHgvTrl, + }, + testTypesGroup8Notifiable: { + vehicle: ContingencyVehicleSectionDefaultTrl, + test: ContingencyTestSectionGroup8Notifiable, + visit: ContingencyVisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSectionHgvTrl, + }, + testTypesGroup5And13: { + required: CreateRequiredSectionHgvTrl, + vehicle: ContingencyVehicleSectionDefaultTrl, + test: ContingencyTestSectionGroup5And13, + visit: ContingencyVisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesGroup6And11: { + required: CreateRequiredSectionHgvTrl, + vehicle: ContingencyVehicleSectionDefaultTrl, + test: ContingencyTestSectionGroup6And11, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesGroup7: { + required: CreateRequiredSectionHgvTrl, + vehicle: ContingencyVehicleSectionDefaultTrl, + test: ContingencyTestSectionGroup7, + visit: ContingencyVisitSection, + notes: AdrNotesSection, + customDefects: CustomDefectsSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesGroup9And10: { + required: CreateRequiredSectionHgvTrl, + vehicle: ContingencyVehicleSectionDefaultTrl, + test: ContingencyTestSectionGroup9And10, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesGroup9And10CentralDocs: { + required: CreateRequiredSectionHgvTrl, + vehicle: ContingencyVehicleSectionDefaultTrl, + test: ContingencyTestSectionGroup9And10CentralDocs, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesGroup12And14: { + required: CreateRequiredSectionHgvTrl, + vehicle: ContingencyVehicleSectionDefaultTrl, + test: ContingencyTestSectionGroup12and14, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup1: { + vehicle: ContingencyVehicleSectionDefaultTrl, + test: ContingencyTestSectionSpecialistGroup1, + visit: ContingencyVisitSection, + notes: NotesSection, + requiredStandards: RequiredStandardsTpl, + defects: defectsHiddenSection, + customDefects: AdditionalDefectsSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSectionHgvTrl, + }, + testTypesSpecialistGroup1OldIVAorMSVA: { + vehicle: ContingencyVehicleSectionDefaultTrl, + test: OldIVAContingencyTestSectionSpecialistGroup1, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSectionHgvTrl, + }, + testTypesSpecialistGroup5: { + vehicle: ContingencyVehicleSectionDefaultTrl, + test: ContingencyTestSectionSpecialistGroup5, + visit: ContingencyVisitSection, + notes: NotesSection, + requiredStandards: RequiredStandardsTpl, + defects: defectsHiddenSection, + customDefects: AdditionalDefectsSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSectionHgvTrl, + }, + testTypesSpecialistGroup5OldIVAorMSVA: { + vehicle: ContingencyVehicleSectionDefaultTrl, + test: OldIVAContingencyTestSectionSpecialistGroup5, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: CreateRequiredSectionHgvTrl, + }, + testTypesDeskBasedGroup1: { + required: CreateRequiredSectionHgvTrl, + vehicle: DeskBasedVehicleSectionDefaultTrl, + test: DeskBasedTestSectionGroup1And4And5HgvTrl, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationHiddenSection, + }, + testTypesDeskBasedGroup2: { + required: CreateRequiredSectionHgvTrl, + vehicle: DeskBasedVehicleSectionDefaultTrl, + test: DeskBasedTestSectionGroup2And5, + emissions: DeskBasedEmissionsSection, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationHiddenSection, + }, + testTypesDeskBasedGroup3: { + required: CreateRequiredSectionHgvTrl, + vehicle: DeskBasedVehicleSectionDefaultTrl, + test: DeskBasedTestSectionGroup3, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationHiddenSection, + }, + testTypesDeskBasedGroup4: { + required: CreateRequiredSectionHgvTrl, + vehicle: DeskBasedVehicleSectionDefaultTrl, + test: DeskBasedTestSectionGroup1And4And5HgvTrl, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationHiddenSection, + }, + }, + lgv: { + default: { + required: CreateRequiredSectionLgvCar, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: TestSection, + defects: defectsHiddenSection, + visit: ContingencyVisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup1: { + required: CreateRequiredSectionLgvCar, + vehicle: ContingencyIvaMsvaVehicleSection, + test: ContingencyTestSectionSpecialistGroup1, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + visit: ContingencyVisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup1OldIVAorMSVA: { + required: CreateRequiredSectionLgvCar, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: OldIVAContingencyTestSectionSpecialistGroup1, + customDefects: CustomDefectsSection, + visit: ContingencyVisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup4: { + required: DeskBasedRequiredHiddenSectionGroup4And5Lgv, + vehicle: DeskBasedVehicleSectionGroup4LGV, + test: DeskBasedTestSectionGroup4LgvCarMotorcycle, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup5: { + required: CreateRequiredSectionLgvCar, + vehicle: ContingencyIvaMsvaVehicleSection, + test: ContingencyTestSectionSpecialistGroup5, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + visit: ContingencyVisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup5OldIVAorMSVA: { + required: CreateRequiredSectionLgvCar, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: OldIVAContingencyTestSectionSpecialistGroup5, + customDefects: CustomDefectsSection, + visit: ContingencyVisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup5: { + required: DeskBasedRequiredHiddenSectionGroup4And5Lgv, + vehicle: DeskBasedVehicleSectionGroup5Lgv, + test: DeskBasedTestSectionLgvGroup5, + visit: ContingencyVisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + }, + car: { + default: { + required: CreateRequiredSectionLgvCar, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: TestSection, + defects: defectsHiddenSection, + visit: ContingencyVisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup1: { + required: CreateRequiredSectionLgvCar, + vehicle: ContingencyIvaMsvaVehicleSection, + test: ContingencyTestSectionSpecialistGroup1, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + visit: ContingencyVisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup1OldIVAorMSVA: { + required: CreateRequiredSectionLgvCar, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: OldIVAContingencyTestSectionSpecialistGroup1, + customDefects: CustomDefectsSection, + visit: ContingencyVisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup4: { + required: DeskBasedRequiredHiddenSectionGroup4And5Lgv, + vehicle: DeskBasedVehicleSectionGroup4LGV, + test: DeskBasedTestSectionGroup4LgvCarMotorcycle, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup5: { + required: CreateRequiredSectionLgvCar, + vehicle: ContingencyIvaMsvaVehicleSection, + test: ContingencyTestSectionSpecialistGroup5, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + visit: ContingencyVisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup5OldIVAorMSVA: { + required: CreateRequiredSectionLgvCar, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: OldIVAContingencyTestSectionSpecialistGroup5, + customDefects: CustomDefectsSection, + visit: ContingencyVisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + }, + 'small trl': { + default: { + required: CreateRequiredSection, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: TestSection, + defects: defectsHiddenSection, + visit: ContingencyVisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup3: { + required: SpecialistRequiredSectionLgvCarSmallTrl, + vehicle: VehicleSectionGroup3, + test: SpecialistTestSectionGroup3, + customDefects: CustomDefectsHiddenSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + }, + motorcycle: { + default: { + required: CreateRequiredSection, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: TestSection, + defects: defectsHiddenSection, + visit: ContingencyVisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup1: { + required: CreateRequiredSectionMotorcycle, + vehicle: ContingencyIvaMsvaVehicleSection, + test: ContingencyTestSectionSpecialistGroup1, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + visit: ContingencyVisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup1OldIVAorMSVA: { + required: CreateRequiredSectionMotorcycle, + vehicle: ContingencyVehicleSectionDefaultPsvHgvLight, + test: OldIVAContingencyTestSectionSpecialistGroup1, + customDefects: CustomDefectsSection, + visit: ContingencyVisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup4: { + required: DeskBasedRequiredHiddenSectionGroup4Motorcyle, + vehicle: DeskBasedVehicleSectionGroup4LGV, + test: DeskBasedTestSectionGroup4LgvCarMotorcycle, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + }, }; diff --git a/src/app/forms/templates/test-records/master.template.ts b/src/app/forms/templates/test-records/master.template.ts index df1b10e05a..d137a86173 100644 --- a/src/app/forms/templates/test-records/master.template.ts +++ b/src/app/forms/templates/test-records/master.template.ts @@ -11,9 +11,7 @@ import { NotesSection } from './section-templates/notes/notes-section.template'; import { reasonForCreationSection } from './section-templates/reasonForCreation/reasonForCreation.template'; import { CustomDefectsHiddenSection } from './section-templates/required/custom-defects-hidden-section.template'; import { defectsHiddenSection } from './section-templates/required/defect-hidden-section.template'; -import { - AmendDeskBasedRequiredHiddenSectionGroup4Motorcyle, -} from './section-templates/required/desk-based-required-hidden-group4-motorcycle-amend.template'; +import { AmendDeskBasedRequiredHiddenSectionGroup4Motorcyle } from './section-templates/required/desk-based-required-hidden-group4-motorcycle-amend.template'; import { DeskBasedRequiredHiddenSectionGroup5Lgv } from './section-templates/required/desk-based-required-hidden-group5-lgv.template'; import { DeskBasedRequiredSectionHgvTrl } from './section-templates/required/desk-based-required-hidden-section-hgv-trl.template'; import { DeskBasedRequiredSectionPsv } from './section-templates/required/desk-based-required-hidden-section-psv.template'; @@ -39,8 +37,6 @@ import { SpecialistTestSectionGroup2 } from './section-templates/test/specialist import { SpecialistTestSectionGroup3And4 } from './section-templates/test/specialist/specialist-test-section-group3And4.template'; import { SpecialistTestSectionGroup5 } from './section-templates/test/specialist/specialist-test-section-group5.template'; import { TestSectionGroup1 } from './section-templates/test/test-section-group1.template'; -import { TestSectionGroup12And14 } from './section-templates/test/test-section-group12And14.template'; -import { TestSectionGroup15And16 } from './section-templates/test/test-section-group15And16.template'; import { TestSectionGroup2 } from './section-templates/test/test-section-group2.template'; import { TestSectionGroup3And4And8 } from './section-templates/test/test-section-group3And4And8.template'; import { TestSectionGroup5And13 } from './section-templates/test/test-section-group5And13.template'; @@ -49,15 +45,15 @@ import { TestSectionGroup7 } from './section-templates/test/test-section-group7. import { TestSectionGroup8Notifiable } from './section-templates/test/test-section-group8Notifiable.template'; import { TestSectionGroup9And10 } from './section-templates/test/test-section-group9And10.template'; import { TestSectionGroup9And10CentralDocs } from './section-templates/test/test-section-group9And10CentralDocs.template'; +import { TestSectionGroup12And14 } from './section-templates/test/test-section-group12And14.template'; +import { TestSectionGroup15And16 } from './section-templates/test/test-section-group15And16.template'; import { TestSection } from './section-templates/test/test-section.template'; import { IvaMsvaVehicleSection } from './section-templates/vehicle/amend-iva-msva-psv-hgv-light.template'; import { VehicleSectionDefaultPsvHgvLight } from './section-templates/vehicle/default-psv-hgv-light-vehicle-section.template'; import { VehicleSectionDefaultTrl } from './section-templates/vehicle/default-trl-vehicle-section.template'; import { DeskBasedVehicleSectionDefaultPsvHgv } from './section-templates/vehicle/desk-based-default-psv-hgv-vehicle-section.template'; import { DeskBasedVehicleSectionDefaultTrl } from './section-templates/vehicle/desk-based-default-trl-vehicle-section.template'; -import { - DeskBasedVehicleSectionHgvGroup1And2And4 as DeskBasedVehicleSectionHgvGroup1And2And4And5, -} from './section-templates/vehicle/desk-based-test-hgv-vehicle-section-group1And2And4.template'; +import { DeskBasedVehicleSectionHgvGroup1And2And4 as DeskBasedVehicleSectionHgvGroup1And2And4And5 } from './section-templates/vehicle/desk-based-test-hgv-vehicle-section-group1And2And4.template'; import { DeskBasedVehicleSectionGroup4LGV } from './section-templates/vehicle/desk-based-vehicle-section-group4-lgv.template'; import { DeskBasedVehicleSectionGroup5Lgv } from './section-templates/vehicle/desk-based-vehicle-section-group5-lgv.template'; import { VisitSection } from './section-templates/visit/visit-section.template'; @@ -67,698 +63,701 @@ import { VisitSection } from './section-templates/visit/visit-section.template'; * Keys of child object must be a valid test type id. * Child object must ALWAYS have a 'default' key. */ -export const masterTpl: Record>>> = { - psv: { - default: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSection, - seatbelts: SeatbeltSection, - emissions: EmissionsSection, - visit: VisitSection, - notes: NotesSection, - defects: DefectsTpl, - reasonForCreation: reasonForCreationSection, - customDefects: CustomDefectsSection, - required: RequiredSection, - }, - testTypesGroup1: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSectionGroup1, - seatbelts: SeatbeltSection, - visit: VisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSection, - }, - testTypesGroup2: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSectionGroup2, - seatbelts: SeatbeltSection, - visit: VisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSection, - }, - testTypesGroup3And4And8: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSectionGroup3And4And8, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSection, - }, - testTypesGroup8Notifiable: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSectionGroup8Notifiable, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSection, - }, - testTypesGroup15And16: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSectionGroup15And16, - emissions: EmissionsSection, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSection, - }, - testTypesSpecialistGroup1: { - vehicle: IvaMsvaVehicleSection, - test: SpecialistTestSectionGroup1, - visit: VisitSection, - notes: NotesSection, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSpecialistSection, - }, - testTypesSpecialistGroup1OldIVAorMSVA: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: OldIVASpecialistTestSectionGroup1, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSpecialistSection, - }, - testTypesSpecialistGroup2: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: SpecialistTestSectionGroup2, - seatbelts: SeatbeltSection, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSpecialistSection, - }, - testTypesSpecialistGroup3: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: SpecialistTestSectionGroup3And4, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSpecialistSection, - }, - testTypesSpecialistGroup4: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: SpecialistTestSectionGroup3And4, - seatbelts: SeatbeltSection, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSpecialistSection, - }, - testTypesSpecialistGroup5: { - vehicle: IvaMsvaVehicleSection, - test: SpecialistTestSectionGroup5, - visit: VisitSection, - notes: NotesSection, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSpecialistSection, - }, - testTypesSpecialistGroup5OldIVAorMSVA: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: OldIVASpecialistTestSectionGroup5, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSpecialistSection, - }, - testTypesDeskBasedGroup2: { - required: DeskBasedRequiredSectionPsv, - vehicle: DeskBasedVehicleSectionDefaultPsvHgv, - test: AmendDeskBasedTestSectionGroup2And5, - emissions: EmissionsSection, - visit: VisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup3: { - required: DeskBasedRequiredSectionPsv, - vehicle: DeskBasedVehicleSectionDefaultPsvHgv, - test: AmendDeskBasedTestSectionGroup3, - visit: VisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup4: { - required: RequiredSection, - vehicle: DeskBasedVehicleSectionDefaultPsvHgv, - test: amendDeskBasedTestSectionGroup4Psv, - visit: VisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup1: { - required: RequiredSection, - vehicle: DeskBasedVehicleSectionDefaultPsvHgv, - test: AmendDeskBasedTestSectionGroup1Psv, - visit: VisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - }, - hgv: { - default: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSection, - emissions: EmissionsSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - customDefects: CustomDefectsSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup3And4And8: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSectionGroup3And4And8, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup8Notifiable: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSectionGroup8Notifiable, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup5And13: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSectionGroup5And13, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - customDefects: CustomDefectsSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup6And11: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSectionGroup6And11, - visit: VisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup7: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSectionGroup7, - visit: VisitSection, - notes: AdrNotesSection, - reasonForCreation: reasonForCreationSection, - customDefects: CustomDefectsSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup9And10: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSectionGroup9And10, - visit: VisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup9And10CentralDocs: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSectionGroup9And10CentralDocs, - visit: VisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup12And14: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSectionGroup12And14, - visit: VisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup15And16: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSectionGroup15And16, - emissions: EmissionsSection, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSection, - }, - testTypesSpecialistGroup1: { - vehicle: IvaMsvaVehicleSection, - test: SpecialistTestSectionGroup1, - visit: VisitSection, - notes: NotesSection, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - reasonForCreation: reasonForCreationSection, - required: SpecialistRequiredSectionHGVTRL, - }, - testTypesSpecialistGroup1OldIVAorMSVA: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: OldIVASpecialistTestSectionGroup1, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: SpecialistRequiredSectionHGVTRL, - }, - testTypesSpecialistGroup5: { - vehicle: IvaMsvaVehicleSection, - test: SpecialistTestSectionGroup5, - visit: VisitSection, - notes: NotesSection, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - reasonForCreation: reasonForCreationSection, - required: SpecialistRequiredSectionHGVTRL, - }, - testTypesSpecialistGroup5OldIVAorMSVA: { - vehicle: VehicleSectionDefaultPsvHgvLight, - test: OldIVASpecialistTestSectionGroup5, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: SpecialistRequiredSectionHGVTRL, - }, - testTypesDeskBasedGroup1: { - required: RequiredSection, - vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, - test: amendDeskBasedTestSectionGroup1And4HgvTrl, - visit: VisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup2: { - required: DeskBasedRequiredSectionHgvTrl, - vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, - test: AmendDeskBasedTestSectionGroup2And5, - visit: VisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup3: { - required: DeskBasedRequiredSectionHgvTrl, - vehicle: DeskBasedVehicleSectionDefaultPsvHgv, - test: AmendDeskBasedTestSectionGroup3, - visit: VisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup4: { - required: RequiredSection, - vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, - test: amendDeskBasedTestSectionGroup1And4HgvTrl, - visit: VisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup5: { - required: RequiredSection, - vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, - test: AmendDeskBasedTestSectionGroup2And5, - visit: VisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - }, - trl: { - default: { - vehicle: VehicleSectionDefaultTrl, - test: TestSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - customDefects: CustomDefectsSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup3And4And8: { - vehicle: VehicleSectionDefaultTrl, - test: TestSectionGroup3And4And8, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup8Notifiable: { - vehicle: VehicleSectionDefaultTrl, - test: TestSectionGroup8Notifiable, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup5And13: { - vehicle: VehicleSectionDefaultTrl, - test: TestSectionGroup5And13, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - customDefects: CustomDefectsSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup6And11: { - vehicle: VehicleSectionDefaultTrl, - test: TestSectionGroup6And11, - visit: VisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup7: { - vehicle: VehicleSectionDefaultTrl, - test: TestSectionGroup7, - visit: VisitSection, - notes: AdrNotesSection, - reasonForCreation: reasonForCreationSection, - customDefects: CustomDefectsSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup9And10: { - vehicle: VehicleSectionDefaultTrl, - test: TestSectionGroup9And10, - visit: VisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup9And10CentralDocs: { - vehicle: VehicleSectionDefaultTrl, - test: TestSectionGroup9And10CentralDocs, - visit: VisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSectionHGVTRL, - }, - testTypesGroup12And14: { - vehicle: VehicleSectionDefaultTrl, - test: TestSectionGroup12And14, - visit: VisitSection, - notes: NotesSection, - defects: DefectsTpl, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - required: RequiredSectionHGVTRL, - }, - testTypesSpecialistGroup1: { - vehicle: VehicleSectionDefaultTrl, - test: SpecialistTestSectionGroup1, - visit: VisitSection, - notes: NotesSection, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - reasonForCreation: reasonForCreationSection, - required: SpecialistRequiredSectionHGVTRL, - }, - testTypesSpecialistGroup1OldIVAorMSVA: { - vehicle: VehicleSectionDefaultTrl, - test: OldIVASpecialistTestSectionGroup1, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: SpecialistRequiredSectionHGVTRL, - }, - testTypesSpecialistGroup5: { - vehicle: VehicleSectionDefaultTrl, - test: SpecialistTestSectionGroup5, - visit: VisitSection, - notes: NotesSection, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - reasonForCreation: reasonForCreationSection, - required: SpecialistRequiredSectionHGVTRL, - }, - testTypesSpecialistGroup5OldIVAorMSVA: { - vehicle: VehicleSectionDefaultTrl, - test: OldIVASpecialistTestSectionGroup5, - visit: VisitSection, - notes: NotesSection, - customDefects: CustomDefectsSection, - reasonForCreation: reasonForCreationSection, - required: SpecialistRequiredSectionHGVTRL, - }, - testTypesDeskBasedGroup1: { - required: RequiredSection, - vehicle: DeskBasedVehicleSectionDefaultTrl, - test: amendDeskBasedTestSectionGroup1And4HgvTrl, - visit: VisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup2: { - required: DeskBasedRequiredSectionHgvTrl, - vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, - test: AmendDeskBasedTestSectionGroup2And5, - visit: VisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup3: { - required: DeskBasedRequiredSectionHgvTrl, - vehicle: DeskBasedVehicleSectionDefaultTrl, - test: AmendDeskBasedTestSectionGroup3, - visit: VisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup4: { - required: RequiredSection, - vehicle: DeskBasedVehicleSectionDefaultTrl, - test: amendDeskBasedTestSectionGroup1And4HgvTrl, - visit: VisitSection, - notes: NotesSection, - defects: defectsHiddenSection, - customDefects: CustomDefectsHiddenSection, - reasonForCreation: reasonForCreationSection, - }, - }, - lgv: { - default: { - required: SpecialistRequiredSectionLgvCarSmallTrl, - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSection, - defects: defectsHiddenSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup1: { - required: SpecialistRequiredSectionLgvCarSmallTrl, - vehicle: IvaMsvaVehicleSection, - test: SpecialistTestSectionGroup1, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup1OldIVAorMSVA: { - required: SpecialistRequiredSectionLgvCarSmallTrl, - vehicle: VehicleSectionDefaultPsvHgvLight, - test: OldIVASpecialistTestSectionGroup1, - customDefects: CustomDefectsSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup5: { - required: SpecialistRequiredSectionLgvCarSmallTrl, - vehicle: IvaMsvaVehicleSection, - test: SpecialistTestSectionGroup5, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup5OldIVAorMSVA: { - required: SpecialistRequiredSectionLgvCarSmallTrl, - vehicle: VehicleSectionDefaultPsvHgvLight, - test: OldIVASpecialistTestSectionGroup5, - customDefects: CustomDefectsSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup4: { - required: AmendDeskBasedRequiredHiddenSectionGroup4, - vehicle: DeskBasedVehicleSectionGroup4LGV, - test: AmendDeskBasedTestSectionGroup4LgvCarMotorcycle, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup5: { - required: DeskBasedRequiredHiddenSectionGroup5Lgv, - vehicle: DeskBasedVehicleSectionGroup5Lgv, - test: AmendDeskBasedTestSectionLgvGroup5, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - }, - car: { - default: { - required: RequiredSpecialistSection, - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSection, - defects: defectsHiddenSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup1: { - required: SpecialistRequiredSectionLgvCarSmallTrl, - vehicle: IvaMsvaVehicleSection, - test: SpecialistTestSectionGroup1, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup1OldIVAorMSVA: { - required: SpecialistRequiredSectionLgvCarSmallTrl, - vehicle: VehicleSectionDefaultPsvHgvLight, - test: OldIVASpecialistTestSectionGroup1, - customDefects: CustomDefectsSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup5: { - required: SpecialistRequiredSectionLgvCarSmallTrl, - vehicle: IvaMsvaVehicleSection, - test: SpecialistTestSectionGroup5, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup5OldIVAorMSVA: { - required: SpecialistRequiredSectionLgvCarSmallTrl, - vehicle: VehicleSectionDefaultPsvHgvLight, - test: OldIVASpecialistTestSectionGroup5, - customDefects: CustomDefectsSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup4: { - required: AmendDeskBasedRequiredHiddenSectionGroup4, - vehicle: DeskBasedVehicleSectionGroup4LGV, - test: AmendDeskBasedTestSectionGroup4LgvCarMotorcycle, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - }, - 'small trl': { - default: { - required: RequiredSpecialistSection, - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSection, - defects: defectsHiddenSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - }, - motorcycle: { - default: { - required: RequiredSpecialistSection, - vehicle: VehicleSectionDefaultPsvHgvLight, - test: TestSection, - defects: defectsHiddenSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup1: { - required: RequiredSpecialistSectionMotorcycle, - vehicle: IvaMsvaVehicleSection, - test: SpecialistTestSectionGroup1, - requiredStandards: RequiredStandardsTpl, - customDefects: AdditionalDefectsSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesSpecialistGroup1OldIVAorMSVA: { - required: RequiredSpecialistSectionMotorcycle, - vehicle: VehicleSectionDefaultPsvHgvLight, - test: OldIVASpecialistTestSectionGroup1, - customDefects: CustomDefectsSection, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - testTypesDeskBasedGroup4: { - required: AmendDeskBasedRequiredHiddenSectionGroup4Motorcyle, - vehicle: DeskBasedVehicleSectionGroup4LGV, - test: AmendDeskBasedTestSectionGroup4LgvCarMotorcycle, - visit: VisitSection, - notes: NotesSection, - reasonForCreation: reasonForCreationSection, - }, - }, +export const masterTpl: Record< + VehicleTypes, + Partial>> +> = { + psv: { + default: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSection, + seatbelts: SeatbeltSection, + emissions: EmissionsSection, + visit: VisitSection, + notes: NotesSection, + defects: DefectsTpl, + reasonForCreation: reasonForCreationSection, + customDefects: CustomDefectsSection, + required: RequiredSection, + }, + testTypesGroup1: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSectionGroup1, + seatbelts: SeatbeltSection, + visit: VisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSection, + }, + testTypesGroup2: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSectionGroup2, + seatbelts: SeatbeltSection, + visit: VisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSection, + }, + testTypesGroup3And4And8: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSectionGroup3And4And8, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSection, + }, + testTypesGroup8Notifiable: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSectionGroup8Notifiable, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSection, + }, + testTypesGroup15And16: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSectionGroup15And16, + emissions: EmissionsSection, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSection, + }, + testTypesSpecialistGroup1: { + vehicle: IvaMsvaVehicleSection, + test: SpecialistTestSectionGroup1, + visit: VisitSection, + notes: NotesSection, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSpecialistSection, + }, + testTypesSpecialistGroup1OldIVAorMSVA: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: OldIVASpecialistTestSectionGroup1, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSpecialistSection, + }, + testTypesSpecialistGroup2: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: SpecialistTestSectionGroup2, + seatbelts: SeatbeltSection, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSpecialistSection, + }, + testTypesSpecialistGroup3: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: SpecialistTestSectionGroup3And4, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSpecialistSection, + }, + testTypesSpecialistGroup4: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: SpecialistTestSectionGroup3And4, + seatbelts: SeatbeltSection, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSpecialistSection, + }, + testTypesSpecialistGroup5: { + vehicle: IvaMsvaVehicleSection, + test: SpecialistTestSectionGroup5, + visit: VisitSection, + notes: NotesSection, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSpecialistSection, + }, + testTypesSpecialistGroup5OldIVAorMSVA: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: OldIVASpecialistTestSectionGroup5, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSpecialistSection, + }, + testTypesDeskBasedGroup2: { + required: DeskBasedRequiredSectionPsv, + vehicle: DeskBasedVehicleSectionDefaultPsvHgv, + test: AmendDeskBasedTestSectionGroup2And5, + emissions: EmissionsSection, + visit: VisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup3: { + required: DeskBasedRequiredSectionPsv, + vehicle: DeskBasedVehicleSectionDefaultPsvHgv, + test: AmendDeskBasedTestSectionGroup3, + visit: VisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup4: { + required: RequiredSection, + vehicle: DeskBasedVehicleSectionDefaultPsvHgv, + test: amendDeskBasedTestSectionGroup4Psv, + visit: VisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup1: { + required: RequiredSection, + vehicle: DeskBasedVehicleSectionDefaultPsvHgv, + test: AmendDeskBasedTestSectionGroup1Psv, + visit: VisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + }, + hgv: { + default: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSection, + emissions: EmissionsSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + customDefects: CustomDefectsSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup3And4And8: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSectionGroup3And4And8, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup8Notifiable: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSectionGroup8Notifiable, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup5And13: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSectionGroup5And13, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + customDefects: CustomDefectsSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup6And11: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSectionGroup6And11, + visit: VisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup7: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSectionGroup7, + visit: VisitSection, + notes: AdrNotesSection, + reasonForCreation: reasonForCreationSection, + customDefects: CustomDefectsSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup9And10: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSectionGroup9And10, + visit: VisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup9And10CentralDocs: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSectionGroup9And10CentralDocs, + visit: VisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup12And14: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSectionGroup12And14, + visit: VisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup15And16: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSectionGroup15And16, + emissions: EmissionsSection, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSection, + }, + testTypesSpecialistGroup1: { + vehicle: IvaMsvaVehicleSection, + test: SpecialistTestSectionGroup1, + visit: VisitSection, + notes: NotesSection, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + reasonForCreation: reasonForCreationSection, + required: SpecialistRequiredSectionHGVTRL, + }, + testTypesSpecialistGroup1OldIVAorMSVA: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: OldIVASpecialistTestSectionGroup1, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: SpecialistRequiredSectionHGVTRL, + }, + testTypesSpecialistGroup5: { + vehicle: IvaMsvaVehicleSection, + test: SpecialistTestSectionGroup5, + visit: VisitSection, + notes: NotesSection, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + reasonForCreation: reasonForCreationSection, + required: SpecialistRequiredSectionHGVTRL, + }, + testTypesSpecialistGroup5OldIVAorMSVA: { + vehicle: VehicleSectionDefaultPsvHgvLight, + test: OldIVASpecialistTestSectionGroup5, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: SpecialistRequiredSectionHGVTRL, + }, + testTypesDeskBasedGroup1: { + required: RequiredSection, + vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, + test: amendDeskBasedTestSectionGroup1And4HgvTrl, + visit: VisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup2: { + required: DeskBasedRequiredSectionHgvTrl, + vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, + test: AmendDeskBasedTestSectionGroup2And5, + visit: VisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup3: { + required: DeskBasedRequiredSectionHgvTrl, + vehicle: DeskBasedVehicleSectionDefaultPsvHgv, + test: AmendDeskBasedTestSectionGroup3, + visit: VisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup4: { + required: RequiredSection, + vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, + test: amendDeskBasedTestSectionGroup1And4HgvTrl, + visit: VisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup5: { + required: RequiredSection, + vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, + test: AmendDeskBasedTestSectionGroup2And5, + visit: VisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + }, + trl: { + default: { + vehicle: VehicleSectionDefaultTrl, + test: TestSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + customDefects: CustomDefectsSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup3And4And8: { + vehicle: VehicleSectionDefaultTrl, + test: TestSectionGroup3And4And8, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup8Notifiable: { + vehicle: VehicleSectionDefaultTrl, + test: TestSectionGroup8Notifiable, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup5And13: { + vehicle: VehicleSectionDefaultTrl, + test: TestSectionGroup5And13, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + customDefects: CustomDefectsSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup6And11: { + vehicle: VehicleSectionDefaultTrl, + test: TestSectionGroup6And11, + visit: VisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup7: { + vehicle: VehicleSectionDefaultTrl, + test: TestSectionGroup7, + visit: VisitSection, + notes: AdrNotesSection, + reasonForCreation: reasonForCreationSection, + customDefects: CustomDefectsSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup9And10: { + vehicle: VehicleSectionDefaultTrl, + test: TestSectionGroup9And10, + visit: VisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup9And10CentralDocs: { + vehicle: VehicleSectionDefaultTrl, + test: TestSectionGroup9And10CentralDocs, + visit: VisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSectionHGVTRL, + }, + testTypesGroup12And14: { + vehicle: VehicleSectionDefaultTrl, + test: TestSectionGroup12And14, + visit: VisitSection, + notes: NotesSection, + defects: DefectsTpl, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + required: RequiredSectionHGVTRL, + }, + testTypesSpecialistGroup1: { + vehicle: VehicleSectionDefaultTrl, + test: SpecialistTestSectionGroup1, + visit: VisitSection, + notes: NotesSection, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + reasonForCreation: reasonForCreationSection, + required: SpecialistRequiredSectionHGVTRL, + }, + testTypesSpecialistGroup1OldIVAorMSVA: { + vehicle: VehicleSectionDefaultTrl, + test: OldIVASpecialistTestSectionGroup1, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: SpecialistRequiredSectionHGVTRL, + }, + testTypesSpecialistGroup5: { + vehicle: VehicleSectionDefaultTrl, + test: SpecialistTestSectionGroup5, + visit: VisitSection, + notes: NotesSection, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + reasonForCreation: reasonForCreationSection, + required: SpecialistRequiredSectionHGVTRL, + }, + testTypesSpecialistGroup5OldIVAorMSVA: { + vehicle: VehicleSectionDefaultTrl, + test: OldIVASpecialistTestSectionGroup5, + visit: VisitSection, + notes: NotesSection, + customDefects: CustomDefectsSection, + reasonForCreation: reasonForCreationSection, + required: SpecialistRequiredSectionHGVTRL, + }, + testTypesDeskBasedGroup1: { + required: RequiredSection, + vehicle: DeskBasedVehicleSectionDefaultTrl, + test: amendDeskBasedTestSectionGroup1And4HgvTrl, + visit: VisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup2: { + required: DeskBasedRequiredSectionHgvTrl, + vehicle: DeskBasedVehicleSectionHgvGroup1And2And4And5, + test: AmendDeskBasedTestSectionGroup2And5, + visit: VisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup3: { + required: DeskBasedRequiredSectionHgvTrl, + vehicle: DeskBasedVehicleSectionDefaultTrl, + test: AmendDeskBasedTestSectionGroup3, + visit: VisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup4: { + required: RequiredSection, + vehicle: DeskBasedVehicleSectionDefaultTrl, + test: amendDeskBasedTestSectionGroup1And4HgvTrl, + visit: VisitSection, + notes: NotesSection, + defects: defectsHiddenSection, + customDefects: CustomDefectsHiddenSection, + reasonForCreation: reasonForCreationSection, + }, + }, + lgv: { + default: { + required: SpecialistRequiredSectionLgvCarSmallTrl, + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSection, + defects: defectsHiddenSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup1: { + required: SpecialistRequiredSectionLgvCarSmallTrl, + vehicle: IvaMsvaVehicleSection, + test: SpecialistTestSectionGroup1, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup1OldIVAorMSVA: { + required: SpecialistRequiredSectionLgvCarSmallTrl, + vehicle: VehicleSectionDefaultPsvHgvLight, + test: OldIVASpecialistTestSectionGroup1, + customDefects: CustomDefectsSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup5: { + required: SpecialistRequiredSectionLgvCarSmallTrl, + vehicle: IvaMsvaVehicleSection, + test: SpecialistTestSectionGroup5, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup5OldIVAorMSVA: { + required: SpecialistRequiredSectionLgvCarSmallTrl, + vehicle: VehicleSectionDefaultPsvHgvLight, + test: OldIVASpecialistTestSectionGroup5, + customDefects: CustomDefectsSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup4: { + required: AmendDeskBasedRequiredHiddenSectionGroup4, + vehicle: DeskBasedVehicleSectionGroup4LGV, + test: AmendDeskBasedTestSectionGroup4LgvCarMotorcycle, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup5: { + required: DeskBasedRequiredHiddenSectionGroup5Lgv, + vehicle: DeskBasedVehicleSectionGroup5Lgv, + test: AmendDeskBasedTestSectionLgvGroup5, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + }, + car: { + default: { + required: RequiredSpecialistSection, + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSection, + defects: defectsHiddenSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup1: { + required: SpecialistRequiredSectionLgvCarSmallTrl, + vehicle: IvaMsvaVehicleSection, + test: SpecialistTestSectionGroup1, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup1OldIVAorMSVA: { + required: SpecialistRequiredSectionLgvCarSmallTrl, + vehicle: VehicleSectionDefaultPsvHgvLight, + test: OldIVASpecialistTestSectionGroup1, + customDefects: CustomDefectsSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup5: { + required: SpecialistRequiredSectionLgvCarSmallTrl, + vehicle: IvaMsvaVehicleSection, + test: SpecialistTestSectionGroup5, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup5OldIVAorMSVA: { + required: SpecialistRequiredSectionLgvCarSmallTrl, + vehicle: VehicleSectionDefaultPsvHgvLight, + test: OldIVASpecialistTestSectionGroup5, + customDefects: CustomDefectsSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup4: { + required: AmendDeskBasedRequiredHiddenSectionGroup4, + vehicle: DeskBasedVehicleSectionGroup4LGV, + test: AmendDeskBasedTestSectionGroup4LgvCarMotorcycle, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + }, + 'small trl': { + default: { + required: RequiredSpecialistSection, + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSection, + defects: defectsHiddenSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + }, + motorcycle: { + default: { + required: RequiredSpecialistSection, + vehicle: VehicleSectionDefaultPsvHgvLight, + test: TestSection, + defects: defectsHiddenSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup1: { + required: RequiredSpecialistSectionMotorcycle, + vehicle: IvaMsvaVehicleSection, + test: SpecialistTestSectionGroup1, + requiredStandards: RequiredStandardsTpl, + customDefects: AdditionalDefectsSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesSpecialistGroup1OldIVAorMSVA: { + required: RequiredSpecialistSectionMotorcycle, + vehicle: VehicleSectionDefaultPsvHgvLight, + test: OldIVASpecialistTestSectionGroup1, + customDefects: CustomDefectsSection, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + testTypesDeskBasedGroup4: { + required: AmendDeskBasedRequiredHiddenSectionGroup4Motorcyle, + vehicle: DeskBasedVehicleSectionGroup4LGV, + test: AmendDeskBasedTestSectionGroup4LgvCarMotorcycle, + visit: VisitSection, + notes: NotesSection, + reasonForCreation: reasonForCreationSection, + }, + }, }; diff --git a/src/app/forms/templates/test-records/section-templates/additionalDefects/additional-defects-section.template.ts b/src/app/forms/templates/test-records/section-templates/additionalDefects/additional-defects-section.template.ts index f4f4f6fe48..809de0aa3f 100644 --- a/src/app/forms/templates/test-records/section-templates/additionalDefects/additional-defects-section.template.ts +++ b/src/app/forms/templates/test-records/section-templates/additionalDefects/additional-defects-section.template.ts @@ -2,46 +2,46 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { FormNode, FormNodeTypes } from '@forms/services/dynamic-form.types'; export const AdditionalDefectsSection: FormNode = { - name: 'additionalDefectsSection', - label: 'Additional Defects', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'customDefects', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'defectName', - label: 'Defect Name', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Required }, { name: ValidatorNames.MaxLength, args: 200 }], - }, - { - name: 'defectNotes', - label: 'Defect Notes', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Required }, { name: ValidatorNames.MaxLength, args: 200 }], - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], + name: 'additionalDefectsSection', + label: 'Additional Defects', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'customDefects', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'defectName', + label: 'Defect Name', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Required }, { name: ValidatorNames.MaxLength, args: 200 }], + }, + { + name: 'defectNotes', + label: 'Defect Notes', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Required }, { name: ValidatorNames.MaxLength, args: 200 }], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/customDefects/custom-defects-section.template.ts b/src/app/forms/templates/test-records/section-templates/customDefects/custom-defects-section.template.ts index eb20f82085..830080d065 100644 --- a/src/app/forms/templates/test-records/section-templates/customDefects/custom-defects-section.template.ts +++ b/src/app/forms/templates/test-records/section-templates/customDefects/custom-defects-section.template.ts @@ -2,53 +2,53 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { FormNode, FormNodeTypes, FormNodeWidth } from '@forms/services/dynamic-form.types'; export const CustomDefectsSection: FormNode = { - name: 'customDefectsSection', - label: 'Custom Defects', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'customDefects', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'referenceNumber', - label: 'Reference Number', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Required }, { name: ValidatorNames.MaxLength, args: 10 }], - width: FormNodeWidth.XL, - }, - { - name: 'defectName', - label: 'Defect Name', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Required }, { name: ValidatorNames.MaxLength, args: 200 }], - }, - { - name: 'defectNotes', - label: 'Defect Notes', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.Required }, { name: ValidatorNames.MaxLength, args: 200 }], - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], + name: 'customDefectsSection', + label: 'Custom Defects', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'customDefects', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'referenceNumber', + label: 'Reference Number', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Required }, { name: ValidatorNames.MaxLength, args: 10 }], + width: FormNodeWidth.XL, + }, + { + name: 'defectName', + label: 'Defect Name', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Required }, { name: ValidatorNames.MaxLength, args: 200 }], + }, + { + name: 'defectNotes', + label: 'Defect Notes', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.Required }, { name: ValidatorNames.MaxLength, args: 200 }], + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/emissions/desk-based-emissions-section.template.ts b/src/app/forms/templates/test-records/section-templates/emissions/desk-based-emissions-section.template.ts index 11db5133fa..8668a118f0 100644 --- a/src/app/forms/templates/test-records/section-templates/emissions/desk-based-emissions-section.template.ts +++ b/src/app/forms/templates/test-records/section-templates/emissions/desk-based-emissions-section.template.ts @@ -1,142 +1,152 @@ -import { FormNode, FormNodeTypes, FormNodeEditTypes } from '@forms/services/dynamic-form.types'; -import { ValidatorNames } from '@forms/models/validators.enum'; import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; -import { EmissionStandard } from '@models/test-types/emissions.enum'; +import { ValidatorNames } from '@forms/models/validators.enum'; +import { FormNode, FormNodeEditTypes, FormNodeTypes } from '@forms/services/dynamic-form.types'; import { getOptionsFromEnum } from '@forms/utils/enum-map'; +import { EmissionStandard } from '@models/test-types/emissions.enum'; export const DeskBasedEmissionsSection: FormNode = { - name: 'deskBasedEmissionsSection', - label: 'Emissions', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'emissionStandard', - label: 'Emissions standard', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [{ label: '0.10 g/kWh Euro III PM', value: '0.10 g/kWh Euro 3 PM' }, - ...getOptionsFromEnum(EmissionStandard), - ], - required: true, - value: null, - }, - { - name: 'smokeTestKLimitApplied', - label: 'Smoke test K limit applied', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 100 }], - required: true, - value: null, - }, - { - name: 'fuelType', - label: 'Fuel type', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'diesel', label: 'Diesel' }, - { value: 'gas-cng', label: 'Gas-CNG' }, - { value: 'gas-lng', label: 'Gas-LNG' }, - { value: 'gas-lpg', label: 'Gas-LPG' }, - { value: 'fuel cell', label: 'Fuel cell' }, - { value: 'petrol', label: 'Petrol' }, - { value: 'full electric', label: 'Full electric' }, - ], - required: true, - value: null, - }, - { - name: 'modType', - label: 'Modification Type', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'code', - label: 'Modification code', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'p', label: 'P' }, - { value: 'm', label: 'M' }, - { value: 'g', label: 'G' }, - ], - validators: [ - { name: ValidatorNames.HideIfParentSiblingEqual, args: { sibling: 'modificationTypeUsed', value: 'p' } }, - { name: ValidatorNames.HideIfParentSiblingNotEqual, args: { sibling: 'particulateTrapFitted', value: 'p' } }, - { name: ValidatorNames.HideIfParentSiblingNotEqual, args: { sibling: 'particulateTrapSerialNumber', value: 'p' } }, - ], - }, - { - name: 'description', - label: 'Modification description', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'particulate trap', label: 'Particulate trap' }, - { value: 'modification or change of engine', label: 'Modification or change of engine' }, - { value: 'gas engine', label: 'Gas engine' }, - ], - }, - ], - }, - { - name: 'modificationTypeUsed', - label: 'Modification type used', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 100 }], - asyncValidators: [ - { - name: AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, - args: { testResult: ['fail', 'abandoned'], sibling: 'modType.code', value: 'm' }, - }, - { - name: AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, - args: { testResult: ['fail', 'abandoned'], sibling: 'modType.code', value: 'g' }, - }, - ], - required: true, - value: null, - }, - { - name: 'particulateTrapFitted', - label: 'Particulate trap fitted', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 100 }], - asyncValidators: [ - { - name: AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, - args: { testResult: ['fail', 'abandoned'], sibling: 'modType.code', value: 'p' }, - }, - ], - required: true, - value: null, - }, - { - name: 'particulateTrapSerialNumber', - label: 'Particulate trap serial number', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 100 }], - asyncValidators: [ - { - name: AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, - args: { testResult: ['fail', 'abandoned'], sibling: 'modType.code', value: 'p' }, - }, - ], - required: true, - value: null, - }, - ], - }, - ], - }, - ], + name: 'deskBasedEmissionsSection', + label: 'Emissions', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'emissionStandard', + label: 'Emissions standard', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { label: '0.10 g/kWh Euro III PM', value: '0.10 g/kWh Euro 3 PM' }, + ...getOptionsFromEnum(EmissionStandard), + ], + required: true, + value: null, + }, + { + name: 'smokeTestKLimitApplied', + label: 'Smoke test K limit applied', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 100 }], + required: true, + value: null, + }, + { + name: 'fuelType', + label: 'Fuel type', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'diesel', label: 'Diesel' }, + { value: 'gas-cng', label: 'Gas-CNG' }, + { value: 'gas-lng', label: 'Gas-LNG' }, + { value: 'gas-lpg', label: 'Gas-LPG' }, + { value: 'fuel cell', label: 'Fuel cell' }, + { value: 'petrol', label: 'Petrol' }, + { value: 'full electric', label: 'Full electric' }, + ], + required: true, + value: null, + }, + { + name: 'modType', + label: 'Modification Type', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'code', + label: 'Modification code', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'p', label: 'P' }, + { value: 'm', label: 'M' }, + { value: 'g', label: 'G' }, + ], + validators: [ + { + name: ValidatorNames.HideIfParentSiblingEqual, + args: { sibling: 'modificationTypeUsed', value: 'p' }, + }, + { + name: ValidatorNames.HideIfParentSiblingNotEqual, + args: { sibling: 'particulateTrapFitted', value: 'p' }, + }, + { + name: ValidatorNames.HideIfParentSiblingNotEqual, + args: { sibling: 'particulateTrapSerialNumber', value: 'p' }, + }, + ], + }, + { + name: 'description', + label: 'Modification description', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'particulate trap', label: 'Particulate trap' }, + { value: 'modification or change of engine', label: 'Modification or change of engine' }, + { value: 'gas engine', label: 'Gas engine' }, + ], + }, + ], + }, + { + name: 'modificationTypeUsed', + label: 'Modification type used', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 100 }], + asyncValidators: [ + { + name: AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, + args: { testResult: ['fail', 'abandoned'], sibling: 'modType.code', value: 'm' }, + }, + { + name: AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, + args: { testResult: ['fail', 'abandoned'], sibling: 'modType.code', value: 'g' }, + }, + ], + required: true, + value: null, + }, + { + name: 'particulateTrapFitted', + label: 'Particulate trap fitted', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 100 }], + asyncValidators: [ + { + name: AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, + args: { testResult: ['fail', 'abandoned'], sibling: 'modType.code', value: 'p' }, + }, + ], + required: true, + value: null, + }, + { + name: 'particulateTrapSerialNumber', + label: 'Particulate trap serial number', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 100 }], + asyncValidators: [ + { + name: AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, + args: { testResult: ['fail', 'abandoned'], sibling: 'modType.code', value: 'p' }, + }, + ], + required: true, + value: null, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/emissions/emissions-section.template.ts b/src/app/forms/templates/test-records/section-templates/emissions/emissions-section.template.ts index 1d6fbd318a..77b3a33b51 100644 --- a/src/app/forms/templates/test-records/section-templates/emissions/emissions-section.template.ts +++ b/src/app/forms/templates/test-records/section-templates/emissions/emissions-section.template.ts @@ -1,146 +1,164 @@ -import { FormNode, FormNodeTypes, FormNodeEditTypes } from '@forms/services/dynamic-form.types'; -import { ValidatorNames } from '@forms/models/validators.enum'; import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; -import { EmissionStandard } from '@models/test-types/emissions.enum'; +import { ValidatorNames } from '@forms/models/validators.enum'; +import { FormNode, FormNodeEditTypes, FormNodeTypes } from '@forms/services/dynamic-form.types'; import { getOptionsFromEnum } from '@forms/utils/enum-map'; +import { EmissionStandard } from '@models/test-types/emissions.enum'; export const EmissionsSection: FormNode = { - name: 'emissionsSection', - label: 'Emissions', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'emissionStandard', - label: 'Emissions standard', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [{ label: '0.10 g/kWh Euro III PM', value: '0.10 g/kWh Euro 3 PM' }, - ...getOptionsFromEnum(EmissionStandard), - ], - asyncValidators: [{ name: AsyncValidatorNames.RequiredIfNotResult, args: { testResult: ['fail', 'abandoned'] } }], - required: true, - value: null, - }, - { - name: 'smokeTestKLimitApplied', - label: 'Smoke test K limit applied', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 100 }], - asyncValidators: [{ name: AsyncValidatorNames.RequiredIfNotResult, args: { testResult: ['fail', 'abandoned'] } }], - required: true, - value: null, - }, - { - name: 'fuelType', - label: 'Fuel type', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'diesel', label: 'Diesel' }, - { value: 'gas-cng', label: 'Gas-CNG' }, - { value: 'gas-lng', label: 'Gas-LNG' }, - { value: 'gas-lpg', label: 'Gas-LPG' }, - { value: 'fuel cell', label: 'Fuel cell' }, - { value: 'petrol', label: 'Petrol' }, - { value: 'full electric', label: 'Full electric' }, - ], - asyncValidators: [{ name: AsyncValidatorNames.RequiredIfNotResult, args: { testResult: ['fail', 'abandoned'] } }], - required: true, - value: null, - }, - { - name: 'modType', - label: 'Modification Type', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'code', - label: 'Modification code', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'p', label: 'P' }, - { value: 'm', label: 'M' }, - { value: 'g', label: 'G' }, - ], - validators: [ - { name: ValidatorNames.HideIfParentSiblingEqual, args: { sibling: 'modificationTypeUsed', value: 'p' } }, - { name: ValidatorNames.HideIfParentSiblingNotEqual, args: { sibling: 'particulateTrapFitted', value: 'p' } }, - { name: ValidatorNames.HideIfParentSiblingNotEqual, args: { sibling: 'particulateTrapSerialNumber', value: 'p' } }, - ], - asyncValidators: [{ name: AsyncValidatorNames.RequiredIfNotResult, args: { testResult: ['fail', 'abandoned'] } }], - }, - { - name: 'description', - label: 'Modification description', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'particulate trap', label: 'Particulate trap' }, - { value: 'modification or change of engine', label: 'Modification or change of engine' }, - { value: 'gas engine', label: 'Gas engine' }, - ], - }, - ], - }, - { - name: 'modificationTypeUsed', - label: 'Modification type used', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 100 }], - asyncValidators: [ - { - name: AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, - args: { testResult: ['fail', 'abandoned'], sibling: 'modType.code', value: 'm' }, - }, - { - name: AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, - args: { testResult: ['fail', 'abandoned'], sibling: 'modType.code', value: 'g' }, - }, - ], - required: true, - value: null, - }, - { - name: 'particulateTrapFitted', - label: 'Particulate trap fitted', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 100 }], - asyncValidators: [ - { - name: AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, - args: { testResult: ['fail', 'abandoned'], sibling: 'modType.code', value: 'p' }, - }, - ], - required: true, - value: null, - }, - { - name: 'particulateTrapSerialNumber', - label: 'Particulate trap serial number', - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.MaxLength, args: 100 }], - asyncValidators: [ - { - name: AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, - args: { testResult: ['fail', 'abandoned'], sibling: 'modType.code', value: 'p' }, - }, - ], - required: true, - value: null, - }, - ], - }, - ], - }, - ], + name: 'emissionsSection', + label: 'Emissions', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'emissionStandard', + label: 'Emissions standard', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { label: '0.10 g/kWh Euro III PM', value: '0.10 g/kWh Euro 3 PM' }, + ...getOptionsFromEnum(EmissionStandard), + ], + asyncValidators: [ + { name: AsyncValidatorNames.RequiredIfNotResult, args: { testResult: ['fail', 'abandoned'] } }, + ], + required: true, + value: null, + }, + { + name: 'smokeTestKLimitApplied', + label: 'Smoke test K limit applied', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 100 }], + asyncValidators: [ + { name: AsyncValidatorNames.RequiredIfNotResult, args: { testResult: ['fail', 'abandoned'] } }, + ], + required: true, + value: null, + }, + { + name: 'fuelType', + label: 'Fuel type', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'diesel', label: 'Diesel' }, + { value: 'gas-cng', label: 'Gas-CNG' }, + { value: 'gas-lng', label: 'Gas-LNG' }, + { value: 'gas-lpg', label: 'Gas-LPG' }, + { value: 'fuel cell', label: 'Fuel cell' }, + { value: 'petrol', label: 'Petrol' }, + { value: 'full electric', label: 'Full electric' }, + ], + asyncValidators: [ + { name: AsyncValidatorNames.RequiredIfNotResult, args: { testResult: ['fail', 'abandoned'] } }, + ], + required: true, + value: null, + }, + { + name: 'modType', + label: 'Modification Type', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'code', + label: 'Modification code', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'p', label: 'P' }, + { value: 'm', label: 'M' }, + { value: 'g', label: 'G' }, + ], + validators: [ + { + name: ValidatorNames.HideIfParentSiblingEqual, + args: { sibling: 'modificationTypeUsed', value: 'p' }, + }, + { + name: ValidatorNames.HideIfParentSiblingNotEqual, + args: { sibling: 'particulateTrapFitted', value: 'p' }, + }, + { + name: ValidatorNames.HideIfParentSiblingNotEqual, + args: { sibling: 'particulateTrapSerialNumber', value: 'p' }, + }, + ], + asyncValidators: [ + { name: AsyncValidatorNames.RequiredIfNotResult, args: { testResult: ['fail', 'abandoned'] } }, + ], + }, + { + name: 'description', + label: 'Modification description', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'particulate trap', label: 'Particulate trap' }, + { value: 'modification or change of engine', label: 'Modification or change of engine' }, + { value: 'gas engine', label: 'Gas engine' }, + ], + }, + ], + }, + { + name: 'modificationTypeUsed', + label: 'Modification type used', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 100 }], + asyncValidators: [ + { + name: AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, + args: { testResult: ['fail', 'abandoned'], sibling: 'modType.code', value: 'm' }, + }, + { + name: AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, + args: { testResult: ['fail', 'abandoned'], sibling: 'modType.code', value: 'g' }, + }, + ], + required: true, + value: null, + }, + { + name: 'particulateTrapFitted', + label: 'Particulate trap fitted', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 100 }], + asyncValidators: [ + { + name: AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, + args: { testResult: ['fail', 'abandoned'], sibling: 'modType.code', value: 'p' }, + }, + ], + required: true, + value: null, + }, + { + name: 'particulateTrapSerialNumber', + label: 'Particulate trap serial number', + type: FormNodeTypes.CONTROL, + validators: [{ name: ValidatorNames.MaxLength, args: 100 }], + asyncValidators: [ + { + name: AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, + args: { testResult: ['fail', 'abandoned'], sibling: 'modType.code', value: 'p' }, + }, + ], + required: true, + value: null, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/notes/adr-notes-section.template.ts b/src/app/forms/templates/test-records/section-templates/notes/adr-notes-section.template.ts index 44e792a9db..5d9fdacf6a 100644 --- a/src/app/forms/templates/test-records/section-templates/notes/adr-notes-section.template.ts +++ b/src/app/forms/templates/test-records/section-templates/notes/adr-notes-section.template.ts @@ -1,8 +1,6 @@ import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; -import { - CustomFormControl, FormNode, FormNodeEditTypes, FormNodeTypes, -} from '@forms/services/dynamic-form.types'; +import { CustomFormControl, FormNode, FormNodeEditTypes, FormNodeTypes } from '@forms/services/dynamic-form.types'; import { resultOfTestEnum } from '@models/test-types/test-type.model'; import { Store, select } from '@ngrx/store'; import { State } from '@store/index'; @@ -10,52 +8,52 @@ import { testResultInEdit } from '@store/test-records'; import { map, take, tap } from 'rxjs'; export const AdrNotesSection: FormNode = { - name: 'notesSection', - label: 'Notes', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'additionalNotesRecorded', - label: 'Additional Notes', - type: FormNodeTypes.CONTROL, - value: '', - editType: FormNodeEditTypes.TEXTAREA, - validators: [{ name: ValidatorNames.MaxLength, args: 500 }], - asyncValidators: [ - // @TODO abstract into generic custom validator when used in multiple places - { - name: AsyncValidatorNames.Custom, - args: (control: CustomFormControl, store: Store) => { - return store.pipe( - select(testResultInEdit), - take(1), - map((testResult) => { - const testType = testResult?.testTypes.at(0); - const isPRS = testType?.testResult === resultOfTestEnum.prs; - const isPass = testType?.testResult === resultOfTestEnum.pass; - return testType?.centralDocs?.issueRequired && (isPRS || isPass); - }), - tap((issueRequired) => { - control.meta.hint = issueRequired ? 'Enter a reason for issuing documents centrally' : ''; - }), - map(() => null), - ); - }, - }, - ], - }, - ], - }, - ], - }, - ], + name: 'notesSection', + label: 'Notes', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'additionalNotesRecorded', + label: 'Additional Notes', + type: FormNodeTypes.CONTROL, + value: '', + editType: FormNodeEditTypes.TEXTAREA, + validators: [{ name: ValidatorNames.MaxLength, args: 500 }], + asyncValidators: [ + // @TODO abstract into generic custom validator when used in multiple places + { + name: AsyncValidatorNames.Custom, + args: (control: CustomFormControl, store: Store) => { + return store.pipe( + select(testResultInEdit), + take(1), + map((testResult) => { + const testType = testResult?.testTypes.at(0); + const isPRS = testType?.testResult === resultOfTestEnum.prs; + const isPass = testType?.testResult === resultOfTestEnum.pass; + return testType?.centralDocs?.issueRequired && (isPRS || isPass); + }), + 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/notes/notes-section.template.ts b/src/app/forms/templates/test-records/section-templates/notes/notes-section.template.ts index a1ea95e1e2..0253c707c7 100644 --- a/src/app/forms/templates/test-records/section-templates/notes/notes-section.template.ts +++ b/src/app/forms/templates/test-records/section-templates/notes/notes-section.template.ts @@ -2,30 +2,30 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { FormNode, FormNodeEditTypes, FormNodeTypes } from '@forms/services/dynamic-form.types'; export const NotesSection: FormNode = { - name: 'notesSection', - label: 'Notes', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'additionalNotesRecorded', - label: 'Additional Notes', - type: FormNodeTypes.CONTROL, - value: '', - editType: FormNodeEditTypes.TEXTAREA, - validators: [{ name: ValidatorNames.MaxLength, args: 500 }], - }, - ], - }, - ], - }, - ], + name: 'notesSection', + label: 'Notes', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'additionalNotesRecorded', + label: 'Additional Notes', + type: FormNodeTypes.CONTROL, + value: '', + editType: FormNodeEditTypes.TEXTAREA, + validators: [{ name: ValidatorNames.MaxLength, args: 500 }], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/reasonForCreation/reasonForCreation.template.ts b/src/app/forms/templates/test-records/section-templates/reasonForCreation/reasonForCreation.template.ts index 4021a6f413..fa7669e897 100644 --- a/src/app/forms/templates/test-records/section-templates/reasonForCreation/reasonForCreation.template.ts +++ b/src/app/forms/templates/test-records/section-templates/reasonForCreation/reasonForCreation.template.ts @@ -1,35 +1,33 @@ import { ValidatorNames } from '@forms/models/validators.enum'; -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const reasonForCreationSection: FormNode = { - name: 'reasonForCreationSection', - label: 'Reason for creation', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'reasonForCreation', - label: 'Reason for creation', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.TEXTAREA, - validators: [{ name: ValidatorNames.MaxLength, args: 500 }, { name: ValidatorNames.Required }], - }, - ], + name: 'reasonForCreationSection', + label: 'Reason for creation', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'reasonForCreation', + label: 'Reason for creation', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.TEXTAREA, + validators: [{ name: ValidatorNames.MaxLength, args: 500 }, { name: ValidatorNames.Required }], + }, + ], }; export const reasonForCreationHiddenSection: FormNode = { - name: 'requiredSection', - label: 'Reason for creation', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'reasonForCreation', - label: 'Reason for creation', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - ], + name: 'requiredSection', + label: 'Reason for creation', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'reasonForCreation', + label: 'Reason for creation', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/contingency-required-hidden-section-hgv-trl.template.ts b/src/app/forms/templates/test-records/section-templates/required/contingency-required-hidden-section-hgv-trl.template.ts index 20a31f0fdb..5172a8b327 100644 --- a/src/app/forms/templates/test-records/section-templates/required/contingency-required-hidden-section-hgv-trl.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/contingency-required-hidden-section-hgv-trl.template.ts @@ -1,214 +1,212 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const CreateRequiredSectionHgvTrl: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - label: 'Test status', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - options: [ - { label: 'Submitted', value: 'submitted' }, - { label: 'Cancelled', value: 'cancelled' }, - ], - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - label: 'Reason for cancellation', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - label: 'First use date', - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - label: 'Created by name', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - label: 'Create by ID', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - label: 'Last update by?', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - label: 'Last updated by ID', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - label: 'Should email certificate?', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - options: [ - { label: 'Yes', value: 'yes' }, - { label: 'No', value: 'no' }, - ], - }, - { - name: 'vehicleConfiguration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - type: FormNodeTypes.CONTROL, - label: 'Test Type ID', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeName', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'secondaryCertificateNumber', - type: FormNodeTypes.CONTROL, - label: 'Second ceritificate number', - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', - type: FormNodeTypes.CONTROL, - label: 'Certificate link', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + label: 'Test status', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + options: [ + { label: 'Submitted', value: 'submitted' }, + { label: 'Cancelled', value: 'cancelled' }, + ], + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + label: 'Reason for cancellation', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + label: 'First use date', + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + label: 'Created by name', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + label: 'Create by ID', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', + type: FormNodeTypes.CONTROL, + label: 'Last update by?', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + label: 'Last updated by ID', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + label: 'Should email certificate?', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + options: [ + { label: 'Yes', value: 'yes' }, + { label: 'No', value: 'no' }, + ], + }, + { + name: 'vehicleConfiguration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + type: FormNodeTypes.CONTROL, + label: 'Test Type ID', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeName', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'secondaryCertificateNumber', + type: FormNodeTypes.CONTROL, + label: 'Second ceritificate number', + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', + type: FormNodeTypes.CONTROL, + label: 'Certificate link', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/contingency-required-hidden-section-lgv-car.template.ts b/src/app/forms/templates/test-records/section-templates/required/contingency-required-hidden-section-lgv-car.template.ts index 2c98525180..1782b09787 100644 --- a/src/app/forms/templates/test-records/section-templates/required/contingency-required-hidden-section-lgv-car.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/contingency-required-hidden-section-lgv-car.template.ts @@ -1,225 +1,223 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const CreateRequiredSectionLgvCar: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - label: 'Test status', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - label: 'Reason for cancellation', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleSubclass', - type: FormNodeTypes.ARRAY, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: '0', - type: FormNodeTypes.CONTROL, - }, - ], - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - label: 'First use date', - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - label: 'Created by name', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - label: 'Create by ID', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - label: 'Last update by?', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - label: 'Last updated by ID', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - label: 'Should email certificate?', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleConfiguration', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleSize', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - type: FormNodeTypes.CONTROL, - label: 'Test Type ID', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeName', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'secondaryCertificateNumber', - type: FormNodeTypes.CONTROL, - label: 'Second ceritificate number', - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', - type: FormNodeTypes.CONTROL, - label: 'Certificate link', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + label: 'Test status', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + label: 'Reason for cancellation', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleSubclass', + type: FormNodeTypes.ARRAY, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: '0', + type: FormNodeTypes.CONTROL, + }, + ], + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + label: 'First use date', + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + label: 'Created by name', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + label: 'Create by ID', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', + type: FormNodeTypes.CONTROL, + label: 'Last update by?', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + label: 'Last updated by ID', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + label: 'Should email certificate?', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleConfiguration', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleSize', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + type: FormNodeTypes.CONTROL, + label: 'Test Type ID', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeName', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'secondaryCertificateNumber', + type: FormNodeTypes.CONTROL, + label: 'Second ceritificate number', + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', + type: FormNodeTypes.CONTROL, + label: 'Certificate link', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/contingency-required-hidden-section-motorcycle.template.ts b/src/app/forms/templates/test-records/section-templates/required/contingency-required-hidden-section-motorcycle.template.ts index 72427ba09b..ffc717355f 100644 --- a/src/app/forms/templates/test-records/section-templates/required/contingency-required-hidden-section-motorcycle.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/contingency-required-hidden-section-motorcycle.template.ts @@ -1,213 +1,211 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const CreateRequiredSectionMotorcycle: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - label: 'Test status', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - label: 'Reason for cancellation', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - label: 'First use date', - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - label: 'Created by name', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - label: 'Create by ID', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - label: 'Last update by?', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - label: 'Last updated by ID', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - label: 'Should email certificate?', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleConfiguration', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleSize', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - type: FormNodeTypes.CONTROL, - label: 'Test Type ID', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeName', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'secondaryCertificateNumber', - type: FormNodeTypes.CONTROL, - label: 'Second ceritificate number', - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', - type: FormNodeTypes.CONTROL, - label: 'Certificate link', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + label: 'Test status', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + label: 'Reason for cancellation', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + label: 'First use date', + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + label: 'Created by name', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + label: 'Create by ID', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', + type: FormNodeTypes.CONTROL, + label: 'Last update by?', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + label: 'Last updated by ID', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + label: 'Should email certificate?', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleConfiguration', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleSize', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + type: FormNodeTypes.CONTROL, + label: 'Test Type ID', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeName', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'secondaryCertificateNumber', + type: FormNodeTypes.CONTROL, + label: 'Second ceritificate number', + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', + type: FormNodeTypes.CONTROL, + label: 'Certificate link', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/contingency-required-hidden-section.template.ts b/src/app/forms/templates/test-records/section-templates/required/contingency-required-hidden-section.template.ts index b1c2555aa1..553a9ab812 100644 --- a/src/app/forms/templates/test-records/section-templates/required/contingency-required-hidden-section.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/contingency-required-hidden-section.template.ts @@ -1,226 +1,224 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const CreateRequiredSection: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - label: 'Test status', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - options: [ - { label: 'Submitted', value: 'submitted' }, - { label: 'Cancelled', value: 'cancelled' }, - ], - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - label: 'Reason for cancellation', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - label: 'First use date', - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - label: 'Created by name', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - label: 'Create by ID', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - label: 'Last update by?', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - label: 'Last updated by ID', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - label: 'Should email certificate?', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - options: [ - { label: 'Yes', value: 'yes' }, - { label: 'No', value: 'no' }, - ], - }, - { - name: 'numberOfSeats', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleConfiguration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleSize', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - type: FormNodeTypes.CONTROL, - label: 'Test Type ID', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeName', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'secondaryCertificateNumber', - type: FormNodeTypes.CONTROL, - label: 'Second ceritificate number', - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', - type: FormNodeTypes.CONTROL, - label: 'Certificate link', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + label: 'Test status', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + options: [ + { label: 'Submitted', value: 'submitted' }, + { label: 'Cancelled', value: 'cancelled' }, + ], + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + label: 'Reason for cancellation', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + label: 'First use date', + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + label: 'Created by name', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + label: 'Create by ID', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', + type: FormNodeTypes.CONTROL, + label: 'Last update by?', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + label: 'Last updated by ID', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + label: 'Should email certificate?', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + options: [ + { label: 'Yes', value: 'yes' }, + { label: 'No', value: 'no' }, + ], + }, + { + name: 'numberOfSeats', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleConfiguration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleSize', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + type: FormNodeTypes.CONTROL, + label: 'Test Type ID', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeName', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'secondaryCertificateNumber', + type: FormNodeTypes.CONTROL, + label: 'Second ceritificate number', + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', + type: FormNodeTypes.CONTROL, + label: 'Certificate link', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/custom-defects-hidden-section.template.ts b/src/app/forms/templates/test-records/section-templates/required/custom-defects-hidden-section.template.ts index d8660da509..c2520add45 100644 --- a/src/app/forms/templates/test-records/section-templates/required/custom-defects-hidden-section.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/custom-defects-hidden-section.template.ts @@ -1,29 +1,27 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const CustomDefectsHiddenSection: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'customDefects', - type: FormNodeTypes.ARRAY, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'customDefects', + type: FormNodeTypes.ARRAY, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/defect-hidden-section.template.ts b/src/app/forms/templates/test-records/section-templates/required/defect-hidden-section.template.ts index 7c3719e283..840d86c208 100644 --- a/src/app/forms/templates/test-records/section-templates/required/defect-hidden-section.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/defect-hidden-section.template.ts @@ -1,29 +1,27 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const defectsHiddenSection: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'defects', - type: FormNodeTypes.ARRAY, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'defects', + type: FormNodeTypes.ARRAY, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-group4-lgv.template.ts b/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-group4-lgv.template.ts index e752bac584..dd14878fc0 100644 --- a/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-group4-lgv.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-group4-lgv.template.ts @@ -1,270 +1,268 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const DeskBasedRequiredHiddenSectionGroup4And5Lgv: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'contingencyTestNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testerStaffId', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - editType: FormNodeEditTypes.HIDDEN, + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'contingencyTestNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testerStaffId', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleSubclass', - type: FormNodeTypes.ARRAY, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: '0', - type: FormNodeTypes.CONTROL, - }, - ], - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleSubclass', + type: FormNodeTypes.ARRAY, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: '0', + type: FormNodeTypes.CONTROL, + }, + ], + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleConfiguration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - label: 'Test Type ID', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeName', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'prohibitionIssued', - type: FormNodeTypes.CONTROL, - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testNumber', - label: 'Test Number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'secondaryCertificateNumber', - type: FormNodeTypes.CONTROL, - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleConfiguration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + label: 'Test Type ID', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeName', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'prohibitionIssued', + type: FormNodeTypes.CONTROL, + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testNumber', + label: 'Test Number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'secondaryCertificateNumber', + type: FormNodeTypes.CONTROL, + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-group4-motorcycle-amend.template.ts b/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-group4-motorcycle-amend.template.ts index 972e568ddd..2f7725dbfd 100644 --- a/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-group4-motorcycle-amend.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-group4-motorcycle-amend.template.ts @@ -1,244 +1,242 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const AmendDeskBasedRequiredHiddenSectionGroup4Motorcyle: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'contingencyTestNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testerStaffId', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - editType: FormNodeEditTypes.HIDDEN, + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'contingencyTestNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testerStaffId', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleConfiguration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - label: 'Test Type ID', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeName', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeClassification', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - value: null, - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testNumber', - label: 'Test Number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'secondaryCertificateNumber', - type: FormNodeTypes.CONTROL, - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleConfiguration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + label: 'Test Type ID', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeName', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeClassification', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + value: null, + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testNumber', + label: 'Test Number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'secondaryCertificateNumber', + type: FormNodeTypes.CONTROL, + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-group4-motorcycle.template.ts b/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-group4-motorcycle.template.ts index 5332f19e9c..04b613f056 100644 --- a/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-group4-motorcycle.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-group4-motorcycle.template.ts @@ -1,258 +1,256 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const DeskBasedRequiredHiddenSectionGroup4Motorcyle: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'contingencyTestNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testerStaffId', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - editType: FormNodeEditTypes.HIDDEN, + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'contingencyTestNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testerStaffId', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleConfiguration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - label: 'Test Type ID', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeName', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'prohibitionIssued', - type: FormNodeTypes.CONTROL, - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testNumber', - label: 'Test Number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'secondaryCertificateNumber', - type: FormNodeTypes.CONTROL, - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleConfiguration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + label: 'Test Type ID', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeName', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'prohibitionIssued', + type: FormNodeTypes.CONTROL, + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testNumber', + label: 'Test Number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'secondaryCertificateNumber', + type: FormNodeTypes.CONTROL, + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-group5-lgv.template.ts b/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-group5-lgv.template.ts index 525ec4ca44..fe89b9d195 100644 --- a/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-group5-lgv.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-group5-lgv.template.ts @@ -1,244 +1,242 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const DeskBasedRequiredHiddenSectionGroup5Lgv: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'contingencyTestNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testerStaffId', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - editType: FormNodeEditTypes.HIDDEN, + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'contingencyTestNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testerStaffId', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleSubclass', - type: FormNodeTypes.ARRAY, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: '0', - type: FormNodeTypes.CONTROL, - }, - ], - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleSubclass', + type: FormNodeTypes.ARRAY, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: '0', + type: FormNodeTypes.CONTROL, + }, + ], + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleConfiguration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - label: 'Test Type ID', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleConfiguration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + label: 'Test Type ID', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeClassification', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - value: null, - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testNumber', - label: 'Test Number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeClassification', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + value: null, + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testNumber', + label: 'Test Number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-section-hgv-trl.template.ts b/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-section-hgv-trl.template.ts index c95441b203..0ba707c9af 100644 --- a/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-section-hgv-trl.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-section-hgv-trl.template.ts @@ -1,232 +1,230 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const DeskBasedRequiredSectionHgvTrl: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'contingencyTestNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testerStaffId', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - editType: FormNodeEditTypes.HIDDEN, + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'contingencyTestNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testerStaffId', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleConfiguration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - label: 'Test Type ID', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleConfiguration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + label: 'Test Type ID', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeClassification', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - value: null, - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testNumber', - label: 'Test Number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeClassification', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + value: null, + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testNumber', + label: 'Test Number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-section-psv.template.ts b/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-section-psv.template.ts index 9499576083..8ee62b9e72 100644 --- a/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-section-psv.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/desk-based-required-hidden-section-psv.template.ts @@ -1,243 +1,241 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const DeskBasedRequiredSectionPsv: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'contingencyTestNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testerStaffId', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - editType: FormNodeEditTypes.HIDDEN, + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'contingencyTestNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testerStaffId', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfSeats', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleConfiguration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleSize', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - label: 'Test Type ID', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeClassification', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - value: '', - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testNumber', - label: 'Test Number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfSeats', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleConfiguration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleSize', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + label: 'Test Type ID', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeClassification', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + value: '', + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testNumber', + label: 'Test Number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/desk-based-required-section-group4-amend.template.ts b/src/app/forms/templates/test-records/section-templates/required/desk-based-required-section-group4-amend.template.ts index da63e667e3..ff767ab956 100644 --- a/src/app/forms/templates/test-records/section-templates/required/desk-based-required-section-group4-amend.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/desk-based-required-section-group4-amend.template.ts @@ -1,256 +1,254 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const AmendDeskBasedRequiredHiddenSectionGroup4: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'contingencyTestNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testerStaffId', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - editType: FormNodeEditTypes.HIDDEN, + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'contingencyTestNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testerStaffId', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleSubclass', - type: FormNodeTypes.ARRAY, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: '0', - type: FormNodeTypes.CONTROL, - }, - ], - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleSubclass', + type: FormNodeTypes.ARRAY, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: '0', + type: FormNodeTypes.CONTROL, + }, + ], + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleConfiguration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - label: 'Test Type ID', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeName', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeClassification', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - value: null, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testNumber', - label: 'Test Number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'secondaryCertificateNumber', - type: FormNodeTypes.CONTROL, - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleConfiguration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + label: 'Test Type ID', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeName', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeClassification', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + value: null, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testNumber', + label: 'Test Number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'secondaryCertificateNumber', + type: FormNodeTypes.CONTROL, + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/required-hidden-section-hgv-trl.template.ts b/src/app/forms/templates/test-records/section-templates/required/required-hidden-section-hgv-trl.template.ts index 628251f35b..a70c28ad2b 100644 --- a/src/app/forms/templates/test-records/section-templates/required/required-hidden-section-hgv-trl.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/required-hidden-section-hgv-trl.template.ts @@ -1,231 +1,229 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const RequiredSectionHGVTRL: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'contingencyTestNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testerStaffId', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - editType: FormNodeEditTypes.HIDDEN, + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'contingencyTestNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testerStaffId', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleConfiguration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - label: 'Test Type ID', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'secondaryCertificateNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleConfiguration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + label: 'Test Type ID', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'secondaryCertificateNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeClassification', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeClassification', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/required-hidden-section.template.ts b/src/app/forms/templates/test-records/section-templates/required/required-hidden-section.template.ts index 20a3154443..38f5170262 100644 --- a/src/app/forms/templates/test-records/section-templates/required/required-hidden-section.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/required-hidden-section.template.ts @@ -1,249 +1,247 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const RequiredSection: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'contingencyTestNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testerStaffId', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - editType: FormNodeEditTypes.HIDDEN, + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'contingencyTestNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testerStaffId', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfSeats', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleConfiguration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleSize', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - label: 'Test Type ID', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'secondaryCertificateNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeClassification', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - value: '', - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testNumber', - label: 'Test Number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfSeats', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleConfiguration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleSize', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + label: 'Test Type ID', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'secondaryCertificateNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeClassification', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + value: '', + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testNumber', + label: 'Test Number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/seatbelt-hidden-section.template.ts b/src/app/forms/templates/test-records/section-templates/required/seatbelt-hidden-section.template.ts index 6dded7eecb..13669f33fc 100644 --- a/src/app/forms/templates/test-records/section-templates/required/seatbelt-hidden-section.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/seatbelt-hidden-section.template.ts @@ -1,44 +1,42 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const SeatbeltHiddenSection: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'seatbeltInstallationCheckDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - value: null, - }, - { - name: 'numberOfSeatbeltsFitted', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - value: null, - }, - { - name: 'lastSeatbeltInstallationCheckDate', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - }, - ], - }, - ], - }, - ], + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'seatbeltInstallationCheckDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + value: null, + }, + { + name: 'numberOfSeatbeltsFitted', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + value: null, + }, + { + name: 'lastSeatbeltInstallationCheckDate', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/specialist-required-hidden-section-hgv-trl.template.ts b/src/app/forms/templates/test-records/section-templates/required/specialist-required-hidden-section-hgv-trl.template.ts index 3ca3b129ba..952d73d7e6 100644 --- a/src/app/forms/templates/test-records/section-templates/required/specialist-required-hidden-section-hgv-trl.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/specialist-required-hidden-section-hgv-trl.template.ts @@ -1,224 +1,222 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const SpecialistRequiredSectionHGVTRL: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'contingencyTestNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testerStaffId', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - editType: FormNodeEditTypes.HIDDEN, + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'contingencyTestNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testerStaffId', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleConfiguration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - label: 'Test Type ID', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleConfiguration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + label: 'Test Type ID', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeClassification', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeClassification', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/specialist-required-hidden-section-lgv-car.template.ts b/src/app/forms/templates/test-records/section-templates/required/specialist-required-hidden-section-lgv-car.template.ts index b68f033e61..67253a0b30 100644 --- a/src/app/forms/templates/test-records/section-templates/required/specialist-required-hidden-section-lgv-car.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/specialist-required-hidden-section-lgv-car.template.ts @@ -1,236 +1,234 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const SpecialistRequiredSectionLgvCarSmallTrl: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'contingencyTestNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testerStaffId', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - editType: FormNodeEditTypes.HIDDEN, + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'contingencyTestNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testerStaffId', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleSubclass', - type: FormNodeTypes.ARRAY, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: '0', - type: FormNodeTypes.CONTROL, - }, - ], - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleSubclass', + type: FormNodeTypes.ARRAY, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: '0', + type: FormNodeTypes.CONTROL, + }, + ], + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleConfiguration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - label: 'Test Type ID', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleConfiguration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + label: 'Test Type ID', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeClassification', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeClassification', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/specialist-required-hidden-section-motorcycle.template.ts b/src/app/forms/templates/test-records/section-templates/required/specialist-required-hidden-section-motorcycle.template.ts index 54a62f27b0..1e3cd6ad77 100644 --- a/src/app/forms/templates/test-records/section-templates/required/specialist-required-hidden-section-motorcycle.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/specialist-required-hidden-section-motorcycle.template.ts @@ -1,227 +1,225 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const RequiredSpecialistSectionMotorcycle: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'contingencyTestNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testerStaffId', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - editType: FormNodeEditTypes.HIDDEN, + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'contingencyTestNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testerStaffId', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleConfiguration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleSize', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - label: 'Test Type ID', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeClassification', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleConfiguration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleSize', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + label: 'Test Type ID', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeClassification', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/required/specialist-required-hidden-section.template.ts b/src/app/forms/templates/test-records/section-templates/required/specialist-required-hidden-section.template.ts index 24360c3de0..9cfb6fe245 100644 --- a/src/app/forms/templates/test-records/section-templates/required/specialist-required-hidden-section.template.ts +++ b/src/app/forms/templates/test-records/section-templates/required/specialist-required-hidden-section.template.ts @@ -1,233 +1,231 @@ -import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, -} from '@forms/services/dynamic-form.types'; +import { FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes } from '@forms/services/dynamic-form.types'; export const RequiredSpecialistSection: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResultId', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'contingencyTestNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'typeOfTest', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'source', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testStatus', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'systemNumber', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testerStaffId', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleClass', - type: FormNodeTypes.GROUP, - editType: FormNodeEditTypes.HIDDEN, + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResultId', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'contingencyTestNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'typeOfTest', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'source', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testStatus', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'systemNumber', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testerStaffId', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleClass', + type: FormNodeTypes.GROUP, + editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - children: [ - { - name: 'code', - customId: 'vehicleClassCode', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'description', - customId: 'vehicleClassDescription', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - { - name: 'vehicleType', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'noOfAxles', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfWheelsDriven', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'regnDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'firstUseDate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedByName', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedById', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'shouldEmailCertificate', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'numberOfSeats', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleConfiguration', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'vehicleSize', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'reasonForCancellation', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypeId', - label: 'Test Type ID', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'name', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'lastUpdatedAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'certificateLink', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypeClassification', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'deletionFlag', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + viewType: FormNodeViewTypes.HIDDEN, + children: [ + { + name: 'code', + customId: 'vehicleClassCode', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'description', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + { + name: 'vehicleType', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'noOfAxles', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfWheelsDriven', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'regnDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'firstUseDate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdByName', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedByName', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedById', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'shouldEmailCertificate', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'numberOfSeats', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleConfiguration', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'vehicleSize', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'reasonForCancellation', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypeId', + label: 'Test Type ID', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'name', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'lastUpdatedAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'certificateLink', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypeClassification', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'deletionFlag', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/seatbelt/seatbelt-section.template.ts b/src/app/forms/templates/test-records/section-templates/seatbelt/seatbelt-section.template.ts index 6a3bcc1af3..4f20ce2fec 100644 --- a/src/app/forms/templates/test-records/section-templates/seatbelt/seatbelt-section.template.ts +++ b/src/app/forms/templates/test-records/section-templates/seatbelt/seatbelt-section.template.ts @@ -1,62 +1,72 @@ import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const SeatbeltSection: FormNode = { - name: 'seatbeltSection', - label: 'Seatbelt', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'seatbeltInstallationCheckDate', - label: 'Carried out during test', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.RADIO, - value: null, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - asyncValidators: [{ name: AsyncValidatorNames.RequiredIfNotAbandoned }], - }, - { - name: 'numberOfSeatbeltsFitted', - label: 'Number of seatbelts fitted', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - value: null, - validators: [ - { name: ValidatorNames.RequiredIfEquals, args: { sibling: 'seatbeltInstallationCheckDate', value: [true] } }, - { name: ValidatorNames.Max, args: 99 }, - ], - width: FormNodeWidth.M, - }, - { - name: 'lastSeatbeltInstallationCheckDate', - label: 'Most recent installation check', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - value: null, - validators: [ - { name: ValidatorNames.RequiredIfEquals, args: { sibling: 'seatbeltInstallationCheckDate', value: [true] } }, - { name: ValidatorNames.PastDate }, - ], - }, - ], - }, - ], - }, - ], + name: 'seatbeltSection', + label: 'Seatbelt', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'seatbeltInstallationCheckDate', + label: 'Carried out during test', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + value: null, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + asyncValidators: [{ name: AsyncValidatorNames.RequiredIfNotAbandoned }], + }, + { + name: 'numberOfSeatbeltsFitted', + label: 'Number of seatbelts fitted', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + value: null, + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'seatbeltInstallationCheckDate', value: [true] }, + }, + { name: ValidatorNames.Max, args: 99 }, + ], + width: FormNodeWidth.M, + }, + { + name: 'lastSeatbeltInstallationCheckDate', + label: 'Most recent installation check', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + value: null, + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'seatbeltInstallationCheckDate', value: [true] }, + }, + { name: ValidatorNames.PastDate }, + ], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group1.template.ts b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group1.template.ts index 2f98d5f949..1b6ae39ce5 100644 --- a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group1.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group1.template.ts @@ -1,122 +1,130 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const ContingencyTestSectionGroup1: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'contingencyTestNumber', - label: 'Contingency Test Number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }, { name: ValidatorNames.MinLength, args: 6 }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - }, - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - type: FormNodeTypes.CONTROL, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testExpiryDate', - label: 'Expiry Date', - disabled: true, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'prohibitionIssued', - label: 'Prohibition issued', - type: FormNodeTypes.CONTROL, - value: null, - editType: FormNodeEditTypes.HIDDEN, - required: true, - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'contingencyTestNumber', + label: 'Contingency Test Number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { name: ValidatorNames.MinLength, args: 6 }, + { name: ValidatorNames.Required }, + ], + width: FormNodeWidth.L, + }, + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + type: FormNodeTypes.CONTROL, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testExpiryDate', + label: 'Expiry Date', + disabled: true, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'prohibitionIssued', + label: 'Prohibition issued', + type: FormNodeTypes.CONTROL, + value: null, + editType: FormNodeEditTypes.HIDDEN, + required: true, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group12and14.template.ts b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group12and14.template.ts index 5e79593724..ce0bb27e91 100644 --- a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group12and14.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group12and14.template.ts @@ -1,116 +1,124 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const ContingencyTestSectionGroup12and14: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'contingencyTestNumber', - label: 'Contingency Test Number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }, { name: ValidatorNames.MinLength, args: 6 }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - }, - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.PastDate }], - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - value: null, - type: FormNodeTypes.CONTROL, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'prohibitionIssued', - label: 'Prohibition issued', - type: FormNodeTypes.CONTROL, - value: null, - editType: FormNodeEditTypes.HIDDEN, - required: true, - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'contingencyTestNumber', + label: 'Contingency Test Number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { name: ValidatorNames.MinLength, args: 6 }, + { name: ValidatorNames.Required }, + ], + width: FormNodeWidth.L, + }, + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + value: null, + type: FormNodeTypes.CONTROL, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'prohibitionIssued', + label: 'Prohibition issued', + type: FormNodeTypes.CONTROL, + value: null, + editType: FormNodeEditTypes.HIDDEN, + required: true, + }, + ], + }, + ], + }, + ], }; 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 5cfdd2b459..b0c30a31a6 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 @@ -1,149 +1,157 @@ import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const ContingencyTestSectionGroup15and16: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'contingencyTestNumber', - label: 'Contingency Test Number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }, { name: ValidatorNames.MinLength, args: 6 }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - }, - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.PastDate }], - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - ], - validators: [{ name: ValidatorNames.HideIfNotEqual, args: { sibling: 'testExpiryDate', value: 'pass' } }], - asyncValidators: [{ name: AsyncValidatorNames.PassResultDependantOnCustomDefects }], - type: FormNodeTypes.CONTROL, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXT, - validators: [{ name: ValidatorNames.Required }, { name: ValidatorNames.Alphanumeric }], - viewType: FormNodeViewTypes.HIDDEN, - required: true, - value: null, - }, - { - name: 'testExpiryDate', - label: 'Expiry Date', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATE, - validators: [ - { - name: ValidatorNames.RequiredIfEquals, - args: { sibling: 'testResult', value: ['pass'] }, - }, - { name: ValidatorNames.FutureDate }, - ], - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'prohibitionIssued', - type: FormNodeTypes.CONTROL, - label: 'Prohibition issued', - value: null, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.Required }], - }, - { - name: 'defects', - type: FormNodeTypes.ARRAY, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'contingencyTestNumber', + label: 'Contingency Test Number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { name: ValidatorNames.MinLength, args: 6 }, + { name: ValidatorNames.Required }, + ], + width: FormNodeWidth.L, + }, + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + ], + validators: [{ name: ValidatorNames.HideIfNotEqual, args: { sibling: 'testExpiryDate', value: 'pass' } }], + asyncValidators: [{ name: AsyncValidatorNames.PassResultDependantOnCustomDefects }], + type: FormNodeTypes.CONTROL, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXT, + validators: [{ name: ValidatorNames.Required }, { name: ValidatorNames.Alphanumeric }], + viewType: FormNodeViewTypes.HIDDEN, + required: true, + value: null, + }, + { + name: 'testExpiryDate', + label: 'Expiry Date', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATE, + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'testResult', value: ['pass'] }, + }, + { name: ValidatorNames.FutureDate }, + ], + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'prohibitionIssued', + type: FormNodeTypes.CONTROL, + label: 'Prohibition issued', + value: null, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [{ name: ValidatorNames.Required }], + }, + { + name: 'defects', + type: FormNodeTypes.ARRAY, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group3And4And8.template.ts b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group3And4And8.template.ts index 3fee879648..ae79b30acd 100644 --- a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group3And4And8.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group3And4And8.template.ts @@ -1,133 +1,141 @@ import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const ContingencyTestSectionGroup3And4And8: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'contingencyTestNumber', - label: 'Contingency Test Number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }, { name: ValidatorNames.MinLength, args: 6 }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - }, - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.PastDate }], - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - ], - asyncValidators: [{ name: AsyncValidatorNames.ResultDependantOnCustomDefects }], - type: FormNodeTypes.CONTROL, - }, - { - name: 'testTypeName', - label: 'Description', - value: '', - disabled: true, + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'contingencyTestNumber', + label: 'Contingency Test Number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { name: ValidatorNames.MinLength, args: 6 }, + { name: ValidatorNames.Required }, + ], + width: FormNodeWidth.L, + }, + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + ], + asyncValidators: [{ name: AsyncValidatorNames.ResultDependantOnCustomDefects }], + type: FormNodeTypes.CONTROL, + }, + { + name: 'testTypeName', + label: 'Description', + value: '', + disabled: true, - type: FormNodeTypes.CONTROL, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'prohibitionIssued', - type: FormNodeTypes.CONTROL, - label: 'Prohibition issued', - value: null, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.Required }], - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'prohibitionIssued', + type: FormNodeTypes.CONTROL, + label: 'Prohibition issued', + value: null, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [{ name: ValidatorNames.Required }], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group5And13.template.ts b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group5And13.template.ts index 9cceae04f5..217456dce1 100644 --- a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group5And13.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group5And13.template.ts @@ -1,140 +1,150 @@ import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const ContingencyTestSectionGroup5And13: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'contingencyTestNumber', - label: 'Contingency Test Number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }, { name: ValidatorNames.MinLength, args: 6 }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - }, - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.PastDate }], - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - ], - asyncValidators: [{ name: AsyncValidatorNames.ResultDependantOnCustomDefects }], - validators: [{ name: ValidatorNames.HideIfNotEqual, args: { sibling: 'certificateNumber', value: 'pass' } }], - type: FormNodeTypes.CONTROL, - }, - { - name: 'testTypeName', - label: 'Description', - value: '', - disabled: true, + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'contingencyTestNumber', + label: 'Contingency Test Number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { name: ValidatorNames.MinLength, args: 6 }, + { name: ValidatorNames.Required }, + ], + width: FormNodeWidth.L, + }, + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + ], + asyncValidators: [{ name: AsyncValidatorNames.ResultDependantOnCustomDefects }], + validators: [ + { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'certificateNumber', value: 'pass' } }, + ], + type: FormNodeTypes.CONTROL, + }, + { + name: 'testTypeName', + label: 'Description', + value: '', + disabled: true, - type: FormNodeTypes.CONTROL, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - validators: [ - { name: ValidatorNames.Alphanumeric }, - { - name: ValidatorNames.RequiredIfEquals, - args: { sibling: 'testResult', value: ['pass'] }, - }, - ], - required: true, - value: null, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'prohibitionIssued', - type: FormNodeTypes.CONTROL, - label: 'Prohibition issued', - value: null, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.Required }], - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + validators: [ + { name: ValidatorNames.Alphanumeric }, + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'testResult', value: ['pass'] }, + }, + ], + required: true, + value: null, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'prohibitionIssued', + type: FormNodeTypes.CONTROL, + label: 'Prohibition issued', + value: null, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [{ name: ValidatorNames.Required }], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group6And11.template.ts b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group6And11.template.ts index bb48b82af8..edae8e8760 100644 --- a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group6And11.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group6And11.template.ts @@ -1,123 +1,131 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const ContingencyTestSectionGroup6And11: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'contingencyTestNumber', - label: 'Contingency Test Number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }, { name: ValidatorNames.MinLength, args: 6 }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - }, - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.PastDate }], - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - value: null, - type: FormNodeTypes.CONTROL, - }, - { - name: 'testTypeName', - label: 'Description', - value: '', - disabled: true, - type: FormNodeTypes.CONTROL, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'prohibitionIssued', - label: 'Prohibition issued', - type: FormNodeTypes.CONTROL, - value: null, - editType: FormNodeEditTypes.HIDDEN, - required: true, - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'contingencyTestNumber', + label: 'Contingency Test Number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { name: ValidatorNames.MinLength, args: 6 }, + { name: ValidatorNames.Required }, + ], + width: FormNodeWidth.L, + }, + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + value: null, + type: FormNodeTypes.CONTROL, + }, + { + name: 'testTypeName', + label: 'Description', + value: '', + disabled: true, + type: FormNodeTypes.CONTROL, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'prohibitionIssued', + label: 'Prohibition issued', + type: FormNodeTypes.CONTROL, + value: null, + editType: FormNodeEditTypes.HIDDEN, + required: true, + }, + ], + }, + ], + }, + ], }; 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..4b5f02ff72 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 @@ -2,196 +2,209 @@ import { ContingencyAdrGenerateCertComponent } from '@forms/components/contingen import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const ContingencyTestSectionGroup7: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'contingencyTestNumber', - label: 'Contingency Test Number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }, { name: ValidatorNames.MinLength, args: 6 }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - }, - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.PastDate }], - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - ], - validators: [ - { 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', - value: '', - disabled: true, + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'contingencyTestNumber', + label: 'Contingency Test Number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { name: ValidatorNames.MinLength, args: 6 }, + { name: ValidatorNames.Required }, + ], + width: FormNodeWidth.L, + }, + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + ], + validators: [ + { 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', + value: '', + disabled: true, - type: FormNodeTypes.CONTROL, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'generateCert', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.CUSTOM, - editComponent: ContingencyAdrGenerateCertComponent, - validators: [ - { - name: ValidatorNames.ShowGroupsWhenEqualTo, - args: { sibling: 'testResult', value: ['pass'] }, - }, - ], - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - validators: [ - { name: ValidatorNames.Alphanumeric }, - // Make required if test result is pass/prs, but issue documents centrally is false - { name: ValidatorNames.IssueRequired }, - ], - required: true, - value: null, - }, - { - name: 'testExpiryDate', - label: 'Expiry Date', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATE, - validators: [ - { - name: ValidatorNames.RequiredIfEquals, - args: { sibling: 'testResult', value: ['pass'] }, - }, - { name: ValidatorNames.FutureDate }, - ], - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'prohibitionIssued', - type: FormNodeTypes.CONTROL, - label: 'Prohibition issued', - value: null, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.Required }], - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'generateCert', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.CUSTOM, + editComponent: ContingencyAdrGenerateCertComponent, + validators: [ + { + name: ValidatorNames.ShowGroupsWhenEqualTo, + args: { sibling: 'testResult', value: ['pass'] }, + }, + ], + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + validators: [ + { name: ValidatorNames.Alphanumeric }, + // Make required if test result is pass/prs, but issue documents centrally is false + { name: ValidatorNames.IssueRequired }, + ], + required: true, + value: null, + }, + { + name: 'testExpiryDate', + label: 'Expiry Date', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATE, + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'testResult', value: ['pass'] }, + }, + { name: ValidatorNames.FutureDate }, + ], + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'prohibitionIssued', + type: FormNodeTypes.CONTROL, + label: 'Prohibition issued', + value: null, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [{ name: ValidatorNames.Required }], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group8Notifiable.template.ts b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group8Notifiable.template.ts index ad8c1dd4e0..d3eff21dc3 100644 --- a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group8Notifiable.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group8Notifiable.template.ts @@ -1,158 +1,166 @@ import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const ContingencyTestSectionGroup8Notifiable: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'contingencyTestNumber', - label: 'Contingency Test Number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }, { name: ValidatorNames.MinLength, args: 6 }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - }, - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.PastDate }], - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - ], - validators: [{ 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' }, - ], - }, - { - name: 'reasonsForIssue', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: [], - }, - ], - }, - { - name: 'testTypeName', - label: 'Description', - value: '', - disabled: true, + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'contingencyTestNumber', + label: 'Contingency Test Number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { name: ValidatorNames.MinLength, args: 6 }, + { name: ValidatorNames.Required }, + ], + width: FormNodeWidth.L, + }, + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + ], + validators: [{ 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' }, + ], + }, + { + name: 'reasonsForIssue', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: [], + }, + ], + }, + { + name: 'testTypeName', + label: 'Description', + value: '', + disabled: true, - type: FormNodeTypes.CONTROL, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'prohibitionIssued', - type: FormNodeTypes.CONTROL, - label: 'Prohibition issued', - value: null, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.Required }], - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'prohibitionIssued', + type: FormNodeTypes.CONTROL, + label: 'Prohibition issued', + value: null, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [{ name: ValidatorNames.Required }], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group9And10.template.ts b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group9And10.template.ts index c99c02e8af..481994a6b4 100644 --- a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group9And10.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group9And10.template.ts @@ -1,124 +1,132 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const ContingencyTestSectionGroup9And10: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'contingencyTestNumber', - label: 'Contingency Test Number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }, { name: ValidatorNames.MinLength, args: 6 }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - }, - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.PastDate }], - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - value: null, - type: FormNodeTypes.CONTROL, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testExpiryDate', - label: 'Expiry Date', - disabled: true, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'prohibitionIssued', - label: 'Prohibition issued', - type: FormNodeTypes.CONTROL, - value: null, - editType: FormNodeEditTypes.HIDDEN, - required: true, - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'contingencyTestNumber', + label: 'Contingency Test Number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { name: ValidatorNames.MinLength, args: 6 }, + { name: ValidatorNames.Required }, + ], + width: FormNodeWidth.L, + }, + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + value: null, + type: FormNodeTypes.CONTROL, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testExpiryDate', + label: 'Expiry Date', + disabled: true, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'prohibitionIssued', + label: 'Prohibition issued', + type: FormNodeTypes.CONTROL, + value: null, + editType: FormNodeEditTypes.HIDDEN, + required: true, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group9And10CentralDocs.template.ts b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group9And10CentralDocs.template.ts index b5f184cc80..ef825e6eb7 100644 --- a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group9And10CentralDocs.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-group9And10CentralDocs.template.ts @@ -1,150 +1,165 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const ContingencyTestSectionGroup9And10CentralDocs: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'contingencyTestNumber', - label: 'Contingency Test Number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }, { name: ValidatorNames.MinLength, args: 6 }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - }, - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.PastDate }], - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - value: null, - type: FormNodeTypes.CONTROL, - validators: [{ name: ValidatorNames.HideIfNotEqual, args: { sibling: 'centralDocs', value: ['pass', 'prs'] } }], - }, - { - 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, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testExpiryDate', - label: 'Expiry Date', - disabled: true, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'prohibitionIssued', - label: 'Prohibition issued', - type: FormNodeTypes.CONTROL, - value: null, - editType: FormNodeEditTypes.HIDDEN, - required: true, - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'contingencyTestNumber', + label: 'Contingency Test Number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { name: ValidatorNames.MinLength, args: 6 }, + { name: ValidatorNames.Required }, + ], + width: FormNodeWidth.L, + }, + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + value: null, + type: FormNodeTypes.CONTROL, + validators: [ + { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'centralDocs', value: ['pass', 'prs'] } }, + ], + }, + { + 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, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testExpiryDate', + label: 'Expiry Date', + disabled: true, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'prohibitionIssued', + label: 'Prohibition issued', + type: FormNodeTypes.CONTROL, + value: null, + editType: FormNodeEditTypes.HIDDEN, + required: true, + }, + ], + }, + ], + }, + ], }; 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..c057b08719 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 @@ -2,196 +2,211 @@ import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { TEST_TYPES_GROUP1_SPEC_TEST } from '@forms/models/testTypeId.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const ContingencyTestSectionSpecialistGroup1: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'contingencyTestNumber', - label: 'Contingency Test Number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }, { name: ValidatorNames.MinLength, args: 6 }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - }, - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.PastDate }], - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - { value: 'prs', label: 'PRS' }, - ], - validators: [{ name: ValidatorNames.HideIfNotEqual, args: { sibling: 'centralDocs', value: ['pass', 'prs'] } }], - asyncValidators: [ - { name: AsyncValidatorNames.ResultDependantOnRequiredStandards }, - { - name: AsyncValidatorNames.HideIfEqualsWithCondition, - args: { - sibling: 'certificateNumber', - value: 'fail', - conditions: { field: 'testTypeId', operator: 'equals', value: TEST_TYPES_GROUP1_SPEC_TEST }, - }, - }, - ], - 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', - value: '', - disabled: true, + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'contingencyTestNumber', + label: 'Contingency Test Number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { name: ValidatorNames.MinLength, args: 6 }, + { name: ValidatorNames.Required }, + ], + width: FormNodeWidth.L, + }, + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + { value: 'prs', label: 'PRS' }, + ], + validators: [ + { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'centralDocs', value: ['pass', 'prs'] } }, + ], + asyncValidators: [ + { name: AsyncValidatorNames.ResultDependantOnRequiredStandards }, + { + name: AsyncValidatorNames.HideIfEqualsWithCondition, + args: { + sibling: 'certificateNumber', + value: 'fail', + conditions: { field: 'testTypeId', operator: 'equals', value: TEST_TYPES_GROUP1_SPEC_TEST }, + }, + }, + ], + 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', + value: '', + disabled: true, - type: FormNodeTypes.CONTROL, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - editType: FormNodeEditTypes.TEXT, - validators: [ - { name: ValidatorNames.Alphanumeric }, - // Make required if test result is pass/prs, but issue documents centrally is false - { name: ValidatorNames.IssueRequired }, - ], - required: true, - value: null, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'prohibitionIssued', - type: FormNodeTypes.CONTROL, - label: 'Prohibition issued', - value: null, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.Required }], - }, - { - name: 'reapplicationDate', - label: 'Reapplication date', - hint: 'For example, 27 3 2007', - editType: FormNodeEditTypes.DATE, - viewType: FormNodeViewTypes.DATE, - type: FormNodeTypes.CONTROL, - groups: ['failOnly'], - validators: [ - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'testResult', - value: ['fail'], - customErrorMessage: 'Reapplication date is required', - }, - }, - { name: ValidatorNames.FutureDate }, - ], - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.TEXT, + validators: [ + { name: ValidatorNames.Alphanumeric }, + // Make required if test result is pass/prs, but issue documents centrally is false + { name: ValidatorNames.IssueRequired }, + ], + required: true, + value: null, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'prohibitionIssued', + type: FormNodeTypes.CONTROL, + label: 'Prohibition issued', + value: null, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [{ name: ValidatorNames.Required }], + }, + { + name: 'reapplicationDate', + label: 'Reapplication date', + hint: 'For example, 27 3 2007', + editType: FormNodeEditTypes.DATE, + viewType: FormNodeViewTypes.DATE, + type: FormNodeTypes.CONTROL, + groups: ['failOnly'], + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'testResult', + value: ['fail'], + customErrorMessage: 'Reapplication date is required', + }, + }, + { name: ValidatorNames.FutureDate }, + ], + }, + ], + }, + ], + }, + ], }; 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..c170f94622 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 @@ -1,156 +1,164 @@ import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const ContingencyTestSectionSpecialistGroup2: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'contingencyTestNumber', - label: 'Contingency Test Number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }, { name: ValidatorNames.MinLength, args: 6 }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - }, - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.PastDate }], - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - { value: 'prs', label: 'PRS' }, - ], - validators: [ - { - name: ValidatorNames.HideIfNotEqual, - args: { sibling: 'secondaryCertificateNumber', value: 'pass' }, - }, - ], - asyncValidators: [{ name: AsyncValidatorNames.ResultDependantOnCustomDefects }], - type: FormNodeTypes.CONTROL, - }, - { - name: 'testTypeName', - label: 'Description', - value: '', - disabled: true, - type: FormNodeTypes.CONTROL, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'secondaryCertificateNumber', - label: 'Secondary Certificate number', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - editType: FormNodeEditTypes.TEXT, - hint: 'COIF Certificate number', - validators: [ - { - name: ValidatorNames.RequiredIfEquals, - args: { sibling: 'testResult', value: ['pass'] }, - }, - { name: ValidatorNames.MaxLength, args: 20 }, - { name: ValidatorNames.Alphanumeric }, - ], - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'prohibitionIssued', - type: FormNodeTypes.CONTROL, - label: 'Prohibition issued', - value: null, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.Required }], - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'contingencyTestNumber', + label: 'Contingency Test Number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { name: ValidatorNames.MinLength, args: 6 }, + { name: ValidatorNames.Required }, + ], + width: FormNodeWidth.L, + }, + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + { value: 'prs', label: 'PRS' }, + ], + validators: [ + { + name: ValidatorNames.HideIfNotEqual, + args: { sibling: 'secondaryCertificateNumber', value: 'pass' }, + }, + ], + asyncValidators: [{ name: AsyncValidatorNames.ResultDependantOnCustomDefects }], + type: FormNodeTypes.CONTROL, + }, + { + name: 'testTypeName', + label: 'Description', + value: '', + disabled: true, + type: FormNodeTypes.CONTROL, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'secondaryCertificateNumber', + label: 'Secondary Certificate number', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.TEXT, + hint: 'COIF Certificate number', + validators: [ + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'testResult', value: ['pass'] }, + }, + { name: ValidatorNames.MaxLength, args: 20 }, + { name: ValidatorNames.Alphanumeric }, + ], + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'prohibitionIssued', + type: FormNodeTypes.CONTROL, + label: 'Prohibition issued', + value: null, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [{ name: ValidatorNames.Required }], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-specialist-group3And4.template.ts b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-specialist-group3And4.template.ts index 32bbd691ab..6fe6638d68 100644 --- a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-specialist-group3And4.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-specialist-group3And4.template.ts @@ -1,154 +1,165 @@ import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const ContingencyTestSectionSpecialistGroup3And4: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'contingencyTestNumber', - label: 'Contingency Test Number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }, { name: ValidatorNames.MinLength, args: 6 }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - }, - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.PastDate }], - }, - { - name: 'testEndTimestamp', - label: 'Test end date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - { value: 'prs', label: 'PRS' }, - ], - validators: [ - { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'certificateNumber', value: ['pass'] } }, - { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'secondaryCertificateNumber', value: ['pass'] } }, - ], - asyncValidators: [{ name: AsyncValidatorNames.ResultDependantOnCustomDefects }], - type: FormNodeTypes.CONTROL, - }, - { - name: 'testTypeName', - label: 'Description', - value: '', - disabled: true, - type: FormNodeTypes.CONTROL, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - required: true, - value: null, - }, - { - name: 'secondaryCertificateNumber', - label: 'Secondary certificate number', - value: '', - required: true, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXT, - validators: [ - { name: ValidatorNames.Alphanumeric }, - { - name: ValidatorNames.RequiredIfEquals, - args: { sibling: 'testResult', value: ['pass'] }, - }, - { name: ValidatorNames.MaxLength, args: 20 }, - ], - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'prohibitionIssued', - type: FormNodeTypes.CONTROL, - label: 'Prohibition issued', - value: null, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.Required }], - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'contingencyTestNumber', + label: 'Contingency Test Number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { name: ValidatorNames.MinLength, args: 6 }, + { name: ValidatorNames.Required }, + ], + width: FormNodeWidth.L, + }, + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'testEndTimestamp', + label: 'Test end date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + { value: 'prs', label: 'PRS' }, + ], + validators: [ + { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'certificateNumber', value: ['pass'] } }, + { + name: ValidatorNames.HideIfNotEqual, + args: { sibling: 'secondaryCertificateNumber', value: ['pass'] }, + }, + ], + asyncValidators: [{ name: AsyncValidatorNames.ResultDependantOnCustomDefects }], + type: FormNodeTypes.CONTROL, + }, + { + name: 'testTypeName', + label: 'Description', + value: '', + disabled: true, + type: FormNodeTypes.CONTROL, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + required: true, + value: null, + }, + { + name: 'secondaryCertificateNumber', + label: 'Secondary certificate number', + value: '', + required: true, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXT, + validators: [ + { name: ValidatorNames.Alphanumeric }, + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'testResult', value: ['pass'] }, + }, + { name: ValidatorNames.MaxLength, args: 20 }, + ], + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'prohibitionIssued', + type: FormNodeTypes.CONTROL, + label: 'Prohibition issued', + value: null, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [{ name: ValidatorNames.Required }], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-specialist-group5.template.ts b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-specialist-group5.template.ts index b2616cc8d6..f88e62215e 100644 --- a/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-specialist-group5.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/contingency/contingency-test-section-specialist-group5.template.ts @@ -2,171 +2,179 @@ import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { TEST_TYPES_GROUP5_SPEC_TEST } from '@forms/models/testTypeId.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const ContingencyTestSectionSpecialistGroup5: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'contingencyTestNumber', - label: 'Contingency Test Number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }, { name: ValidatorNames.MinLength, args: 6 }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - }, - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.PastDate }], - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - { value: 'prs', label: 'PRS' }, - ], - validators: [ - { - name: ValidatorNames.ShowGroupsWhenIncludes, - args: { - values: ['fail'], - groups: ['failOnly'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenExcludes, - args: { - values: ['fail'], - groups: ['failOnly'], - }, - }, - ], - asyncValidators: [ - { name: AsyncValidatorNames.ResultDependantOnRequiredStandards }, - { - name: AsyncValidatorNames.HideIfEqualsWithCondition, - args: { - sibling: 'certificateNumber', - value: 'fail', - conditions: { field: 'testTypeId', operator: 'equals', value: TEST_TYPES_GROUP5_SPEC_TEST }, - }, - }, - ], - type: FormNodeTypes.CONTROL, - }, - { - name: 'testTypeName', - label: 'Description', - value: '', - disabled: true, + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'contingencyTestNumber', + label: 'Contingency Test Number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { name: ValidatorNames.MinLength, args: 6 }, + { name: ValidatorNames.Required }, + ], + width: FormNodeWidth.L, + }, + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + { value: 'prs', label: 'PRS' }, + ], + validators: [ + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: ['fail'], + groups: ['failOnly'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: ['fail'], + groups: ['failOnly'], + }, + }, + ], + asyncValidators: [ + { name: AsyncValidatorNames.ResultDependantOnRequiredStandards }, + { + name: AsyncValidatorNames.HideIfEqualsWithCondition, + args: { + sibling: 'certificateNumber', + value: 'fail', + conditions: { field: 'testTypeId', operator: 'equals', value: TEST_TYPES_GROUP5_SPEC_TEST }, + }, + }, + ], + type: FormNodeTypes.CONTROL, + }, + { + name: 'testTypeName', + label: 'Description', + value: '', + disabled: true, - type: FormNodeTypes.CONTROL, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - value: null, - type: FormNodeTypes.CONTROL, - required: true, - viewType: FormNodeViewTypes.STRING, - editType: FormNodeEditTypes.TEXT, - validators: [ - { name: ValidatorNames.Alphanumeric }, - { - name: ValidatorNames.RequiredIfEquals, - args: { - sibling: 'testResult', - value: ['pass', 'prs'], - }, - }, - ], - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'prohibitionIssued', - type: FormNodeTypes.CONTROL, - label: 'Prohibition issued', - value: null, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.Required }], - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + value: null, + type: FormNodeTypes.CONTROL, + required: true, + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.TEXT, + validators: [ + { name: ValidatorNames.Alphanumeric }, + { + name: ValidatorNames.RequiredIfEquals, + args: { + sibling: 'testResult', + value: ['pass', 'prs'], + }, + }, + ], + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'prohibitionIssued', + type: FormNodeTypes.CONTROL, + label: 'Prohibition issued', + value: null, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [{ name: ValidatorNames.Required }], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/contingency/old-contingency-specialist-group1.template.ts b/src/app/forms/templates/test-records/section-templates/test/contingency/old-contingency-specialist-group1.template.ts index ba8416810c..69942f4ea6 100644 --- a/src/app/forms/templates/test-records/section-templates/test/contingency/old-contingency-specialist-group1.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/contingency/old-contingency-specialist-group1.template.ts @@ -1,146 +1,154 @@ import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const OldIVAContingencyTestSectionSpecialistGroup1: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'contingencyTestNumber', - label: 'Contingency Test Number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }, { name: ValidatorNames.MinLength, args: 6 }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - }, - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.PastDate }], - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - { value: 'prs', label: 'PRS' }, - ], - asyncValidators: [ - { name: AsyncValidatorNames.ResultDependantOnCustomDefects }, - { - name: AsyncValidatorNames.HideIfEqualsWithCondition, - args: { - sibling: 'certificateNumber', - value: 'fail', - conditions: { field: 'testTypeId', operator: 'equals', value: ['150', '151', '181', '182'] }, - }, - }, - ], - type: FormNodeTypes.CONTROL, - }, - { - name: 'testTypeName', - label: 'Description', - value: '', - disabled: true, + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'contingencyTestNumber', + label: 'Contingency Test Number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { name: ValidatorNames.MinLength, args: 6 }, + { name: ValidatorNames.Required }, + ], + width: FormNodeWidth.L, + }, + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + { value: 'prs', label: 'PRS' }, + ], + asyncValidators: [ + { name: AsyncValidatorNames.ResultDependantOnCustomDefects }, + { + name: AsyncValidatorNames.HideIfEqualsWithCondition, + args: { + sibling: 'certificateNumber', + value: 'fail', + conditions: { field: 'testTypeId', operator: 'equals', value: ['150', '151', '181', '182'] }, + }, + }, + ], + type: FormNodeTypes.CONTROL, + }, + { + name: 'testTypeName', + label: 'Description', + value: '', + disabled: true, - type: FormNodeTypes.CONTROL, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.STRING, - editType: FormNodeEditTypes.TEXT, - validators: [{ name: ValidatorNames.Alphanumeric }], - required: true, - value: null, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'prohibitionIssued', - type: FormNodeTypes.CONTROL, - label: 'Prohibition issued', - value: null, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.Required }], - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.TEXT, + validators: [{ name: ValidatorNames.Alphanumeric }], + required: true, + value: null, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'prohibitionIssued', + type: FormNodeTypes.CONTROL, + label: 'Prohibition issued', + value: null, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [{ name: ValidatorNames.Required }], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/contingency/old-contingency-specialist-group5.template.ts b/src/app/forms/templates/test-records/section-templates/test/contingency/old-contingency-specialist-group5.template.ts index f950f3affa..dea912e768 100644 --- a/src/app/forms/templates/test-records/section-templates/test/contingency/old-contingency-specialist-group5.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/contingency/old-contingency-specialist-group5.template.ts @@ -1,134 +1,142 @@ import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const OldIVAContingencyTestSectionSpecialistGroup5: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'contingencyTestNumber', - label: 'Contingency Test Number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMERICSTRING, - validators: [{ name: ValidatorNames.MaxLength, args: 8 }, { name: ValidatorNames.MinLength, args: 6 }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - }, - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.PastDate }], - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - { value: 'prs', label: 'PRS' }, - ], - asyncValidators: [{ name: AsyncValidatorNames.ResultDependantOnCustomDefects }], - type: FormNodeTypes.CONTROL, - }, - { - name: 'testTypeName', - label: 'Description', - value: '', - disabled: true, + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'contingencyTestNumber', + label: 'Contingency Test Number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMERICSTRING, + validators: [ + { name: ValidatorNames.MaxLength, args: 8 }, + { name: ValidatorNames.MinLength, args: 6 }, + { name: ValidatorNames.Required }, + ], + width: FormNodeWidth.L, + }, + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + { value: 'prs', label: 'PRS' }, + ], + asyncValidators: [{ name: AsyncValidatorNames.ResultDependantOnCustomDefects }], + type: FormNodeTypes.CONTROL, + }, + { + name: 'testTypeName', + label: 'Description', + value: '', + disabled: true, - type: FormNodeTypes.CONTROL, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'prohibitionIssued', - type: FormNodeTypes.CONTROL, - label: 'Prohibition issued', - value: null, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - validators: [{ name: ValidatorNames.Required }], - }, - ], - }, - ], - }, - ], + type: FormNodeTypes.CONTROL, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'prohibitionIssued', + type: FormNodeTypes.CONTROL, + label: 'Prohibition issued', + value: null, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + validators: [{ name: ValidatorNames.Required }], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group1-PSV.template.ts b/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group1-PSV.template.ts index 7e4db16897..b7f14c607f 100644 --- a/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group1-PSV.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group1-PSV.template.ts @@ -1,221 +1,225 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const DeskBasedTestSectionGroup1Psv: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - type: FormNodeTypes.CONTROL, - value: 'pass', - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - validators: [ - { name: ValidatorNames.Alphanumeric }, - { - name: ValidatorNames.RequiredIfEquals, - args: { sibling: 'testResult', value: ['pass'] }, - }, - ], - required: true, - value: null, - }, + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + type: FormNodeTypes.CONTROL, + value: 'pass', + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + validators: [ + { name: ValidatorNames.Alphanumeric }, + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'testResult', value: ['pass'] }, + }, + ], + required: true, + value: null, + }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: null, - label: 'Test start date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: null, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testExpiryDate', - label: 'Expiry date', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - }, - { - name: 'prohibitionIssued', - label: 'Prohibition issued', - type: FormNodeTypes.CONTROL, - value: null, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: null, + label: 'Test start date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: null, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testExpiryDate', + label: 'Expiry date', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + }, + { + name: 'prohibitionIssued', + label: 'Prohibition issued', + type: FormNodeTypes.CONTROL, + value: null, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; export const AmendDeskBasedTestSectionGroup1Psv: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testCode', - label: 'Test Code', - value: '', - disabled: true, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XS, - }, - { - name: 'testResult', - label: 'Result', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - ], - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - validators: [ - { name: ValidatorNames.Alphanumeric }, - { - name: ValidatorNames.RequiredIfEquals, - args: { sibling: 'testResult', value: ['pass'] }, - }, - ], - required: true, - value: null, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: null, - label: 'Test start date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: null, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testExpiryDate', - label: 'Expiry date', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - validators: [{ name: ValidatorNames.HideIfEmpty, args: 'testAnniversaryDate' }], - }, - { - name: 'testAnniversaryDate', - label: 'Anniversary date', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - validators: [ - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.DateNotExceed, args: { sibling: 'testExpiryDate', months: 14 } }, - ], - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testCode', + label: 'Test Code', + value: '', + disabled: true, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XS, + }, + { + name: 'testResult', + label: 'Result', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + ], + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + validators: [ + { name: ValidatorNames.Alphanumeric }, + { + name: ValidatorNames.RequiredIfEquals, + args: { sibling: 'testResult', value: ['pass'] }, + }, + ], + required: true, + value: null, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: null, + label: 'Test start date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: null, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testExpiryDate', + label: 'Expiry date', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + validators: [{ name: ValidatorNames.HideIfEmpty, args: 'testAnniversaryDate' }], + }, + { + name: 'testAnniversaryDate', + label: 'Anniversary date', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + validators: [ + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.DateNotExceed, args: { sibling: 'testExpiryDate', months: 14 } }, + ], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group1And4-HGV-TRL.template.ts b/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group1And4-HGV-TRL.template.ts index f474b48b08..be890a4ba3 100644 --- a/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group1And4-HGV-TRL.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group1And4-HGV-TRL.template.ts @@ -1,195 +1,199 @@ import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const DeskBasedTestSectionGroup1And4HgvTrl: FormNode = { - name: 'requiredSection', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - type: FormNodeTypes.CONTROL, - value: 'pass', - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - required: true, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - width: FormNodeWidth.L, - required: true, - value: null, - }, + name: 'requiredSection', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + type: FormNodeTypes.CONTROL, + value: 'pass', + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + required: true, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + width: FormNodeWidth.L, + required: true, + value: null, + }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: null, - label: 'Test start date and time', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: null, - label: 'Test end date and time', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'prohibitionIssued', - label: 'Prohibition issued', - type: FormNodeTypes.CONTROL, - value: null, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: null, + label: 'Test start date and time', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: null, + label: 'Test end date and time', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'prohibitionIssued', + label: 'Prohibition issued', + type: FormNodeTypes.CONTROL, + value: null, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; export const amendDeskBasedTestSectionGroup1And4HgvTrl: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testCode', - label: 'Test Code', - value: '', - disabled: true, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.STRING, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XS, - }, - { - name: 'testResult', - label: 'Result', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - type: FormNodeTypes.CONTROL, - value: 'pass', - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - width: FormNodeWidth.L, - required: true, - value: null, - }, + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testCode', + label: 'Test Code', + value: '', + disabled: true, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.STRING, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XS, + }, + { + name: 'testResult', + label: 'Result', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + type: FormNodeTypes.CONTROL, + value: 'pass', + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + width: FormNodeWidth.L, + required: true, + value: null, + }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: null, - label: 'Test start date and time', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: null, - label: 'Test end date and time', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testNumber', - label: 'Test Number', - value: '', - disabled: true, - type: FormNodeTypes.CONTROL, - }, - ], - }, - ], - }, - ], + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: null, + label: 'Test start date and time', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: null, + label: 'Test end date and time', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testNumber', + label: 'Test Number', + value: '', + disabled: true, + type: FormNodeTypes.CONTROL, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group2.template.ts b/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group2.template.ts index beb205c3e8..7b4f529358 100644 --- a/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group2.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group2.template.ts @@ -1,204 +1,208 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const DeskBasedTestSectionGroup2And5: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - value: '', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - value: '', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - type: FormNodeTypes.CONTROL, - label: 'Result', - value: 'pass', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - value: null, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - required: true, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - value: null, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - required: true, - }, - { - name: 'certificateNumber', - type: FormNodeTypes.CONTROL, - label: 'Certificate number', - value: '', - validators: [{ name: ValidatorNames.Alphanumeric }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - required: true, - }, - { - name: 'testExpiryDate', - type: FormNodeTypes.CONTROL, - label: 'Expiry Date', - value: null, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test start date and time', - value: null, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date and time', - value: null, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'prohibitionIssued', - type: FormNodeTypes.CONTROL, - value: null, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + value: '', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + value: '', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + type: FormNodeTypes.CONTROL, + label: 'Result', + value: 'pass', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + value: null, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + required: true, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + value: null, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + required: true, + }, + { + name: 'certificateNumber', + type: FormNodeTypes.CONTROL, + label: 'Certificate number', + value: '', + validators: [{ name: ValidatorNames.Alphanumeric }, { name: ValidatorNames.Required }], + width: FormNodeWidth.L, + required: true, + }, + { + name: 'testExpiryDate', + type: FormNodeTypes.CONTROL, + label: 'Expiry Date', + value: null, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test start date and time', + value: null, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date and time', + value: null, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'prohibitionIssued', + type: FormNodeTypes.CONTROL, + value: null, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; export const AmendDeskBasedTestSectionGroup2And5: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - value: '', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - value: '', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testCode', - label: 'Test Code', - value: '', - disabled: true, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XS, - }, - { - name: 'testResult', - label: 'Result', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - ], - }, - { - name: 'certificateNumber', - type: FormNodeTypes.CONTROL, - label: 'Certificate number', - value: '', - validators: [{ name: ValidatorNames.Alphanumeric }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - required: true, - }, - { - name: 'testExpiryDate', - type: FormNodeTypes.CONTROL, - label: 'Expiry Date', - value: null, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test start date and time', - value: null, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date and time', - value: null, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + value: '', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + value: '', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testCode', + label: 'Test Code', + value: '', + disabled: true, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XS, + }, + { + name: 'testResult', + label: 'Result', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + ], + }, + { + name: 'certificateNumber', + type: FormNodeTypes.CONTROL, + label: 'Certificate number', + value: '', + validators: [{ name: ValidatorNames.Alphanumeric }, { name: ValidatorNames.Required }], + width: FormNodeWidth.L, + required: true, + }, + { + name: 'testExpiryDate', + type: FormNodeTypes.CONTROL, + label: 'Expiry Date', + value: null, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test start date and time', + value: null, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date and time', + value: null, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group3.template.ts b/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group3.template.ts index bd0d56b79d..0694519ab0 100644 --- a/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group3.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group3.template.ts @@ -1,198 +1,202 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const DeskBasedTestSectionGroup3: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testStartTimestamp', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - type: FormNodeTypes.CONTROL, - value: 'pass', - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - validators: [{ name: ValidatorNames.Alphanumeric }, { name: ValidatorNames.Required }], - value: null, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: null, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: null, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testExpiryDate', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'prohibitionIssued', - label: 'Prohibition issued', - type: FormNodeTypes.CONTROL, - value: null, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testStartTimestamp', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + type: FormNodeTypes.CONTROL, + value: 'pass', + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + validators: [{ name: ValidatorNames.Alphanumeric }, { name: ValidatorNames.Required }], + value: null, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: null, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: null, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testExpiryDate', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'prohibitionIssued', + label: 'Prohibition issued', + type: FormNodeTypes.CONTROL, + value: null, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; export const AmendDeskBasedTestSectionGroup3: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testStartTimestamp', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testCode', - label: 'Test Code', - value: '', - disabled: true, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XS, - }, - { - name: 'testResult', - label: 'Result', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - ], - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXT, - width: FormNodeWidth.L, - validators: [{ name: ValidatorNames.Alphanumeric }], - value: null, - }, - { - name: 'testNumber', - value: '', - disabled: true, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: null, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: null, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testExpiryDate', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testStartTimestamp', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testCode', + label: 'Test Code', + value: '', + disabled: true, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XS, + }, + { + name: 'testResult', + label: 'Result', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + ], + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXT, + width: FormNodeWidth.L, + validators: [{ name: ValidatorNames.Alphanumeric }], + value: null, + }, + { + name: 'testNumber', + value: '', + disabled: true, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: null, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: null, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testExpiryDate', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group4-PSV.template.ts b/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group4-PSV.template.ts index 7df18ec6dc..c3409ef041 100644 --- a/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group4-PSV.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group4-PSV.template.ts @@ -1,227 +1,231 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const DeskBasedTestSectionGroup4Psv: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - type: FormNodeTypes.CONTROL, - value: 'pass', - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - value: null, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - width: FormNodeWidth.L, - validators: [{ name: ValidatorNames.Alphanumeric }], - value: null, - }, - { - name: 'secondaryCertificateNumber', - label: 'Secondary Certificate number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXT, - width: FormNodeWidth.L, - validators: [{ name: ValidatorNames.Alphanumeric }], - value: null, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: null, - label: 'Test start date and time', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: null, - label: 'Test end date and time', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testExpiryDate', - label: 'Expiry Date', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - }, - { - name: 'prohibitionIssued', - label: 'Prohibition issued', - type: FormNodeTypes.CONTROL, - value: null, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + type: FormNodeTypes.CONTROL, + value: 'pass', + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + value: null, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + width: FormNodeWidth.L, + validators: [{ name: ValidatorNames.Alphanumeric }], + value: null, + }, + { + name: 'secondaryCertificateNumber', + label: 'Secondary Certificate number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXT, + width: FormNodeWidth.L, + validators: [{ name: ValidatorNames.Alphanumeric }], + value: null, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: null, + label: 'Test start date and time', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: null, + label: 'Test end date and time', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testExpiryDate', + label: 'Expiry Date', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + }, + { + name: 'prohibitionIssued', + label: 'Prohibition issued', + type: FormNodeTypes.CONTROL, + value: null, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; export const amendDeskBasedTestSectionGroup4Psv: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testCode', - label: 'Test Code', - value: '', - disabled: true, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XS, - }, - { - name: 'testResult', - label: 'Result', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - ], - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXT, - width: FormNodeWidth.L, - validators: [{ name: ValidatorNames.Alphanumeric }], - value: null, - }, - { - name: 'secondaryCertificateNumber', - label: 'Secondary Certificate number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXT, - width: FormNodeWidth.L, - validators: [{ name: ValidatorNames.Alphanumeric }], - value: null, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: null, - label: 'Test start date and time', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: null, - label: 'Test end date and time', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testExpiryDate', - label: 'Expiry Date', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - validators: [{ name: ValidatorNames.HideIfEmpty, args: 'testAnniversaryDate' }], - }, - { - name: 'testAnniversaryDate', - label: 'Anniversary date', - value: '', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - validators: [ - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.DateNotExceed, args: { sibling: 'testExpiryDate', months: 14 } }, - ], - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testCode', + label: 'Test Code', + value: '', + disabled: true, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XS, + }, + { + name: 'testResult', + label: 'Result', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + ], + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXT, + width: FormNodeWidth.L, + validators: [{ name: ValidatorNames.Alphanumeric }], + value: null, + }, + { + name: 'secondaryCertificateNumber', + label: 'Secondary Certificate number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXT, + width: FormNodeWidth.L, + validators: [{ name: ValidatorNames.Alphanumeric }], + value: null, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: null, + label: 'Test start date and time', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: null, + label: 'Test end date and time', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testExpiryDate', + label: 'Expiry Date', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + validators: [{ name: ValidatorNames.HideIfEmpty, args: 'testAnniversaryDate' }], + }, + { + name: 'testAnniversaryDate', + label: 'Anniversary date', + value: '', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + validators: [ + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.DateNotExceed, args: { sibling: 'testExpiryDate', months: 14 } }, + ], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group4-lgv-template.ts b/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group4-lgv-template.ts index ed9291d02f..63a8e2fc82 100644 --- a/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group4-lgv-template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group4-lgv-template.ts @@ -1,191 +1,195 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const DeskBasedTestSectionGroup4LgvCarMotorcycle: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - ], - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXT, - width: FormNodeWidth.L, - validators: [{ name: ValidatorNames.Alphanumeric }, { name: ValidatorNames.Required }], - value: null, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + ], + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXT, + width: FormNodeWidth.L, + validators: [{ name: ValidatorNames.Alphanumeric }, { name: ValidatorNames.Required }], + value: null, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + ], + }, + ], + }, + ], }; export const AmendDeskBasedTestSectionGroup4LgvCarMotorcycle: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - value: '', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - value: '', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testCode', - label: 'Test Code', - value: '', - disabled: true, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XS, - }, - { - name: 'testNumber', - label: 'Test Number', - value: '', - disabled: true, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.L, - }, - { - name: 'testResult', - label: 'Result', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - ], - }, - { - name: 'certificateNumber', - type: FormNodeTypes.CONTROL, - label: 'Certificate number', - value: '', - validators: [{ name: ValidatorNames.Alphanumeric }, { name: ValidatorNames.Required }], - width: FormNodeWidth.L, - required: true, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + value: '', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + value: '', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testCode', + label: 'Test Code', + value: '', + disabled: true, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XS, + }, + { + name: 'testNumber', + label: 'Test Number', + value: '', + disabled: true, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.L, + }, + { + name: 'testResult', + label: 'Result', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + ], + }, + { + name: 'certificateNumber', + type: FormNodeTypes.CONTROL, + label: 'Certificate number', + value: '', + validators: [{ name: ValidatorNames.Alphanumeric }, { name: ValidatorNames.Required }], + width: FormNodeWidth.L, + required: true, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group5-LGV.ts b/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group5-LGV.ts index 0a5f80bd3d..c3b1b468ba 100644 --- a/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group5-LGV.ts +++ b/src/app/forms/templates/test-records/section-templates/test/desk-based/desk-based-test-section-group5-LGV.ts @@ -1,234 +1,238 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; export const DeskBasedTestSectionLgvGroup5: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testStartTimestamp', - label: 'Test start date', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.PastDate }], - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - label: 'Test end date', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testResult', - label: 'Result', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - ], - type: FormNodeTypes.CONTROL, - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXT, - validators: [{ name: ValidatorNames.Required }, { name: ValidatorNames.Alphanumeric }], - viewType: FormNodeViewTypes.HIDDEN, - required: true, - value: null, - width: FormNodeWidth.L, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'testExpiryDate', - label: 'Expiry Date', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }], - }, - { - name: 'prohibitionIssued', - type: FormNodeTypes.CONTROL, - label: 'Prohibition issued', - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - label: 'Reason for abandoning', - value: null, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'additionalCommentsForAbandon', - type: FormNodeTypes.CONTROL, - value: null, - label: 'Additional details for abandoning', - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testStartTimestamp', + label: 'Test start date', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.PastDate }], + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + label: 'Test end date', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testStartTimestamp' }], + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testResult', + label: 'Result', + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + ], + type: FormNodeTypes.CONTROL, + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXT, + validators: [{ name: ValidatorNames.Required }, { name: ValidatorNames.Alphanumeric }], + viewType: FormNodeViewTypes.HIDDEN, + required: true, + value: null, + width: FormNodeWidth.L, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'testExpiryDate', + label: 'Expiry Date', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }], + }, + { + name: 'prohibitionIssued', + type: FormNodeTypes.CONTROL, + label: 'Prohibition issued', + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'reasonForAbandoning', + type: FormNodeTypes.CONTROL, + label: 'Reason for abandoning', + value: null, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'additionalCommentsForAbandon', + type: FormNodeTypes.CONTROL, + value: null, + label: 'Additional details for abandoning', + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], + }, + ], + }, + ], }; export const AmendDeskBasedTestSectionLgvGroup5: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testStartTimestamp', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testEndTimestamp', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'createdAt', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testCode', - label: 'Test Code', - value: '', - disabled: true, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XS, - }, - { - name: 'testResult', - label: 'Result', - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - ], - }, - { - name: 'certificateNumber', - label: 'Certificate number', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.TEXT, - width: FormNodeWidth.L, - validators: [{ name: ValidatorNames.Alphanumeric }], - value: null, - }, - { - name: 'testNumber', - value: '', - disabled: true, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypeStartTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test start date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, - ], - }, - { - name: 'testTypeEndTimestamp', - type: FormNodeTypes.CONTROL, - value: '', - label: 'Test end date and time', - viewType: FormNodeViewTypes.TIME, - editType: FormNodeEditTypes.DATETIME, - validators: [ - { name: ValidatorNames.Required }, - { name: ValidatorNames.PastDate }, - { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, - { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, - ], - }, - { - name: 'testExpiryDate', - label: 'Expiry Date', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.DATE, - validators: [{ name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }], - }, - ], - }, - ], - }, - ], + name: 'testSection', + label: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testStartTimestamp', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testEndTimestamp', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'createdAt', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + { + name: 'testTypes', + label: 'Test Types', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', // it is important here that the name of the node for an ARRAY type should be an index value + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testCode', + label: 'Test Code', + value: '', + disabled: true, + type: FormNodeTypes.CONTROL, + width: FormNodeWidth.XS, + }, + { + name: 'testResult', + label: 'Result', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: 'pass', label: 'Pass' }, + { value: 'fail', label: 'Fail' }, + ], + }, + { + name: 'certificateNumber', + label: 'Certificate number', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.TEXT, + width: FormNodeWidth.L, + validators: [{ name: ValidatorNames.Alphanumeric }], + value: null, + }, + { + name: 'testNumber', + value: '', + disabled: true, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.HIDDEN, + }, + { + name: 'testTypeStartTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test start date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testStartTimestamp' }, + ], + }, + { + name: 'testTypeEndTimestamp', + type: FormNodeTypes.CONTROL, + value: '', + label: 'Test end date and time', + viewType: FormNodeViewTypes.TIME, + editType: FormNodeEditTypes.DATETIME, + validators: [ + { name: ValidatorNames.Required }, + { name: ValidatorNames.PastDate }, + { name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }, + { name: ValidatorNames.CopyValueToRootControl, args: 'testEndTimestamp' }, + ], + }, + { + name: 'testExpiryDate', + label: 'Expiry Date', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.DATE, + editType: FormNodeEditTypes.DATE, + validators: [{ name: ValidatorNames.AheadOfDate, args: 'testTypeStartTimestamp' }], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/test-records/section-templates/test/specialist/old-specialist-test-section-group1.template.ts b/src/app/forms/templates/test-records/section-templates/test/specialist/old-specialist-test-section-group1.template.ts index b39cf61e19..e9b3a4c0d7 100644 --- a/src/app/forms/templates/test-records/section-templates/test/specialist/old-specialist-test-section-group1.template.ts +++ b/src/app/forms/templates/test-records/section-templates/test/specialist/old-specialist-test-section-group1.template.ts @@ -1,176 +1,183 @@ import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeViewTypes, FormNodeWidth, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeViewTypes, + FormNodeWidth, } from '@forms/services/dynamic-form.types'; import { ReferenceDataResourceType } from '@models/reference-data.model'; export const OldIVASpecialistTestSectionGroup1: FormNode = { - name: 'testSection', - label: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'createdAt', - label: 'Created', - disabled: true, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testStartTimestamp', - label: 'Test Date', - value: '', - disabled: true, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.DATE, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testTypes', - label: 'Test Types', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', // it is important here that the name of the node for an ARRAY type should be an index value - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testCode', - label: 'Test Code', - value: '', - disabled: true, - type: FormNodeTypes.CONTROL, - width: FormNodeWidth.XS, - editType: FormNodeEditTypes.HIDDEN, - }, - { - name: 'testResult', - label: 'Result', - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: 'pass', label: 'Pass' }, - { value: 'fail', label: 'Fail' }, - { value: 'prs', label: 'PRS' }, - { value: 'abandoned', label: 'Abandoned' }, - ], - validators: [ - { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'reasonForAbandoning', value: 'abandoned' } }, - { name: ValidatorNames.HideIfNotEqual, args: { sibling: 'additionalCommentsForAbandon', value: 'abandoned' } }, - ], - asyncValidators: [ - { name: AsyncValidatorNames.ResultDependantOnCustomDefects }, - { - name: AsyncValidatorNames.HideIfEqualsWithCondition, - args: { - sibling: 'certificateNumber', - value: 'fail', - conditions: { field: 'testTypeId', operator: 'equals', value: ['150', '151', '181', '182'] }, - }, - }, - ], - type: FormNodeTypes.CONTROL, - }, - { - name: 'reasonForAbandoning', - type: FormNodeTypes.CONTROL, - label: 'Reason for abandoning', - editType: FormNodeEditTypes.CHECKBOXGROUP, - delimited: { regex: '\\. (? option.value !== EUVehicleCategory.O1 && option.value !== EUVehicleCategory.O2, - ), - width: FormNodeWidth.S, - }, - { - name: 'techRecord_alterationMarker', - label: 'Alteration marker', - value: null, - type: FormNodeTypes.CONTROL, - viewType: FormNodeViewTypes.HIDDEN, - editType: FormNodeEditTypes.RADIO, - options: [ - { value: true, label: 'Yes' }, - { value: false, label: 'No' }, - ], - }, - { - name: 'techRecord_functionCode', - label: 'Function code', - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.HIDDEN, - viewType: FormNodeViewTypes.HIDDEN, - }, - ], + isoDate: false, + }, + { + name: 'techRecord_noOfAxles', + label: 'Number of axles', + value: null, + width: FormNodeWidth.XXS, + type: FormNodeTypes.CONTROL, + disabled: true, + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_roadFriendly', + label: 'Road friendly suspension', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + class: 'flex--half', + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_suspensionType', + label: 'Suspension type (optional)', + value: null, + width: FormNodeWidth.L, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.SELECT, + options: [ + { value: 'S', label: 'Steel' }, + { value: 'R', label: 'Rubber' }, + { value: 'A', label: 'Air' }, + { value: 'H', label: 'Hydraulic' }, + { value: 'O', label: 'Other' }, + ], + class: 'flex--half', + }, + { + name: 'techRecord_vehicleClass_description', + label: 'Vehicle class', + value: '', + customId: 'vehicleClassDescription', + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.STRING, + editType: FormNodeEditTypes.SELECT, + options: [{ label: 'trailer', value: 'trailer' }], + validators: [{ name: ValidatorNames.Required }], + customTags: [{ colour: TagType.RED, label: TagTypeLabels.REQUIRED }], + }, + { + name: 'techRecord_couplingType', + label: 'Coupling type (optional)', + value: null, + width: FormNodeWidth.XL, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: CouplingTypeOptions, + validators: [{ name: ValidatorNames.MaxLength, args: 1 }], + class: 'flex--half', + }, + { + name: 'techRecord_maxLoadOnCoupling', + label: 'Max load on coupling (optional)', + value: null, + width: FormNodeWidth.M, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [{ name: ValidatorNames.Max, args: 99999 }], + class: 'flex--half', + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_vehicleConfiguration', + label: 'Vehicle configuration', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: getOptionsFromEnum(VehicleConfiguration), + validators: [{ name: ValidatorNames.UpdateFunctionCode }], + customTags: [ + { colour: TagType.RED, label: TagTypeLabels.REQUIRED }, + { colour: TagType.PURPLE, label: TagTypeLabels.PLATES }, + ], + }, + { + name: 'techRecord_frameDescription', + label: 'Frame description (optional)', + value: null, + width: FormNodeWidth.XL, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: getOptionsFromEnum(FrameDescriptions), + }, + { + name: 'techRecord_departmentalVehicleMarker', + label: 'Departmental vehicle marker', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + }, + { + name: 'techRecord_euVehicleCategory', + label: 'EU vehicle category', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + options: getOptionsFromEnum(EUVehicleCategory).filter( + (option) => option.value !== EUVehicleCategory.O1 && option.value !== EUVehicleCategory.O2 + ), + width: FormNodeWidth.S, + }, + { + name: 'techRecord_alterationMarker', + label: 'Alteration marker', + value: null, + type: FormNodeTypes.CONTROL, + viewType: FormNodeViewTypes.HIDDEN, + editType: FormNodeEditTypes.RADIO, + options: [ + { value: true, label: 'Yes' }, + { value: false, label: 'No' }, + ], + }, + { + name: 'techRecord_functionCode', + label: 'Function code', + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.HIDDEN, + viewType: FormNodeViewTypes.HIDDEN, + }, + ], }; diff --git a/src/app/forms/templates/trl/trl-tyres.template.ts b/src/app/forms/templates/trl/trl-tyres.template.ts index 3f4f8715ca..96d7d8a4c4 100644 --- a/src/app/forms/templates/trl/trl-tyres.template.ts +++ b/src/app/forms/templates/trl/trl-tyres.template.ts @@ -1,92 +1,104 @@ import { TyreUseCode } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/tyreUseCodeTrl.enum.js'; import { ValidatorNames } from '@forms/models/validators.enum'; import { - FormNode, FormNodeEditTypes, FormNodeTypes, FormNodeWidth, TagTypeLabels, + FormNode, + FormNodeEditTypes, + FormNodeTypes, + FormNodeWidth, + TagTypeLabels, } from '@forms/services/dynamic-form.types'; import { getOptionsFromEnum } from '@forms/utils/enum-map'; import { TagType } from '@shared/components/tag/tag.component'; export const tyresTemplateTrl: FormNode = { - name: 'tyreSection', - type: FormNodeTypes.GROUP, - label: 'Tyres', - children: [ - { - name: 'techRecord_tyreUseCode', - label: 'Tyre use code', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.SELECT, - width: FormNodeWidth.UNSET, - options: getOptionsFromEnum(TyreUseCode), - customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], - }, - { - name: 'techRecord_axles', - value: '', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', - label: 'Axle', - value: '', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'axleNumber', - label: 'Axle Number', - type: FormNodeTypes.CONTROL, - }, + name: 'tyreSection', + type: FormNodeTypes.GROUP, + label: 'Tyres', + children: [ + { + name: 'techRecord_tyreUseCode', + label: 'Tyre use code', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.SELECT, + width: FormNodeWidth.UNSET, + options: getOptionsFromEnum(TyreUseCode), + customTags: [{ colour: TagType.PURPLE, label: TagTypeLabels.PLATES }], + }, + { + name: 'techRecord_axles', + value: '', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + label: 'Axle', + value: '', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'axleNumber', + label: 'Axle Number', + type: FormNodeTypes.CONTROL, + }, - { - name: 'tyres_tyreCode', - label: 'Tyre Code', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - validators: [{ name: ValidatorNames.Numeric }, { name: ValidatorNames.Max, args: 99999 }, { name: ValidatorNames.Min, args: 0 }], - }, - { - name: 'tyres_tyreSize', - label: 'Tyre Size', - value: null, - type: FormNodeTypes.CONTROL, - disabled: true, - validators: [ - { name: ValidatorNames.MaxLength, args: 12 }, - { name: ValidatorNames.Min, args: 0 }, - ], - }, - { - name: 'tyres_plyRating', - label: 'Ply Rating', - value: null, - type: FormNodeTypes.CONTROL, - disabled: true, - validators: [ - { name: ValidatorNames.MaxLength, args: 2 }, - { name: ValidatorNames.Min, args: 0 }, - ], - }, - { - name: 'tyres_fitmentCode', - label: 'Fitment code', - value: null, - type: FormNodeTypes.CONTROL, - validators: [], - }, - { - name: 'tyres_dataTrAxles', - label: 'Load index', - value: null, - type: FormNodeTypes.CONTROL, - editType: FormNodeEditTypes.NUMBER, - disabled: true, - validators: [{ name: ValidatorNames.Numeric }, { name: ValidatorNames.Max, args: 999 }, { name: ValidatorNames.Min, args: 0 }], - }, - ], - }, - ], - }, - ], + { + name: 'tyres_tyreCode', + label: 'Tyre Code', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + validators: [ + { name: ValidatorNames.Numeric }, + { name: ValidatorNames.Max, args: 99999 }, + { name: ValidatorNames.Min, args: 0 }, + ], + }, + { + name: 'tyres_tyreSize', + label: 'Tyre Size', + value: null, + type: FormNodeTypes.CONTROL, + disabled: true, + validators: [ + { name: ValidatorNames.MaxLength, args: 12 }, + { name: ValidatorNames.Min, args: 0 }, + ], + }, + { + name: 'tyres_plyRating', + label: 'Ply Rating', + value: null, + type: FormNodeTypes.CONTROL, + disabled: true, + validators: [ + { name: ValidatorNames.MaxLength, args: 2 }, + { name: ValidatorNames.Min, args: 0 }, + ], + }, + { + name: 'tyres_fitmentCode', + label: 'Fitment code', + value: null, + type: FormNodeTypes.CONTROL, + validators: [], + }, + { + name: 'tyres_dataTrAxles', + label: 'Load index', + value: null, + type: FormNodeTypes.CONTROL, + editType: FormNodeEditTypes.NUMBER, + disabled: true, + validators: [ + { name: ValidatorNames.Numeric }, + { name: ValidatorNames.Max, args: 999 }, + { name: ValidatorNames.Min, args: 0 }, + ], + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/templates/trl/trl-weight.template.ts b/src/app/forms/templates/trl/trl-weight.template.ts index 0677d746ba..5db450a1a2 100644 --- a/src/app/forms/templates/trl/trl-weight.template.ts +++ b/src/app/forms/templates/trl/trl-weight.template.ts @@ -2,104 +2,104 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { FormNode, FormNodeEditTypes, FormNodeTypes } from '../../services/dynamic-form.types'; const requiredValidation = [ - { name: ValidatorNames.Numeric, args: 99999 }, - { name: ValidatorNames.Max, args: 99999 }, - { name: ValidatorNames.Min, args: 0 }, + { name: ValidatorNames.Numeric, args: 99999 }, + { name: ValidatorNames.Max, args: 99999 }, + { name: ValidatorNames.Min, args: 0 }, ]; const optionalValidation = [ - { name: ValidatorNames.Numeric, args: 99999 }, - { name: ValidatorNames.Max, args: 99999 }, - { name: ValidatorNames.Min, args: 0 }, + { name: ValidatorNames.Numeric, args: 99999 }, + { name: ValidatorNames.Max, args: 99999 }, + { name: ValidatorNames.Min, args: 0 }, ]; export const TrlWeight: FormNode = { - name: 'weightsSection', - label: 'Weights', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'grossSection', - label: 'Gross vehicle weight', - value: '', - type: FormNodeTypes.SECTION, - }, - { - name: 'techRecord_grossGbWeight', - label: 'GB', - customValidatorErrorName: 'Gross GB Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - }, - { - name: 'techRecord_grossEecWeight', - label: 'EEC (optional)', - customValidatorErrorName: 'Gross EEC Weight', - value: null, - editType: FormNodeEditTypes.NUMBER, - type: FormNodeTypes.CONTROL, - validators: optionalValidation, - }, - { - name: 'techRecord_grossDesignWeight', - label: 'Design', - customValidatorErrorName: 'Gross Design Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - }, - { - name: 'axleSection', - label: 'Axle weights', - value: '', - type: FormNodeTypes.SECTION, - }, - { - name: 'techRecord_axles', - value: '', - type: FormNodeTypes.ARRAY, - children: [ - { - name: '0', - label: 'Axle', - value: '', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'axleNumber', - label: 'Axle Number', - type: FormNodeTypes.CONTROL, - }, + name: 'weightsSection', + label: 'Weights', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'grossSection', + label: 'Gross vehicle weight', + value: '', + type: FormNodeTypes.SECTION, + }, + { + name: 'techRecord_grossGbWeight', + label: 'GB', + customValidatorErrorName: 'Gross GB Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + }, + { + name: 'techRecord_grossEecWeight', + label: 'EEC (optional)', + customValidatorErrorName: 'Gross EEC Weight', + value: null, + editType: FormNodeEditTypes.NUMBER, + type: FormNodeTypes.CONTROL, + validators: optionalValidation, + }, + { + name: 'techRecord_grossDesignWeight', + label: 'Design', + customValidatorErrorName: 'Gross Design Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + }, + { + name: 'axleSection', + label: 'Axle weights', + value: '', + type: FormNodeTypes.SECTION, + }, + { + name: 'techRecord_axles', + value: '', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + label: 'Axle', + value: '', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'axleNumber', + label: 'Axle Number', + type: FormNodeTypes.CONTROL, + }, - { - name: 'weights_gbWeight', - label: 'GB weight', - customValidatorErrorName: 'Axle GB Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - }, - { - name: 'weights_eecWeight', - label: 'EEC (optional)', - customValidatorErrorName: 'Axle EEC Weight', - value: null, - editType: FormNodeEditTypes.NUMBER, - type: FormNodeTypes.CONTROL, - validators: optionalValidation, - }, - { - name: 'weights_designWeight', - label: 'Design weight', - customValidatorErrorName: 'Axle Design Weight', - value: null, - type: FormNodeTypes.CONTROL, - validators: requiredValidation, - }, - ], - }, - ], - }, - ], + { + name: 'weights_gbWeight', + label: 'GB weight', + customValidatorErrorName: 'Axle GB Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + }, + { + name: 'weights_eecWeight', + label: 'EEC (optional)', + customValidatorErrorName: 'Axle EEC Weight', + value: null, + editType: FormNodeEditTypes.NUMBER, + type: FormNodeTypes.CONTROL, + validators: optionalValidation, + }, + { + name: 'weights_designWeight', + label: 'Design weight', + customValidatorErrorName: 'Axle Design Weight', + value: null, + type: FormNodeTypes.CONTROL, + validators: requiredValidation, + }, + ], + }, + ], + }, + ], }; diff --git a/src/app/forms/utils/enum-map.ts b/src/app/forms/utils/enum-map.ts index 560afc5839..d58ac8ff13 100644 --- a/src/app/forms/utils/enum-map.ts +++ b/src/app/forms/utils/enum-map.ts @@ -1,14 +1,14 @@ import { MultiOptions } from '@forms/models/options.model'; export function getOptionsFromEnum(object: object): MultiOptions { - // eslint-disable-next-line @typescript-eslint/restrict-plus-operands - return Object.values(object).map((value) => ({ value, label: value.charAt(0).toUpperCase() + value.slice(1) })); + // eslint-disable-next-line @typescript-eslint/restrict-plus-operands + return Object.values(object).map((value) => ({ value, label: value.charAt(0).toUpperCase() + value.slice(1) })); } export function getOptionsFromEnumOneChar(object: object): MultiOptions { - return Object.values(object).map((value) => ({ value, label: value.charAt(0).toUpperCase() })); + return Object.values(object).map((value) => ({ value, label: value.charAt(0).toUpperCase() })); } export function getOptionsFromEnumAcronym(object: object): MultiOptions { - return Object.values(object).map((value) => ({ value, label: value.toUpperCase() })); + return Object.values(object).map((value) => ({ value, label: value.toUpperCase() })); } diff --git a/src/app/forms/utils/error-message-map.spec.ts b/src/app/forms/utils/error-message-map.spec.ts index 66b2c8dca8..40ff715e81 100644 --- a/src/app/forms/utils/error-message-map.spec.ts +++ b/src/app/forms/utils/error-message-map.spec.ts @@ -3,53 +3,69 @@ import { ValidatorNames } from '@forms/models/validators.enum'; import { ErrorMessageMap } from './error-message-map'; describe('ErrorMessageMap', () => { - it.each([ - ['This field is required', ValidatorNames.Required, [true, '']], - ['This field is required', ValidatorNames.Required, [true, undefined]], - ['This field is required', ValidatorNames.Required, [true, null]], - ['Name is required', ValidatorNames.Required, [true, 'Name']], - ['This field must match a pattern', ValidatorNames.Pattern, [true, '']], - ['Name must match a pattern', ValidatorNames.Pattern, [true, 'Name']], - ['This field must match pattern xxx', ValidatorNames.CustomPattern, [{ message: 'must match pattern xxx' }, '']], - ['Name must match pattern xxx', ValidatorNames.CustomPattern, [{ message: 'must match pattern xxx' }, 'Name']], - ['\'Date\' is not valid', 'invalidDate', [{ error: true, reason: '\'Date\' is not valid' }]], - ['Name must be less than or equal to 14 characters', ValidatorNames.MaxLength, [{ requiredLength: 14 }, 'Name']], - ['This field must be less than or equal to 14 characters', ValidatorNames.MaxLength, [{ requiredLength: 14 }, '']], - ['Name must be greater than or equal to 14 characters', ValidatorNames.MinLength, [{ requiredLength: 14 }, 'Name']], - ['This field must be greater than or equal to 14 characters', ValidatorNames.MinLength, [{ requiredLength: 14 }, '']], - ['Name is required with Surname', ValidatorNames.RequiredIfEquals, [{ sibling: 'Surname' }, 'Name']], - ['This field is required with Surname', ValidatorNames.RequiredIfEquals, [{ sibling: 'Surname' }, '']], - ['Notes is required', ValidatorNames.ValidateDefectNotes, undefined], - ['foo', 'invalidTestResult', [{ message: 'foo' }]], - ['This field must be less than or equal to 5', ValidatorNames.Max, [{ max: 5 }, '']], - ['Number must be less than or equal to 5', ValidatorNames.Max, [{ max: 5 }, 'Number']], - ['This field must be greater than or equal to 5', ValidatorNames.Min, [{ min: 5 }, '']], - ['Number must be greater than or equal to 5', ValidatorNames.Min, [{ min: 5 }, 'Number']], - ['Date must be in the past', ValidatorNames.PastDate, [true, 'Date']], - ['This date must be in the past', ValidatorNames.PastDate, [true, undefined]], - ['Date must be in the future', ValidatorNames.FutureDate, [true, 'Date']], - ['This date must be in the future', ValidatorNames.FutureDate, [true, undefined]], - ['This date must be ahead of the previous date', ValidatorNames.AheadOfDate, [true, undefined]], - ['This year must be the current or a past year', ValidatorNames.PastYear, [true, undefined]], - ['bar must be ahead of foo (20/01/2021)', ValidatorNames.AheadOfDate, [{ sibling: 'foo', date: new Date('2021-01-20T00:00:00.000Z') }, 'bar']], - ['This field is required', AsyncValidatorNames.RequiredIfNotFail, [{ sibling: 'foo' }, '']], - ['Name is required', AsyncValidatorNames.RequiredIfNotFail, [{ sibling: 'foo' }, 'Name']], - ['Prohibition notice has not been issued.', ValidatorNames.ValidateProhibitionIssued, undefined], - ['This field is required', AsyncValidatorNames.RequiredIfNotAbandoned, [{ sibling: 'foo' }, '']], - ['Name is required', AsyncValidatorNames.RequiredIfNotAbandoned, [{ sibling: 'foo' }, 'Name']], - ['This field is required', AsyncValidatorNames.RequiredIfNotResult, [{ sibling: 'foo' }, '']], - ['Name is required', AsyncValidatorNames.RequiredIfNotResult, [{ sibling: 'foo' }, 'Name']], - ['This field is required', AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, [{ sibling: 'foo' }, '']], - ['Name is required', AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, [{ sibling: 'foo' }, 'Name']], - ['This date must be less than 10 months after the previous date', ValidatorNames.DateNotExceed, [{ months: '10' }, '']], - ['Name must be less than 15 months after foo', ValidatorNames.DateNotExceed, [{ sibling: 'foo', months: '15' }, 'Name']], - ])('should return "%s" for %s with %o', (expected, key, props) => { - if (props) { - // eslint-disable-next-line jest/no-conditional-expect - expect(ErrorMessageMap[`${key}`](...props)).toBe(expected); - } else { - // eslint-disable-next-line jest/no-conditional-expect - expect(ErrorMessageMap[`${key}`]()).toBe(expected); - } - }); + it.each([ + ['This field is required', ValidatorNames.Required, [true, '']], + ['This field is required', ValidatorNames.Required, [true, undefined]], + ['This field is required', ValidatorNames.Required, [true, null]], + ['Name is required', ValidatorNames.Required, [true, 'Name']], + ['This field must match a pattern', ValidatorNames.Pattern, [true, '']], + ['Name must match a pattern', ValidatorNames.Pattern, [true, 'Name']], + ['This field must match pattern xxx', ValidatorNames.CustomPattern, [{ message: 'must match pattern xxx' }, '']], + ['Name must match pattern xxx', ValidatorNames.CustomPattern, [{ message: 'must match pattern xxx' }, 'Name']], + ["'Date' is not valid", 'invalidDate', [{ error: true, reason: "'Date' is not valid" }]], + ['Name must be less than or equal to 14 characters', ValidatorNames.MaxLength, [{ requiredLength: 14 }, 'Name']], + ['This field must be less than or equal to 14 characters', ValidatorNames.MaxLength, [{ requiredLength: 14 }, '']], + ['Name must be greater than or equal to 14 characters', ValidatorNames.MinLength, [{ requiredLength: 14 }, 'Name']], + [ + 'This field must be greater than or equal to 14 characters', + ValidatorNames.MinLength, + [{ requiredLength: 14 }, ''], + ], + ['Name is required with Surname', ValidatorNames.RequiredIfEquals, [{ sibling: 'Surname' }, 'Name']], + ['This field is required with Surname', ValidatorNames.RequiredIfEquals, [{ sibling: 'Surname' }, '']], + ['Notes is required', ValidatorNames.ValidateDefectNotes, undefined], + ['foo', 'invalidTestResult', [{ message: 'foo' }]], + ['This field must be less than or equal to 5', ValidatorNames.Max, [{ max: 5 }, '']], + ['Number must be less than or equal to 5', ValidatorNames.Max, [{ max: 5 }, 'Number']], + ['This field must be greater than or equal to 5', ValidatorNames.Min, [{ min: 5 }, '']], + ['Number must be greater than or equal to 5', ValidatorNames.Min, [{ min: 5 }, 'Number']], + ['Date must be in the past', ValidatorNames.PastDate, [true, 'Date']], + ['This date must be in the past', ValidatorNames.PastDate, [true, undefined]], + ['Date must be in the future', ValidatorNames.FutureDate, [true, 'Date']], + ['This date must be in the future', ValidatorNames.FutureDate, [true, undefined]], + ['This date must be ahead of the previous date', ValidatorNames.AheadOfDate, [true, undefined]], + ['This year must be the current or a past year', ValidatorNames.PastYear, [true, undefined]], + [ + 'bar must be ahead of foo (20/01/2021)', + ValidatorNames.AheadOfDate, + [{ sibling: 'foo', date: new Date('2021-01-20T00:00:00.000Z') }, 'bar'], + ], + ['This field is required', AsyncValidatorNames.RequiredIfNotFail, [{ sibling: 'foo' }, '']], + ['Name is required', AsyncValidatorNames.RequiredIfNotFail, [{ sibling: 'foo' }, 'Name']], + ['Prohibition notice has not been issued.', ValidatorNames.ValidateProhibitionIssued, undefined], + ['This field is required', AsyncValidatorNames.RequiredIfNotAbandoned, [{ sibling: 'foo' }, '']], + ['Name is required', AsyncValidatorNames.RequiredIfNotAbandoned, [{ sibling: 'foo' }, 'Name']], + ['This field is required', AsyncValidatorNames.RequiredIfNotResult, [{ sibling: 'foo' }, '']], + ['Name is required', AsyncValidatorNames.RequiredIfNotResult, [{ sibling: 'foo' }, 'Name']], + ['This field is required', AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, [{ sibling: 'foo' }, '']], + ['Name is required', AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals, [{ sibling: 'foo' }, 'Name']], + [ + 'This date must be less than 10 months after the previous date', + ValidatorNames.DateNotExceed, + [{ months: '10' }, ''], + ], + [ + 'Name must be less than 15 months after foo', + ValidatorNames.DateNotExceed, + [{ sibling: 'foo', months: '15' }, 'Name'], + ], + ])('should return "%s" for %s with %o', (expected, key, props) => { + if (props) { + // eslint-disable-next-line jest/no-conditional-expect + expect(ErrorMessageMap[`${key}`](...props)).toBe(expected); + } else { + // eslint-disable-next-line jest/no-conditional-expect + expect(ErrorMessageMap[`${key}`]()).toBe(expected); + } + }); }); diff --git a/src/app/forms/utils/error-message-map.ts b/src/app/forms/utils/error-message-map.ts index 99c73bf180..9f301062a7 100644 --- a/src/app/forms/utils/error-message-map.ts +++ b/src/app/forms/utils/error-message-map.ts @@ -4,52 +4,63 @@ import { ValidatorNames } from '@forms/models/validators.enum'; const DEFAULT_LABEL = 'This field'; export const ErrorMessageMap: Record = { - // Date errors - invalidDate: (err: { error: boolean; reason: string; index: number }) => `${err.reason}`, - invalidOption: (err: boolean, label?: string) => `${label || DEFAULT_LABEL} is invalid`, - invalidTestResult: (err: { message: string }) => err.message, + // Date errors + invalidDate: (err: { error: boolean; reason: string; index: number }) => `${err.reason}`, + invalidOption: (err: boolean, label?: string) => `${label || DEFAULT_LABEL} is invalid`, + invalidTestResult: (err: { message: string }) => err.message, - validateVin: (error: { message: string }) => error.message, - validateForBatch: (error: { message: string }) => error.message, - validateVrm: (error: { message: string }) => error.message, + validateVin: (error: { message: string }) => error.message, + validateForBatch: (error: { message: string }) => error.message, + validateVrm: (error: { message: string }) => error.message, - [ValidatorNames.AheadOfDate]: (err: { sibling: string; date: Date }, label?: string) => - `${label || 'This date'} must be ahead of ${err.sibling || 'the previous date'}${err.date ? formatDate(err.date, ' (dd/MM/yyyy)', 'en') : ''}`, - [ValidatorNames.CustomPattern]: (err: { message: string }, label?: string) => `${label || DEFAULT_LABEL} ${err.message}`, - [ValidatorNames.DateNotExceed]: (err: { sibling: string; months: number }, label?: string) => - `${label || 'This date'} must be less than ${err.months || 'X'} months after ${err.sibling || 'the previous date'}`, - [ValidatorNames.Defined]: (err: boolean, label?: string) => `${label} is required`, - [ValidatorNames.FutureDate]: (err: boolean, label?: string) => `${label || 'This date'} must be in the future`, - [ValidatorNames.PastYear]: (err: boolean, label?: string) => `${label || 'This year'} must be the current or a past year`, - [ValidatorNames.Max]: (err: { max: number }, label?: string) => `${label || DEFAULT_LABEL} must be less than or equal to ${err.max}`, - [ValidatorNames.MaxLength]: (err: { requiredLength: number }, label?: string) => - `${label || DEFAULT_LABEL} must be less than or equal to ${err.requiredLength} characters`, - [ValidatorNames.Min]: (err: { min: number }, label?: string) => `${label || DEFAULT_LABEL} must be greater than or equal to ${err.min}`, - [ValidatorNames.MinLength]: (err: { requiredLength: number }, label?: string) => - `${label || DEFAULT_LABEL} must be greater than or equal to ${err.requiredLength} characters`, - [ValidatorNames.NotZNumber]: () => 'The VRM/Trailer ID cannot be in a format that is 7 digits followed by the character \'Z\'', - [ValidatorNames.PastDate]: (err: boolean, label?: string) => `${label || 'This date'} must be in the past`, - [ValidatorNames.Pattern]: (err: boolean, label?: string) => `${label || DEFAULT_LABEL} must match a pattern`, - [ValidatorNames.Required]: (err: boolean, label?: string) => `${label || DEFAULT_LABEL} is required`, - [ValidatorNames.RequiredIfEquals]: (err: { sibling: string; customErrorMessage: string }, label?: string) => - err.customErrorMessage ?? `${label || DEFAULT_LABEL} is required with ${err.sibling}`, - [ValidatorNames.RequiredIfNotEquals]: (err: { sibling: string }, label?: string) => `${label || DEFAULT_LABEL} is required with ${err.sibling}`, - [ValidatorNames.requiredIfAllEquals]: (err: { sibling: string }, label?: string) => `${label || DEFAULT_LABEL} is required with ${err.sibling}`, - [ValidatorNames.RequiredIfNotHidden]: (label?: string) => `${label || DEFAULT_LABEL} is required`, - [ValidatorNames.ValidateDefectNotes]: () => 'Notes is required', - [ValidatorNames.ValidateProhibitionIssued]: () => 'Prohibition notice has not been issued.', - [ValidatorNames.ValidateVRMTrailerIdLength]: (err: { message: string }) => err.message, - [ValidatorNames.MustEqualSibling]: (err: { sibling: string }, label?: string) => `${label || DEFAULT_LABEL} must match ${err.sibling}`, - [ValidatorNames.IsMemberOfEnum]: (err: boolean, label?: string) => `${label || DEFAULT_LABEL} is required`, - [ValidatorNames.IsArray]: (err: { message: string }, label?: string) => `${label || DEFAULT_LABEL}`, - [ValidatorNames.Tc3TestValidator]: (err: { message: string }) => `${err.message}`, - [ValidatorNames.DateIsInvalid]: (err: { message?: string }, label?: string) => err.message ?? `${label || DEFAULT_LABEL} is invalid`, - [ValidatorNames.Custom]: (err: { message: string }) => err.message, - [ValidatorNames.MinArrayLengthIfNotEmpty]: (err: { message: string }) => err.message, + [ValidatorNames.AheadOfDate]: (err: { sibling: string; date: Date }, label?: string) => + `${label || 'This date'} must be ahead of ${err.sibling || 'the previous date'}${err.date ? formatDate(err.date, ' (dd/MM/yyyy)', 'en') : ''}`, + [ValidatorNames.CustomPattern]: (err: { message: string }, label?: string) => + `${label || DEFAULT_LABEL} ${err.message}`, + [ValidatorNames.DateNotExceed]: (err: { sibling: string; months: number }, label?: string) => + `${label || 'This date'} must be less than ${err.months || 'X'} months after ${err.sibling || 'the previous date'}`, + [ValidatorNames.Defined]: (err: boolean, label?: string) => `${label} is required`, + [ValidatorNames.FutureDate]: (err: boolean, label?: string) => `${label || 'This date'} must be in the future`, + [ValidatorNames.PastYear]: (err: boolean, label?: string) => + `${label || 'This year'} must be the current or a past year`, + [ValidatorNames.Max]: (err: { max: number }, label?: string) => + `${label || DEFAULT_LABEL} must be less than or equal to ${err.max}`, + [ValidatorNames.MaxLength]: (err: { requiredLength: number }, label?: string) => + `${label || DEFAULT_LABEL} must be less than or equal to ${err.requiredLength} characters`, + [ValidatorNames.Min]: (err: { min: number }, label?: string) => + `${label || DEFAULT_LABEL} must be greater than or equal to ${err.min}`, + [ValidatorNames.MinLength]: (err: { requiredLength: number }, label?: string) => + `${label || DEFAULT_LABEL} must be greater than or equal to ${err.requiredLength} characters`, + [ValidatorNames.NotZNumber]: () => + "The VRM/Trailer ID cannot be in a format that is 7 digits followed by the character 'Z'", + [ValidatorNames.PastDate]: (err: boolean, label?: string) => `${label || 'This date'} must be in the past`, + [ValidatorNames.Pattern]: (err: boolean, label?: string) => `${label || DEFAULT_LABEL} must match a pattern`, + [ValidatorNames.Required]: (err: boolean, label?: string) => `${label || DEFAULT_LABEL} is required`, + [ValidatorNames.RequiredIfEquals]: (err: { sibling: string; customErrorMessage: string }, label?: string) => + err.customErrorMessage ?? `${label || DEFAULT_LABEL} is required with ${err.sibling}`, + [ValidatorNames.RequiredIfNotEquals]: (err: { sibling: string }, label?: string) => + `${label || DEFAULT_LABEL} is required with ${err.sibling}`, + [ValidatorNames.requiredIfAllEquals]: (err: { sibling: string }, label?: string) => + `${label || DEFAULT_LABEL} is required with ${err.sibling}`, + [ValidatorNames.RequiredIfNotHidden]: (label?: string) => `${label || DEFAULT_LABEL} is required`, + [ValidatorNames.ValidateDefectNotes]: () => 'Notes is required', + [ValidatorNames.ValidateProhibitionIssued]: () => 'Prohibition notice has not been issued.', + [ValidatorNames.ValidateVRMTrailerIdLength]: (err: { message: string }) => err.message, + [ValidatorNames.MustEqualSibling]: (err: { sibling: string }, label?: string) => + `${label || DEFAULT_LABEL} must match ${err.sibling}`, + [ValidatorNames.IsMemberOfEnum]: (err: boolean, label?: string) => `${label || DEFAULT_LABEL} is required`, + [ValidatorNames.IsArray]: (err: { message: string }, label?: string) => `${label || DEFAULT_LABEL}`, + [ValidatorNames.Tc3TestValidator]: (err: { message: string }) => `${err.message}`, + [ValidatorNames.DateIsInvalid]: (err: { message?: string }, label?: string) => + err.message ?? `${label || DEFAULT_LABEL} is invalid`, + [ValidatorNames.Custom]: (err: { message: string }) => err.message, + [ValidatorNames.MinArrayLengthIfNotEmpty]: (err: { message: string }) => err.message, - [AsyncValidatorNames.RequiredIfNotAbandoned]: (err: boolean, label?: string) => `${label || DEFAULT_LABEL} is required`, - [AsyncValidatorNames.RequiredIfNotFail]: (err: boolean, label?: string) => `${label || DEFAULT_LABEL} is required`, - [AsyncValidatorNames.RequiredIfNotResult]: (err: boolean, label?: string) => `${label || DEFAULT_LABEL} is required`, - [AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals]: (err: boolean, label?: string) => `${label || DEFAULT_LABEL} is required`, - [AsyncValidatorNames.RequiredWhenCarryingDangerousGoods]: (err: { message: string }) => err.message, + [AsyncValidatorNames.RequiredIfNotAbandoned]: (err: boolean, label?: string) => + `${label || DEFAULT_LABEL} is required`, + [AsyncValidatorNames.RequiredIfNotFail]: (err: boolean, label?: string) => `${label || DEFAULT_LABEL} is required`, + [AsyncValidatorNames.RequiredIfNotResult]: (err: boolean, label?: string) => `${label || DEFAULT_LABEL} is required`, + [AsyncValidatorNames.RequiredIfNotResultAndSiblingEquals]: (err: boolean, label?: string) => + `${label || DEFAULT_LABEL} is required`, + [AsyncValidatorNames.RequiredWhenCarryingDangerousGoods]: (err: { message: string }) => err.message, }; diff --git a/src/app/forms/utils/tech-record-constants.ts b/src/app/forms/utils/tech-record-constants.ts index 6a43047c6d..dacd898c42 100644 --- a/src/app/forms/utils/tech-record-constants.ts +++ b/src/app/forms/utils/tech-record-constants.ts @@ -26,6 +26,8 @@ import { PsvTyresTemplate } from '@forms/templates/psv/psv-tyres.template'; import { PsvWeightsTemplate } from '@forms/templates/psv/psv-weight.template'; import { SmallTrailerTechRecord } from '@forms/templates/small-trailer/small-trailer-tech-record.template'; +import { AdrCertificateTemplate } from '@forms/templates/general/adr-certificate.template'; +import { AdrTemplate } from '@forms/templates/general/adr.template'; import { TechRecordReasonForCreationSection } from '@forms/templates/general/reason-for-creation.template'; import { TrlAuthIntoServiceTemplate } from '@forms/templates/trl/trl-auth-into-service.template'; import { TrlBrakesTemplate } from '@forms/templates/trl/trl-brakes.template'; @@ -35,93 +37,109 @@ import { TrlTechRecordTemplate } from '@forms/templates/trl/trl-tech-record.temp import { tyresTemplateTrl } from '@forms/templates/trl/trl-tyres.template'; import { TrlWeight } from '@forms/templates/trl/trl-weight.template'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; -import { AdrTemplate } from '@forms/templates/general/adr.template'; -import { AdrCertificateTemplate } from '@forms/templates/general/adr-certificate.template'; // The map below initializes the array of sections that the *ngFor in tech summary component's template will iterate over. // The order in which each section is introduced in the array will determine its order on the page when rendered. // Sections which use custom components require a FormNode object with 'name' and 'label' properties. export const vehicleTemplateMap = new Map>([ - [ - VehicleTypes.PSV, - [ - /* 1 */ TechRecordReasonForCreationSection, - /* 2 */ PsvNotes, - /* 3 */ PsvTechRecord, - /* 4 */ PsvTypeApprovalTemplate, - /* 5 */ PsvBrakesTemplate, - /* 6 */ PsvDdaTemplate, - /* 7 */ DocumentsTemplate, - /* 8 */ PsvBodyTemplate, - /* 9 */ PsvWeightsTemplate, - /* 10 */ PsvTyresTemplate, - /* 11 */ PsvDimensionsTemplate, - ], - ], - [ - VehicleTypes.HGV, - [ - /* 1 */ TechRecordReasonForCreationSection, - /* 2 */ NotesTemplate, - /* 3 */ HgvTechRecord, - /* 4 */ HgvAndTrlTypeApprovalTemplate, - /* 5 */ ApplicantDetails, - /* 6 */ DocumentsTemplate, - /* 7 */ HgvAndTrlBodyTemplate, - /* 8 */ HgvWeight, - /* 9 */ tyresTemplateHgv, - /* 10 */ HgvDimensionsTemplate, - /* 11 */ PlatesTemplate, - /* 12 */ AdrTemplate, - /* 13 */ AdrCertificateTemplate, - ], - ], - [ - VehicleTypes.TRL, - [ - /* 1 */ TechRecordReasonForCreationSection, - /* 2 */ NotesTemplate, - /* 3 */ TrlTechRecordTemplate, - /* 4 */ HgvAndTrlTypeApprovalTemplate, - /* 5 */ ApplicantDetails, - /* 6 */ DocumentsTemplate, - /* 7 */ LettersTemplate, - /* 8 */ HgvAndTrlBodyTemplate, - /* 9 */ TrlWeight, - /* 10 */ tyresTemplateTrl, - /* 11 */ TrlBrakesTemplate, - /* 12 */ TrlPurchasers, - /* 13 */ TrlDimensionsTemplate, - /* 14 */ PlatesTemplate, - /* 15 */ TrlAuthIntoServiceTemplate, - /* 16 */ ManufacturerTemplate, - /* 17 */ AdrTemplate, - /* 18 */ AdrCertificateTemplate, - ], - ], - [ - VehicleTypes.SMALL_TRL, - [TechRecordReasonForCreationSection, /* 2 */ SmallTrailerTechRecord, /* 3 */ ApplicantDetails, /* 4 */ NotesTemplate, /* 5 */ Audit], - ], - [ - VehicleTypes.LGV, - [ - /* 1 */TechRecordReasonForCreationSection, - /* 2 */ LgvTechRecord, - /* 3 */ ApplicantDetails, - /* 4 */ NotesTemplate, - /* 5 */ Audit, - /* 6 */ AdrTemplate, - /* 7 */ AdrCertificateTemplate, - ], - ], - [ - VehicleTypes.CAR, - [TechRecordReasonForCreationSection, /* 2 */ CarTechRecord, /* 3 */ ApplicantDetails, /* 4 */ NotesTemplate, /* 5 */ Audit], - ], - [ - VehicleTypes.MOTORCYCLE, - [TechRecordReasonForCreationSection, /* 2 */ MotorcycleTechRecord, /* 3 */ ApplicantDetails, /* 4 */ NotesTemplate, /* 5 */ Audit], - ], + [ + VehicleTypes.PSV, + [ + /* 1 */ TechRecordReasonForCreationSection, + /* 2 */ PsvNotes, + /* 3 */ PsvTechRecord, + /* 4 */ PsvTypeApprovalTemplate, + /* 5 */ PsvBrakesTemplate, + /* 6 */ PsvDdaTemplate, + /* 7 */ DocumentsTemplate, + /* 8 */ PsvBodyTemplate, + /* 9 */ PsvWeightsTemplate, + /* 10 */ PsvTyresTemplate, + /* 11 */ PsvDimensionsTemplate, + ], + ], + [ + VehicleTypes.HGV, + [ + /* 1 */ TechRecordReasonForCreationSection, + /* 2 */ NotesTemplate, + /* 3 */ HgvTechRecord, + /* 4 */ HgvAndTrlTypeApprovalTemplate, + /* 5 */ ApplicantDetails, + /* 6 */ DocumentsTemplate, + /* 7 */ HgvAndTrlBodyTemplate, + /* 8 */ HgvWeight, + /* 9 */ tyresTemplateHgv, + /* 10 */ HgvDimensionsTemplate, + /* 11 */ PlatesTemplate, + /* 12 */ AdrTemplate, + /* 13 */ AdrCertificateTemplate, + ], + ], + [ + VehicleTypes.TRL, + [ + /* 1 */ TechRecordReasonForCreationSection, + /* 2 */ NotesTemplate, + /* 3 */ TrlTechRecordTemplate, + /* 4 */ HgvAndTrlTypeApprovalTemplate, + /* 5 */ ApplicantDetails, + /* 6 */ DocumentsTemplate, + /* 7 */ LettersTemplate, + /* 8 */ HgvAndTrlBodyTemplate, + /* 9 */ TrlWeight, + /* 10 */ tyresTemplateTrl, + /* 11 */ TrlBrakesTemplate, + /* 12 */ TrlPurchasers, + /* 13 */ TrlDimensionsTemplate, + /* 14 */ PlatesTemplate, + /* 15 */ TrlAuthIntoServiceTemplate, + /* 16 */ ManufacturerTemplate, + /* 17 */ AdrTemplate, + /* 18 */ AdrCertificateTemplate, + ], + ], + [ + VehicleTypes.SMALL_TRL, + [ + TechRecordReasonForCreationSection, + /* 2 */ SmallTrailerTechRecord, + /* 3 */ ApplicantDetails, + /* 4 */ NotesTemplate, + /* 5 */ Audit, + ], + ], + [ + VehicleTypes.LGV, + [ + /* 1 */ TechRecordReasonForCreationSection, + /* 2 */ LgvTechRecord, + /* 3 */ ApplicantDetails, + /* 4 */ NotesTemplate, + /* 5 */ Audit, + /* 6 */ AdrTemplate, + /* 7 */ AdrCertificateTemplate, + ], + ], + [ + VehicleTypes.CAR, + [ + TechRecordReasonForCreationSection, + /* 2 */ CarTechRecord, + /* 3 */ ApplicantDetails, + /* 4 */ NotesTemplate, + /* 5 */ Audit, + ], + ], + [ + VehicleTypes.MOTORCYCLE, + [ + TechRecordReasonForCreationSection, + /* 2 */ MotorcycleTechRecord, + /* 3 */ ApplicantDetails, + /* 4 */ NotesTemplate, + /* 5 */ Audit, + ], + ], ]); diff --git a/src/app/forms/validators/adr/adr.validators.spec.ts b/src/app/forms/validators/adr/adr.validators.spec.ts index fff37cd89d..f1831beda7 100644 --- a/src/app/forms/validators/adr/adr.validators.spec.ts +++ b/src/app/forms/validators/adr/adr.validators.spec.ts @@ -1,155 +1,159 @@ -import { - CustomFormControl, CustomFormGroup, - FormNodeTypes, -} from '@forms/services/dynamic-form.types'; +import { CustomFormControl, CustomFormGroup, FormNodeTypes } from '@forms/services/dynamic-form.types'; import { AdrValidators } from './adr.validators'; describe('ADR Validators', () => { - let form: CustomFormGroup; - - beforeEach(() => { - form = new CustomFormGroup({ type: FormNodeTypes.GROUP, name: 'adrForm' }, { - techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: new CustomFormControl({ - name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo', - type: FormNodeTypes.CONTROL, - }), - techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo: new CustomFormControl({ - name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo', - type: FormNodeTypes.CONTROL, - }), - }); - }); - - describe('validateProductListRefNo', () => { - it('should return NULL if the control is hidden', () => { - const control = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo') as CustomFormControl; - control.meta.hide = true; - - expect(AdrValidators.validateProductListRefNo(control)).toBeNull(); - }); - - it('should return an error message if the product list reference number and first UN number is empty', () => { - const a = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo') as CustomFormControl; - a.meta.hide = false; - a.patchValue(''); // make so product list reference number is empty - - const b = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo') as CustomFormControl; - b.meta.hide = false; - b.patchValue(['']); // make so first UN number is empty - - expect(AdrValidators.validateProductListRefNo(a)).toStrictEqual({ - custom: { - message: 'Reference number or UN number 1 is required when selecting Product List', - }, - }); - }); - - it('should return NULL if the product list reference number is populated', () => { - const a = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo') as CustomFormControl; - a.meta.hide = false; - a.patchValue('reference no.'); // make so product list reference number is populated - - const b = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo') as CustomFormControl; - b.meta.hide = false; - b.patchValue(['']); // make so first UN number is empty - - expect(AdrValidators.validateProductListRefNo(a)).toBeNull(); - }); - - it('should return NULL if the first UN number is populated', () => { - const a = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo') as CustomFormControl; - a.meta.hide = false; - a.patchValue(''); // make so product list reference number is empty - - const b = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo') as CustomFormControl; - b.meta.hide = false; - b.patchValue(['something']); // make so first UN number is empty - - expect(AdrValidators.validateProductListRefNo(a)).toBeNull(); - }); - }); - - describe('validProductListUNNumbers', () => { - it('should return NULL if the control is hidden', () => { - const control = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo') as CustomFormControl; - control.meta.hide = true; - - expect(AdrValidators.validateProductListUNNumbers(control)).toBeNull(); - }); - - it('should return an error message if the product list reference number and first UN number is empty', () => { - const a = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo') as CustomFormControl; - a.meta.hide = false; - a.patchValue(''); // make so product list reference number is empty - - const b = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo') as CustomFormControl; - b.meta.hide = false; - b.patchValue(['']); // make so first UN number is empty - - expect(AdrValidators.validateProductListUNNumbers(b)).toStrictEqual({ - custom: { - anchorLink: 'UN_number_1', - message: 'Reference number or UN number 1 is required when selecting Product List', - }, - }); - }); - - it('should return an error message if the last UN number is empty', () => { - const a = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo') as CustomFormControl; - a.meta.hide = false; - a.patchValue(''); // make so product list reference number is empty - - const b = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo') as CustomFormControl; - b.meta.hide = false; - b.patchValue(['first un', '']); // make so last UN number is empty - - expect(AdrValidators.validateProductListUNNumbers(b)).toStrictEqual({ - custom: { - anchorLink: 'UN_number_2', - message: 'UN number 2 is required or remove UN number 2', - }, - }); - }); - - it('should return an error message for any UN number which exceeds 1500 characters', () => { - const longString = new Array(1501).fill('a').join(); - - const a = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo') as CustomFormControl; - a.meta.hide = false; - a.patchValue(''); // make so product list reference number is empty - - const b = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo') as CustomFormControl; - b.meta.hide = false; - b.patchValue(['first un', longString, longString, longString]); // make so last UN number is empty - - expect(AdrValidators.validateProductListUNNumbers(b)).toStrictEqual({ - multiple: [ - { - anchorLink: 'UN_number_2', - error: 'UN number 2 must be less than or equal to 1500 characters', - }, - { - anchorLink: 'UN_number_3', - error: 'UN number 3 must be less than or equal to 1500 characters', - }, - { - anchorLink: 'UN_number_4', - error: 'UN number 4 must be less than or equal to 1500 characters', - }, - ], - }); - }); - - it('should return NULL if ALL UN numbers are populated, but less than 1500 characters in length', () => { - const a = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo') as CustomFormControl; - a.meta.hide = false; - a.patchValue(''); // make so product list reference number is empty - - const b = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo') as CustomFormControl; - b.meta.hide = false; - b.patchValue(['small string', 'small string', 'small string']); // make so last UN number is empty - - expect(AdrValidators.validateProductListUNNumbers(b)).toBeNull(); - }); - }); + let form: CustomFormGroup; + + beforeEach(() => { + form = new CustomFormGroup( + { type: FormNodeTypes.GROUP, name: 'adrForm' }, + { + techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: new CustomFormControl({ + name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo', + type: FormNodeTypes.CONTROL, + }), + techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo: new CustomFormControl({ + name: 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo', + type: FormNodeTypes.CONTROL, + }), + } + ); + }); + + describe('validateProductListRefNo', () => { + it('should return NULL if the control is hidden', () => { + const control = form.get( + 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo' + ) as CustomFormControl; + control.meta.hide = true; + + expect(AdrValidators.validateProductListRefNo(control)).toBeNull(); + }); + + it('should return an error message if the product list reference number and first UN number is empty', () => { + const a = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo') as CustomFormControl; + a.meta.hide = false; + a.patchValue(''); // make so product list reference number is empty + + const b = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo') as CustomFormControl; + b.meta.hide = false; + b.patchValue(['']); // make so first UN number is empty + + expect(AdrValidators.validateProductListRefNo(a)).toStrictEqual({ + custom: { + message: 'Reference number or UN number 1 is required when selecting Product List', + }, + }); + }); + + it('should return NULL if the product list reference number is populated', () => { + const a = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo') as CustomFormControl; + a.meta.hide = false; + a.patchValue('reference no.'); // make so product list reference number is populated + + const b = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo') as CustomFormControl; + b.meta.hide = false; + b.patchValue(['']); // make so first UN number is empty + + expect(AdrValidators.validateProductListRefNo(a)).toBeNull(); + }); + + it('should return NULL if the first UN number is populated', () => { + const a = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo') as CustomFormControl; + a.meta.hide = false; + a.patchValue(''); // make so product list reference number is empty + + const b = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo') as CustomFormControl; + b.meta.hide = false; + b.patchValue(['something']); // make so first UN number is empty + + expect(AdrValidators.validateProductListRefNo(a)).toBeNull(); + }); + }); + + describe('validProductListUNNumbers', () => { + it('should return NULL if the control is hidden', () => { + const control = form.get( + 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo' + ) as CustomFormControl; + control.meta.hide = true; + + expect(AdrValidators.validateProductListUNNumbers(control)).toBeNull(); + }); + + it('should return an error message if the product list reference number and first UN number is empty', () => { + const a = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo') as CustomFormControl; + a.meta.hide = false; + a.patchValue(''); // make so product list reference number is empty + + const b = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo') as CustomFormControl; + b.meta.hide = false; + b.patchValue(['']); // make so first UN number is empty + + expect(AdrValidators.validateProductListUNNumbers(b)).toStrictEqual({ + custom: { + anchorLink: 'UN_number_1', + message: 'Reference number or UN number 1 is required when selecting Product List', + }, + }); + }); + + it('should return an error message if the last UN number is empty', () => { + const a = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo') as CustomFormControl; + a.meta.hide = false; + a.patchValue(''); // make so product list reference number is empty + + const b = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo') as CustomFormControl; + b.meta.hide = false; + b.patchValue(['first un', '']); // make so last UN number is empty + + expect(AdrValidators.validateProductListUNNumbers(b)).toStrictEqual({ + custom: { + anchorLink: 'UN_number_2', + message: 'UN number 2 is required or remove UN number 2', + }, + }); + }); + + it('should return an error message for any UN number which exceeds 1500 characters', () => { + const longString = new Array(1501).fill('a').join(); + + const a = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo') as CustomFormControl; + a.meta.hide = false; + a.patchValue(''); // make so product list reference number is empty + + const b = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo') as CustomFormControl; + b.meta.hide = false; + b.patchValue(['first un', longString, longString, longString]); // make so last UN number is empty + + expect(AdrValidators.validateProductListUNNumbers(b)).toStrictEqual({ + multiple: [ + { + anchorLink: 'UN_number_2', + error: 'UN number 2 must be less than or equal to 1500 characters', + }, + { + anchorLink: 'UN_number_3', + error: 'UN number 3 must be less than or equal to 1500 characters', + }, + { + anchorLink: 'UN_number_4', + error: 'UN number 4 must be less than or equal to 1500 characters', + }, + ], + }); + }); + + it('should return NULL if ALL UN numbers are populated, but less than 1500 characters in length', () => { + const a = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo') as CustomFormControl; + a.meta.hide = false; + a.patchValue(''); // make so product list reference number is empty + + const b = form.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo') as CustomFormControl; + b.meta.hide = false; + b.patchValue(['small string', 'small string', 'small string']); // make so last UN number is empty + + expect(AdrValidators.validateProductListUNNumbers(b)).toBeNull(); + }); + }); }); diff --git a/src/app/forms/validators/adr/adr.validators.ts b/src/app/forms/validators/adr/adr.validators.ts index 910355cada..c6440d1db4 100644 --- a/src/app/forms/validators/adr/adr.validators.ts +++ b/src/app/forms/validators/adr/adr.validators.ts @@ -2,65 +2,69 @@ import { ValidationErrors } from '@angular/forms'; import { CustomFormControl } from '@forms/services/dynamic-form.types'; export class AdrValidators { - static validateProductListRefNo = (control: CustomFormControl): ValidationErrors | null => { - if (control.meta?.hide) { - return null; - } + static validateProductListRefNo = (control: CustomFormControl): ValidationErrors | null => { + if (control.meta?.hide) { + return null; + } - const unNumber1 = control.parent?.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo'); + const unNumber1 = control.parent?.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo'); - // If either productListRefNo is empty, or the first unNumber, mark as invalid - if ((!control.value && !unNumber1?.value) || (!control.value && !unNumber1?.value?.at(0))) { - return { custom: { message: 'Reference number or UN number 1 is required when selecting Product List' } }; - } + // If either productListRefNo is empty, or the first unNumber, mark as invalid + if ((!control.value && !unNumber1?.value) || (!control.value && !unNumber1?.value?.at(0))) { + return { custom: { message: 'Reference number or UN number 1 is required when selecting Product List' } }; + } - return null; - }; + return null; + }; - static validateProductListUNNumbers = (control: CustomFormControl): ValidationErrors | null => { - if (control.meta?.hide) { - return null; - } + static validateProductListUNNumbers = (control: CustomFormControl): ValidationErrors | null => { + if (control.meta?.hide) { + return null; + } - const productListRefNo = control.parent?.get('techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo'); - const firstUnNumber = control.value?.at(0); - const lastUnNumberIndex = (control.value?.length ?? 0) - 1; - const lastUnNumber = control.value?.at(lastUnNumberIndex); + const productListRefNo = control.parent?.get( + 'techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo' + ); + const firstUnNumber = control.value?.at(0); + const lastUnNumberIndex = (control.value?.length ?? 0) - 1; + const lastUnNumber = control.value?.at(lastUnNumberIndex); - // If either productListRefNo is empty, or the first unNumber, mark as invalid - if ((!productListRefNo?.value && !control?.value) || (!productListRefNo?.value && !firstUnNumber)) { - return { - custom: { - message: 'Reference number or UN number 1 is required when selecting Product List', - anchorLink: 'UN_number_1', - }, - }; - } + // If either productListRefNo is empty, or the first unNumber, mark as invalid + if ((!productListRefNo?.value && !control?.value) || (!productListRefNo?.value && !firstUnNumber)) { + return { + custom: { + message: 'Reference number or UN number 1 is required when selecting Product List', + anchorLink: 'UN_number_1', + }, + }; + } - // If there are more than 1 UN numbers, and the last UN number is empty, mark as invalid - if (control.value?.length > 1 && !lastUnNumber) { - return { - custom: { - message: `UN number ${lastUnNumberIndex + 1} is required or remove UN number ${lastUnNumberIndex + 1}`, - anchorLink: `UN_number_${lastUnNumberIndex + 1}`, - }, - }; - } + // If there are more than 1 UN numbers, and the last UN number is empty, mark as invalid + if (control.value?.length > 1 && !lastUnNumber) { + return { + custom: { + message: `UN number ${lastUnNumberIndex + 1} is required or remove UN number ${lastUnNumberIndex + 1}`, + anchorLink: `UN_number_${lastUnNumberIndex + 1}`, + }, + }; + } - // If any of the control indices have length greater than 1500 characters, show an error message for each - if (control.value && control.value.some((unNumber: string) => unNumber.length > 1500)) { - return { - multiple: control.value.map((unNumber: string, index: number) => - unNumber.length > 1500 - ? { - error: `UN number ${index + 1} must be less than or equal to 1500 characters`, - anchorLink: `UN_number_${index + 1}`, - } - : null) - .filter(Boolean), - }; - } + // If any of the control indices have length greater than 1500 characters, show an error message for each + if (control.value && control.value.some((unNumber: string) => unNumber.length > 1500)) { + return { + multiple: control.value + .map((unNumber: string, index: number) => + unNumber.length > 1500 + ? { + error: `UN number ${index + 1} must be less than or equal to 1500 characters`, + anchorLink: `UN_number_${index + 1}`, + } + : null + ) + .filter(Boolean), + }; + } - return null; - }; + return null; + }; } diff --git a/src/app/forms/validators/custom-async-validators.spec.ts b/src/app/forms/validators/custom-async-validators.spec.ts index 6c4e919959..5208b7a640 100644 --- a/src/app/forms/validators/custom-async-validators.spec.ts +++ b/src/app/forms/validators/custom-async-validators.spec.ts @@ -16,803 +16,896 @@ import { Observable, firstValueFrom, lastValueFrom } from 'rxjs'; import { CustomAsyncValidators } from './custom-async-validators'; describe('resultDependantOnCustomDefects', () => { - let form: FormGroup; - let store: MockStore; + let form: FormGroup; + let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideMockStore({ initialState: initialAppState })], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore({ initialState: initialAppState })], + }); - store = TestBed.inject(MockStore); + store = TestBed.inject(MockStore); - form = new FormGroup({ - testResult: new CustomFormControl({ name: 'testResult', type: FormNodeTypes.CONTROL, children: [] }, null), - }); - }); + form = new FormGroup({ + testResult: new CustomFormControl({ name: 'testResult', type: FormNodeTypes.CONTROL, children: [] }, null), + }); + }); - it('should fail validation when value is "pass" and defects are present', async () => { - form.controls['testResult'].patchValue('pass'); + it('should fail validation when value is "pass" and defects are present', async () => { + form.controls['testResult'].patchValue('pass'); - const mockedTestResult = mockTestResult(); - mockedTestResult.testTypes[0].customDefects = [createMockCustomDefect()]; - store.overrideSelector(testResultInEdit, mockedTestResult); + const mockedTestResult = mockTestResult(); + mockedTestResult.testTypes[0].customDefects = [createMockCustomDefect()]; + store.overrideSelector(testResultInEdit, mockedTestResult); - const result = await firstValueFrom( - CustomAsyncValidators.resultDependantOnCustomDefects(store)(form.controls['testResult']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.resultDependantOnCustomDefects(store)( + form.controls['testResult'] + ) as Observable + ); - expect(result).toEqual({ invalidTestResult: { message: 'Cannot pass test when defects are present' } }); - }); + expect(result).toEqual({ invalidTestResult: { message: 'Cannot pass test when defects are present' } }); + }); - it('should fail validation when value is "fail" but no defects are present', async () => { - form.controls['testResult'].patchValue('fail'); + it('should fail validation when value is "fail" but no defects are present', async () => { + form.controls['testResult'].patchValue('fail'); - const testResult = mockTestResult(); - testResult.testTypes = []; + const testResult = mockTestResult(); + testResult.testTypes = []; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom( - CustomAsyncValidators.resultDependantOnCustomDefects(store)(form.controls['testResult']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.resultDependantOnCustomDefects(store)( + form.controls['testResult'] + ) as Observable + ); - expect(result).toEqual({ invalidTestResult: { message: 'Cannot fail test when no defects are present' } }); - }); + expect(result).toEqual({ invalidTestResult: { message: 'Cannot fail test when no defects are present' } }); + }); - it('should fail validation when value is "prs" but no defects are present', async () => { - form.controls['testResult'].patchValue('prs'); + it('should fail validation when value is "prs" but no defects are present', async () => { + form.controls['testResult'].patchValue('prs'); - const testResult = mockTestResult(); - testResult.testTypes = []; + const testResult = mockTestResult(); + testResult.testTypes = []; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom( - CustomAsyncValidators.resultDependantOnCustomDefects(store)(form.controls['testResult']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.resultDependantOnCustomDefects(store)( + form.controls['testResult'] + ) as Observable + ); - expect(result).toEqual({ invalidTestResult: { message: 'Cannot mark test as PRS when no defects are present' } }); - }); + expect(result).toEqual({ invalidTestResult: { message: 'Cannot mark test as PRS when no defects are present' } }); + }); - it('should pass validation when value is "abandoned"', async () => { - form.controls['testResult'].patchValue('abandoned'); + it('should pass validation when value is "abandoned"', async () => { + form.controls['testResult'].patchValue('abandoned'); - store.overrideSelector(testResultInEdit, mockTestResult()); + store.overrideSelector(testResultInEdit, mockTestResult()); - const result = await firstValueFrom( - CustomAsyncValidators.resultDependantOnCustomDefects(store)(form.controls['testResult']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.resultDependantOnCustomDefects(store)( + form.controls['testResult'] + ) as Observable + ); - expect(result).toBeNull(); - }); + expect(result).toBeNull(); + }); }); describe('passResultDependantOnCustomDefects', () => { - let form: FormGroup; - let store: MockStore; + let form: FormGroup; + let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideMockStore({ initialState: initialAppState })], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore({ initialState: initialAppState })], + }); - store = TestBed.inject(MockStore); + store = TestBed.inject(MockStore); - form = new FormGroup({ - testResult: new CustomFormControl({ name: 'testResult', type: FormNodeTypes.CONTROL, children: [] }, null), - }); - }); + form = new FormGroup({ + testResult: new CustomFormControl({ name: 'testResult', type: FormNodeTypes.CONTROL, children: [] }, null), + }); + }); - it('should fail validation when value is "pass" and defects are present', async () => { - form.controls['testResult'].patchValue('pass'); + it('should fail validation when value is "pass" and defects are present', async () => { + form.controls['testResult'].patchValue('pass'); - const mockedTestResult = mockTestResult(); - mockedTestResult.testTypes[0].customDefects = [createMockCustomDefect()]; - store.overrideSelector(testResultInEdit, mockedTestResult); + const mockedTestResult = mockTestResult(); + mockedTestResult.testTypes[0].customDefects = [createMockCustomDefect()]; + store.overrideSelector(testResultInEdit, mockedTestResult); - const result = await firstValueFrom( - CustomAsyncValidators.passResultDependantOnCustomDefects(store)(form.controls['testResult']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.passResultDependantOnCustomDefects(store)( + form.controls['testResult'] + ) as Observable + ); - expect(result).toEqual({ invalidTestResult: { message: 'Cannot pass test when defects are present' } }); - }); + expect(result).toEqual({ invalidTestResult: { message: 'Cannot pass test when defects are present' } }); + }); - it('should pass validation when value is "fail" but no defects are present', async () => { - form.controls['testResult'].patchValue('fail'); + it('should pass validation when value is "fail" but no defects are present', async () => { + form.controls['testResult'].patchValue('fail'); - const testResult = mockTestResult(); - testResult.testTypes = []; + const testResult = mockTestResult(); + testResult.testTypes = []; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom( - CustomAsyncValidators.passResultDependantOnCustomDefects(store)(form.controls['testResult']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.passResultDependantOnCustomDefects(store)( + form.controls['testResult'] + ) as Observable + ); - expect(result).toBeNull(); - }); + expect(result).toBeNull(); + }); - it('should pass validation when value is "prs" but no defects are present', async () => { - form.controls['testResult'].patchValue('prs'); + it('should pass validation when value is "prs" but no defects are present', async () => { + form.controls['testResult'].patchValue('prs'); - const testResult = mockTestResult(); - testResult.testTypes = []; + const testResult = mockTestResult(); + testResult.testTypes = []; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom( - CustomAsyncValidators.passResultDependantOnCustomDefects(store)(form.controls['testResult']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.passResultDependantOnCustomDefects(store)( + form.controls['testResult'] + ) as Observable + ); - expect(result).toBeNull(); - }); + expect(result).toBeNull(); + }); - it('should pass validation when value is "abandoned"', async () => { - form.controls['testResult'].patchValue('abandoned'); + it('should pass validation when value is "abandoned"', async () => { + form.controls['testResult'].patchValue('abandoned'); - store.overrideSelector(testResultInEdit, mockTestResult()); + store.overrideSelector(testResultInEdit, mockTestResult()); - const result = await firstValueFrom( - CustomAsyncValidators.passResultDependantOnCustomDefects(store)(form.controls['testResult']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.passResultDependantOnCustomDefects(store)( + form.controls['testResult'] + ) as Observable + ); - expect(result).toBeNull(); - }); + expect(result).toBeNull(); + }); }); describe('updateTestStationDetails', () => { - let form: FormGroup; - let store: MockStore; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [ - provideMockStore({ - initialState: { - ...initialAppState, - testStations: { - ...initialTestStationsState, - ids: ['1'], - entities: { 1: { testStationName: 'foo', testStationPNumber: '1234', testStationType: 'bar' } }, - }, - }, - }), - ], - }); - - store = TestBed.inject(MockStore); - - form = new FormGroup({ - testStationName: new CustomFormControl({ name: 'testStationName', type: FormNodeTypes.CONTROL, children: [] }, null), - testStationType: new CustomFormControl({ name: 'testStationType', type: FormNodeTypes.CONTROL, children: [] }, null), - testStationPNumber: new CustomFormControl({ name: 'testStationPNumber', type: FormNodeTypes.CONTROL, children: [] }, null), - }); - }); - it('should update the test stations details', async () => { - form.controls['testStationPNumber'].patchValue('1234'); - expect(form.controls['testStationPNumber']).toBeTruthy(); - await firstValueFrom(CustomAsyncValidators.updateTestStationDetails(store)(form.controls['testStationPNumber']) as Observable); - expect(form.controls['testStationType'].value).toBe('bar'); - expect(form.controls['testStationName'].value).toBe('foo'); - }); + let form: FormGroup; + let store: MockStore; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + provideMockStore({ + initialState: { + ...initialAppState, + testStations: { + ...initialTestStationsState, + ids: ['1'], + entities: { 1: { testStationName: 'foo', testStationPNumber: '1234', testStationType: 'bar' } }, + }, + }, + }), + ], + }); + + store = TestBed.inject(MockStore); + + form = new FormGroup({ + testStationName: new CustomFormControl( + { name: 'testStationName', type: FormNodeTypes.CONTROL, children: [] }, + null + ), + testStationType: new CustomFormControl( + { name: 'testStationType', type: FormNodeTypes.CONTROL, children: [] }, + null + ), + testStationPNumber: new CustomFormControl( + { name: 'testStationPNumber', type: FormNodeTypes.CONTROL, children: [] }, + null + ), + }); + }); + it('should update the test stations details', async () => { + form.controls['testStationPNumber'].patchValue('1234'); + expect(form.controls['testStationPNumber']).toBeTruthy(); + await firstValueFrom( + CustomAsyncValidators.updateTestStationDetails(store)(form.controls['testStationPNumber']) as Observable + ); + expect(form.controls['testStationType'].value).toBe('bar'); + expect(form.controls['testStationName'].value).toBe('foo'); + }); }); describe('requiredIfNotFail', () => { - let form: FormGroup; - let store: MockStore; + let form: FormGroup; + let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideMockStore({ initialState: initialAppState })], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore({ initialState: initialAppState })], + }); - store = TestBed.inject(MockStore); + store = TestBed.inject(MockStore); - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), - }); - }); + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), + }); + }); - it('should be required when value is "pass"', async () => { - form.controls['foo'].patchValue(''); + it('should be required when value is "pass"', async () => { + form.controls['foo'].patchValue(''); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom(CustomAsyncValidators.requiredIfNotFail(store)(form.controls['foo']) as Observable); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotFail(store)(form.controls['foo']) as Observable + ); - expect(result).toEqual({ requiredIfNotfail: true }); - }); + expect(result).toEqual({ requiredIfNotfail: true }); + }); - it('should pass validation if field is not empty when value is "pass"', async () => { - form.controls['foo'].patchValue('test'); + it('should pass validation if field is not empty when value is "pass"', async () => { + form.controls['foo'].patchValue('test'); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom(CustomAsyncValidators.requiredIfNotFail(store)(form.controls['foo']) as Observable); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotFail(store)(form.controls['foo']) as Observable + ); - expect(result).toBeNull(); - }); + expect(result).toBeNull(); + }); - it('should not be required when value is "fail"', async () => { - form.controls['foo'].patchValue(''); + it('should not be required when value is "fail"', async () => { + form.controls['foo'].patchValue(''); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.fail }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.fail }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom(CustomAsyncValidators.requiredIfNotFail(store)(form.controls['foo']) as Observable); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotFail(store)(form.controls['foo']) as Observable + ); - expect(result).toBeNull(); - }); + expect(result).toBeNull(); + }); - it('should be required when value is "prs"', async () => { - form.controls['foo'].patchValue(''); + it('should be required when value is "prs"', async () => { + form.controls['foo'].patchValue(''); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.prs }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.prs }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom(CustomAsyncValidators.requiredIfNotFail(store)(form.controls['foo']) as Observable); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotFail(store)(form.controls['foo']) as Observable + ); - expect(result).toEqual({ requiredIfNotfail: true }); - }); + expect(result).toEqual({ requiredIfNotfail: true }); + }); - it('should be required when value is "abandoned"', async () => { - form.controls['foo'].patchValue(''); + it('should be required when value is "abandoned"', async () => { + form.controls['foo'].patchValue(''); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.abandoned }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.abandoned }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom(CustomAsyncValidators.requiredIfNotFail(store)(form.controls['foo']) as Observable); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotFail(store)(form.controls['foo']) as Observable + ); - expect(result).toEqual({ requiredIfNotfail: true }); - }); + expect(result).toEqual({ requiredIfNotfail: true }); + }); }); describe('requiredIfNotAbandoned', () => { - let form: FormGroup; - let store: MockStore; + let form: FormGroup; + let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideMockStore({ initialState: initialAppState })], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore({ initialState: initialAppState })], + }); - store = TestBed.inject(MockStore); + store = TestBed.inject(MockStore); - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), - }); - }); + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), + }); + }); - it('should be required when value is "pass"', async () => { - form.controls['foo'].patchValue(''); + it('should be required when value is "pass"', async () => { + form.controls['foo'].patchValue(''); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom( - CustomAsyncValidators.requiredIfNotAbandoned(store)(form.controls['foo']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotAbandoned(store)(form.controls['foo']) as Observable + ); - expect(result).toEqual({ requiredIfNotabandoned: true }); - }); + expect(result).toEqual({ requiredIfNotabandoned: true }); + }); - it('should pass validation if field is not empty when value is "pass"', async () => { - form.controls['foo'].patchValue('test'); + it('should pass validation if field is not empty when value is "pass"', async () => { + form.controls['foo'].patchValue('test'); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom( - CustomAsyncValidators.requiredIfNotAbandoned(store)(form.controls['foo']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotAbandoned(store)(form.controls['foo']) as Observable + ); - expect(result).toBeNull(); - }); + expect(result).toBeNull(); + }); - it('should be required when value is "fail"', async () => { - form.controls['foo'].patchValue(''); + it('should be required when value is "fail"', async () => { + form.controls['foo'].patchValue(''); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.fail }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.fail }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom( - CustomAsyncValidators.requiredIfNotAbandoned(store)(form.controls['foo']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotAbandoned(store)(form.controls['foo']) as Observable + ); - expect(result).toEqual({ requiredIfNotabandoned: true }); - }); + expect(result).toEqual({ requiredIfNotabandoned: true }); + }); - it('should be required when value is "prs"', async () => { - form.controls['foo'].patchValue(''); + it('should be required when value is "prs"', async () => { + form.controls['foo'].patchValue(''); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.prs }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.prs }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom( - CustomAsyncValidators.requiredIfNotAbandoned(store)(form.controls['foo']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotAbandoned(store)(form.controls['foo']) as Observable + ); - expect(result).toEqual({ requiredIfNotabandoned: true }); - }); + expect(result).toEqual({ requiredIfNotabandoned: true }); + }); - it('should not be required when value is "abandoned"', async () => { - form.controls['foo'].patchValue(''); + it('should not be required when value is "abandoned"', async () => { + form.controls['foo'].patchValue(''); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.abandoned }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.abandoned }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom( - CustomAsyncValidators.requiredIfNotAbandoned(store)(form.controls['foo']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotAbandoned(store)(form.controls['foo']) as Observable + ); - expect(result).toBeNull(); - }); + expect(result).toBeNull(); + }); }); describe('requiredIfNotResult', () => { - let form: FormGroup; - let store: MockStore; + let form: FormGroup; + let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideMockStore({ initialState: initialAppState })], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore({ initialState: initialAppState })], + }); - store = TestBed.inject(MockStore); + store = TestBed.inject(MockStore); - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), - }); - }); + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), + }); + }); - it('should be required when result is "pass" and validator specifies requiredIfNotResult "fail"', async () => { - form.controls['foo'].patchValue(''); + it('should be required when result is "pass" and validator specifies requiredIfNotResult "fail"', async () => { + form.controls['foo'].patchValue(''); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom( - CustomAsyncValidators.requiredIfNotResult(store, resultOfTestEnum.fail)(form.controls['foo']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotResult( + store, + resultOfTestEnum.fail + )(form.controls['foo']) as Observable + ); - expect(result).toEqual({ requiredIfNotfail: true }); - }); + expect(result).toEqual({ requiredIfNotfail: true }); + }); - it('should be required when result is "pass" and validator specifies requiredIfNotResult "fail" or "abandoned"', async () => { - form.controls['foo'].patchValue(''); + it('should be required when result is "pass" and validator specifies requiredIfNotResult "fail" or "abandoned"', async () => { + form.controls['foo'].patchValue(''); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom( - CustomAsyncValidators.requiredIfNotResult(store, [resultOfTestEnum.fail, resultOfTestEnum.abandoned])( - form.controls['foo'], - ) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotResult(store, [resultOfTestEnum.fail, resultOfTestEnum.abandoned])( + form.controls['foo'] + ) as Observable + ); - expect(result).toEqual({ requiredIfNotResult: true }); - }); + expect(result).toEqual({ requiredIfNotResult: true }); + }); - it('should pass validation if field is not empty when value is "pass" and validator specifies requiredIfNotResult "fail"', async () => { - form.controls['foo'].patchValue('test'); + it('should pass validation if field is not empty when value is "pass" and validator specifies requiredIfNotResult "fail"', async () => { + form.controls['foo'].patchValue('test'); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom( - CustomAsyncValidators.requiredIfNotResult(store, resultOfTestEnum.fail)(form.controls['foo']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotResult( + store, + resultOfTestEnum.fail + )(form.controls['foo']) as Observable + ); - expect(result).toBeNull(); - }); + expect(result).toBeNull(); + }); - it('should not be required when value is "fail" and validator specifies requiredIfNotResult "fail"', async () => { - form.controls['foo'].patchValue(''); + it('should not be required when value is "fail" and validator specifies requiredIfNotResult "fail"', async () => { + form.controls['foo'].patchValue(''); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.fail }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.fail }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom( - CustomAsyncValidators.requiredIfNotResult(store, resultOfTestEnum.fail)(form.controls['foo']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotResult( + store, + resultOfTestEnum.fail + )(form.controls['foo']) as Observable + ); - expect(result).toBeNull(); - }); + expect(result).toBeNull(); + }); - it('should be required when value is "prs" and validator specifies requiredIfNotResult "fail"', async () => { - form.controls['foo'].patchValue(''); + it('should be required when value is "prs" and validator specifies requiredIfNotResult "fail"', async () => { + form.controls['foo'].patchValue(''); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.prs }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.prs }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom( - CustomAsyncValidators.requiredIfNotResult(store, resultOfTestEnum.fail)(form.controls['foo']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotResult( + store, + resultOfTestEnum.fail + )(form.controls['foo']) as Observable + ); - expect(result).toEqual({ requiredIfNotfail: true }); - }); + expect(result).toEqual({ requiredIfNotfail: true }); + }); - it('should be required when value is "abandoned" and validator specifies requiredIfNotResult "fail"', async () => { - form.controls['foo'].patchValue(''); + it('should be required when value is "abandoned" and validator specifies requiredIfNotResult "fail"', async () => { + form.controls['foo'].patchValue(''); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.abandoned }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.abandoned }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom( - CustomAsyncValidators.requiredIfNotResult(store, resultOfTestEnum.fail)(form.controls['foo']) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotResult( + store, + resultOfTestEnum.fail + )(form.controls['foo']) as Observable + ); - expect(result).toEqual({ requiredIfNotfail: true }); - }); + expect(result).toEqual({ requiredIfNotfail: true }); + }); - it('should be required when value is "abandoned" and validator specifies requiredIfNotResult "fail" or "pass"', async () => { - form.controls['foo'].patchValue(''); + it('should be required when value is "abandoned" and validator specifies requiredIfNotResult "fail" or "pass"', async () => { + form.controls['foo'].patchValue(''); - const testResult = { testTypes: [{ testResult: resultOfTestEnum.abandoned }] } as TestResultModel; + const testResult = { testTypes: [{ testResult: resultOfTestEnum.abandoned }] } as TestResultModel; - store.overrideSelector(testResultInEdit, testResult); + store.overrideSelector(testResultInEdit, testResult); - const result = await firstValueFrom( - CustomAsyncValidators.requiredIfNotResult(store, [resultOfTestEnum.fail, resultOfTestEnum.pass])( - form.controls['foo'], - ) as Observable, - ); + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotResult(store, [resultOfTestEnum.fail, resultOfTestEnum.pass])( + form.controls['foo'] + ) as Observable + ); - expect(result).toEqual({ requiredIfNotResult: true }); - }); + expect(result).toEqual({ requiredIfNotResult: true }); + }); }); describe('requiredIfNotResultAndSiblingEquals', () => { - let form: FormGroup; - let store: MockStore; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideMockStore({ initialState: initialAppState })], - }); - - store = TestBed.inject(MockStore); - - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), - bar: new CustomFormControl({ name: 'bar', type: FormNodeTypes.CONTROL, children: [] }, null), - }); - }); - - it('should be required when result is "pass" and "bar is "x" and ' - + 'validator specifies requiredIfNotResultAndSiblingEquals "fail" when sibling "bar" is "x"', async () => { - form.controls['foo'].patchValue(''); - form.controls['bar'].patchValue('x'); - - const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; - - store.overrideSelector(testResultInEdit, testResult); - - const result = await firstValueFrom( - CustomAsyncValidators.requiredIfNotResultAndSiblingEquals( - store, - resultOfTestEnum.fail, - 'bar', - 'x', - )(form.controls['foo']) as Observable, - ); - - expect(result).toEqual({ requiredIfNotResultAndSiblingEquals: true }); - }); - - it('should pass validation when result is "fail" and "bar is "x" and ' - + 'validator specifies requiredIfNotResultAndSiblingEquals "fail" when sibling "bar" is "x"', async () => { - form.controls['foo'].patchValue(''); - form.controls['bar'].patchValue('x'); - - const testResult = { testTypes: [{ testResult: resultOfTestEnum.fail }] } as TestResultModel; - - store.overrideSelector(testResultInEdit, testResult); - - const result = await firstValueFrom( - CustomAsyncValidators.requiredIfNotResultAndSiblingEquals( - store, - resultOfTestEnum.fail, - 'bar', - 'x', - )(form.controls['foo']) as Observable, - ); - - expect(result).toBeNull(); - }); - - it('should pass validation when result is "pass" and "bar is "y" and ' - + 'validator specifies requiredIfNotResultAndSiblingEquals "fail" when sibling "bar" is "x"', async () => { - form.controls['foo'].patchValue(''); - form.controls['bar'].patchValue('y'); - - const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; - - store.overrideSelector(testResultInEdit, testResult); - - const result = await firstValueFrom( - CustomAsyncValidators.requiredIfNotResultAndSiblingEquals( - store, - resultOfTestEnum.fail, - 'bar', - 'x', - )(form.controls['foo']) as Observable, - ); - - expect(result).toBeNull(); - }); - - it('should be required when result is "pass" and "bar is "x" and ' - + 'validator specifies requiredIfNotResultAndSiblingEquals "fail"/"abandoned" when sibling "bar" is "x"', async () => { - form.controls['foo'].patchValue(''); - form.controls['bar'].patchValue('x'); - - const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; - - store.overrideSelector(testResultInEdit, testResult); - - const result = await firstValueFrom( - CustomAsyncValidators.requiredIfNotResultAndSiblingEquals( - store, - [resultOfTestEnum.fail, resultOfTestEnum.abandoned], - 'bar', - 'x', - )(form.controls['foo']) as Observable, - ); - - expect(result).toEqual({ requiredIfNotResultAndSiblingEquals: true }); - }); + let form: FormGroup; + let store: MockStore; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore({ initialState: initialAppState })], + }); + + store = TestBed.inject(MockStore); + + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), + bar: new CustomFormControl({ name: 'bar', type: FormNodeTypes.CONTROL, children: [] }, null), + }); + }); + + it( + 'should be required when result is "pass" and "bar is "x" and ' + + 'validator specifies requiredIfNotResultAndSiblingEquals "fail" when sibling "bar" is "x"', + async () => { + form.controls['foo'].patchValue(''); + form.controls['bar'].patchValue('x'); + + const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; + + store.overrideSelector(testResultInEdit, testResult); + + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotResultAndSiblingEquals( + store, + resultOfTestEnum.fail, + 'bar', + 'x' + )(form.controls['foo']) as Observable + ); + + expect(result).toEqual({ requiredIfNotResultAndSiblingEquals: true }); + } + ); + + it( + 'should pass validation when result is "fail" and "bar is "x" and ' + + 'validator specifies requiredIfNotResultAndSiblingEquals "fail" when sibling "bar" is "x"', + async () => { + form.controls['foo'].patchValue(''); + form.controls['bar'].patchValue('x'); + + const testResult = { testTypes: [{ testResult: resultOfTestEnum.fail }] } as TestResultModel; + + store.overrideSelector(testResultInEdit, testResult); + + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotResultAndSiblingEquals( + store, + resultOfTestEnum.fail, + 'bar', + 'x' + )(form.controls['foo']) as Observable + ); + + expect(result).toBeNull(); + } + ); + + it( + 'should pass validation when result is "pass" and "bar is "y" and ' + + 'validator specifies requiredIfNotResultAndSiblingEquals "fail" when sibling "bar" is "x"', + async () => { + form.controls['foo'].patchValue(''); + form.controls['bar'].patchValue('y'); + + const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; + + store.overrideSelector(testResultInEdit, testResult); + + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotResultAndSiblingEquals( + store, + resultOfTestEnum.fail, + 'bar', + 'x' + )(form.controls['foo']) as Observable + ); + + expect(result).toBeNull(); + } + ); + + it( + 'should be required when result is "pass" and "bar is "x" and ' + + 'validator specifies requiredIfNotResultAndSiblingEquals "fail"/"abandoned" when sibling "bar" is "x"', + async () => { + form.controls['foo'].patchValue(''); + form.controls['bar'].patchValue('x'); + + const testResult = { testTypes: [{ testResult: resultOfTestEnum.pass }] } as TestResultModel; + + store.overrideSelector(testResultInEdit, testResult); + + const result = await firstValueFrom( + CustomAsyncValidators.requiredIfNotResultAndSiblingEquals( + store, + [resultOfTestEnum.fail, resultOfTestEnum.abandoned], + 'bar', + 'x' + )(form.controls['foo']) as Observable + ); + + expect(result).toEqual({ requiredIfNotResultAndSiblingEquals: true }); + } + ); }); describe('hide if equals with condition', () => { - let form: FormGroup; - let store: MockStore; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideMockStore({ initialState: initialAppState })], - }); - - store = TestBed.inject(MockStore); - - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), - bar: new CustomFormControl({ name: 'bar', type: FormNodeTypes.CONTROL, children: [] }, null), - }); - }); - - it('"bar" should be hidden when "foo" is "x" and testTypeId is "1" and ' - + 'validator specifies hideIfEqualsWithCondition for current field equals "x" with the condition that the ' - + '"testTypeId" field has a value in "1,2,3,4"', async () => { - form.controls['foo'].patchValue('x'); - - const testResult = { testTypes: [{ testTypeId: '1' }] } as TestResultModel; - - store.overrideSelector(testResultInEdit, testResult); - - await firstValueFrom( - CustomAsyncValidators.hideIfEqualsWithCondition(store, 'bar', 'x', { - field: 'testTypeId', - operator: operatorEnum.Equals, - value: ['1', '2', '3', '4'], - })(form.controls['foo']) as Observable, - ); - - expect((form.controls['bar'] as CustomFormControl).meta.hide).toBe(true); - }); - - it('"bar" should not be hidden when "foo" is "x" and testTypeId is "1" and ' - + 'validator specifies hideIfEqualsWithCondition for current field equals "y" with ' - + 'the condition that the "testTypeId" field has a value in "1,2,3,4"', async () => { - form.controls['foo'].patchValue('x'); - - const testResult = { testTypes: [{ testTypeId: '1' }] } as TestResultModel; - - store.overrideSelector(testResultInEdit, testResult); - - await firstValueFrom( - CustomAsyncValidators.hideIfEqualsWithCondition(store, 'bar', 'y', { - field: 'testTypeId', - operator: operatorEnum.Equals, - value: ['1', '2', '3', '4'], - })(form.controls['foo']) as Observable, - ); - - expect((form.controls['bar'] as CustomFormControl).meta.hide).toBe(false); - }); - - it('"bar" should not be hidden when "foo" is "x" and testTypeId is "5" and ' - + 'validator specifies hideIfEqualsWithCondition for current field equals "x" with ' - + 'the condition that the "testTypeId" field has a value in "1,2,3,4"', async () => { - form.controls['foo'].patchValue('x'); - - const testResult = { testTypes: [{ testTypeId: '5' }] } as TestResultModel; - - store.overrideSelector(testResultInEdit, testResult); - - await firstValueFrom( - CustomAsyncValidators.hideIfEqualsWithCondition(store, 'bar', 'x', { - field: 'testTypeId', - operator: operatorEnum.Equals, - value: ['1', '2', '3', '4'], - })(form.controls['foo']) as Observable, - ); - - expect((form.controls['bar'] as CustomFormControl).meta.hide).toBe(false); - }); - - it('"bar" should be hidden when "foo" is "x" and testTypeId is "1" and "odometerReading" is 100 and ' - + 'validator specifies hideIfEqualsWithCondition for current field equals "x" with the condition that the ' - + '"testTypeId" field has a value in "1,2,3,4" and "odometerReading" is 100', async () => { - form.controls['foo'].patchValue('x'); - - const testResult = { odometerReading: 100, testTypes: [{ testTypeId: '1' }] } as TestResultModel; - - store.overrideSelector(testResultInEdit, testResult); - - await firstValueFrom( - CustomAsyncValidators.hideIfEqualsWithCondition(store, 'bar', 'x', [ - { field: 'testTypeId', operator: operatorEnum.Equals, value: ['1', '2', '3', '4'] }, - { field: 'odometerReading', operator: operatorEnum.Equals, value: 100 }, - ])(form.controls['foo']) as Observable, - ); - - expect((form.controls['bar'] as CustomFormControl).meta.hide).toBe(true); - }); - - it('"bar" should not be hidden when "foo" is "x" and testTypeId is "1" and "odometerReading" is 101 and ' - + 'validator specifies hideIfEqualsWithCondition for current field equals "x" with the condition that the "testTypeId" ' - + 'field has a value in "1,2,3,4" and "odometerReading" is 100', async () => { - form.controls['foo'].patchValue('x'); - - const testResult = { odometerReading: 101, testTypes: [{ testTypeId: '1' }] } as TestResultModel; - - store.overrideSelector(testResultInEdit, testResult); - - await firstValueFrom( - CustomAsyncValidators.hideIfEqualsWithCondition(store, 'bar', 'x', [ - { field: 'testTypeId', operator: operatorEnum.Equals, value: ['1', '2', '3', '4'] }, - { field: 'odometerReading', operator: operatorEnum.Equals, value: 100 }, - ])(form.controls['foo']) as Observable, - ); - - expect((form.controls['bar'] as CustomFormControl).meta.hide).toBe(false); - }); + let form: FormGroup; + let store: MockStore; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore({ initialState: initialAppState })], + }); + + store = TestBed.inject(MockStore); + + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), + bar: new CustomFormControl({ name: 'bar', type: FormNodeTypes.CONTROL, children: [] }, null), + }); + }); + + it( + '"bar" should be hidden when "foo" is "x" and testTypeId is "1" and ' + + 'validator specifies hideIfEqualsWithCondition for current field equals "x" with the condition that the ' + + '"testTypeId" field has a value in "1,2,3,4"', + async () => { + form.controls['foo'].patchValue('x'); + + const testResult = { testTypes: [{ testTypeId: '1' }] } as TestResultModel; + + store.overrideSelector(testResultInEdit, testResult); + + await firstValueFrom( + CustomAsyncValidators.hideIfEqualsWithCondition(store, 'bar', 'x', { + field: 'testTypeId', + operator: operatorEnum.Equals, + value: ['1', '2', '3', '4'], + })(form.controls['foo']) as Observable + ); + + expect((form.controls['bar'] as CustomFormControl).meta.hide).toBe(true); + } + ); + + it( + '"bar" should not be hidden when "foo" is "x" and testTypeId is "1" and ' + + 'validator specifies hideIfEqualsWithCondition for current field equals "y" with ' + + 'the condition that the "testTypeId" field has a value in "1,2,3,4"', + async () => { + form.controls['foo'].patchValue('x'); + + const testResult = { testTypes: [{ testTypeId: '1' }] } as TestResultModel; + + store.overrideSelector(testResultInEdit, testResult); + + await firstValueFrom( + CustomAsyncValidators.hideIfEqualsWithCondition(store, 'bar', 'y', { + field: 'testTypeId', + operator: operatorEnum.Equals, + value: ['1', '2', '3', '4'], + })(form.controls['foo']) as Observable + ); + + expect((form.controls['bar'] as CustomFormControl).meta.hide).toBe(false); + } + ); + + it( + '"bar" should not be hidden when "foo" is "x" and testTypeId is "5" and ' + + 'validator specifies hideIfEqualsWithCondition for current field equals "x" with ' + + 'the condition that the "testTypeId" field has a value in "1,2,3,4"', + async () => { + form.controls['foo'].patchValue('x'); + + const testResult = { testTypes: [{ testTypeId: '5' }] } as TestResultModel; + + store.overrideSelector(testResultInEdit, testResult); + + await firstValueFrom( + CustomAsyncValidators.hideIfEqualsWithCondition(store, 'bar', 'x', { + field: 'testTypeId', + operator: operatorEnum.Equals, + value: ['1', '2', '3', '4'], + })(form.controls['foo']) as Observable + ); + + expect((form.controls['bar'] as CustomFormControl).meta.hide).toBe(false); + } + ); + + it( + '"bar" should be hidden when "foo" is "x" and testTypeId is "1" and "odometerReading" is 100 and ' + + 'validator specifies hideIfEqualsWithCondition for current field equals "x" with the condition that the ' + + '"testTypeId" field has a value in "1,2,3,4" and "odometerReading" is 100', + async () => { + form.controls['foo'].patchValue('x'); + + const testResult = { odometerReading: 100, testTypes: [{ testTypeId: '1' }] } as TestResultModel; + + store.overrideSelector(testResultInEdit, testResult); + + await firstValueFrom( + CustomAsyncValidators.hideIfEqualsWithCondition(store, 'bar', 'x', [ + { field: 'testTypeId', operator: operatorEnum.Equals, value: ['1', '2', '3', '4'] }, + { field: 'odometerReading', operator: operatorEnum.Equals, value: 100 }, + ])(form.controls['foo']) as Observable + ); + + expect((form.controls['bar'] as CustomFormControl).meta.hide).toBe(true); + } + ); + + it( + '"bar" should not be hidden when "foo" is "x" and testTypeId is "1" and "odometerReading" is 101 and ' + + 'validator specifies hideIfEqualsWithCondition for current field equals "x" with the condition that the "testTypeId" ' + + 'field has a value in "1,2,3,4" and "odometerReading" is 100', + async () => { + form.controls['foo'].patchValue('x'); + + const testResult = { odometerReading: 101, testTypes: [{ testTypeId: '1' }] } as TestResultModel; + + store.overrideSelector(testResultInEdit, testResult); + + await firstValueFrom( + CustomAsyncValidators.hideIfEqualsWithCondition(store, 'bar', 'x', [ + { field: 'testTypeId', operator: operatorEnum.Equals, value: ['1', '2', '3', '4'] }, + { field: 'odometerReading', operator: operatorEnum.Equals, value: 100 }, + ])(form.controls['foo']) as Observable + ); + + expect((form.controls['bar'] as CustomFormControl).meta.hide).toBe(false); + } + ); }); describe('requiredWhenCarryingDangerousGoods', () => { - let form: FormGroup; - let store: MockStore; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideMockStore({ initialState: initialAppState })], - }); - - store = TestBed.inject(MockStore); - - form = new FormGroup({ - techRecord_make: new CustomFormControl({ - name: 'techRecord_make', - type: FormNodeTypes.CONTROL, - children: [], - }, null), - techRecord_adrDetails_dangerousGoods: new CustomFormControl({ - name: 'techRecord_adrDetails_dangerousGoods', - type: FormNodeTypes.CONTROL, - children: [], - }, null), - }); - }); - it('should return null if the vehicle is not of type HGV or TRL', async () => { - // Not applicable tech record vehicle type - const carTechRecord: TechRecordType<'car', 'put'> = { - techRecord_vehicleType: 'car', - vin: 'car', - techRecord_reasonForCreation: 'test', - techRecord_statusCode: 'provisional', - }; - - store.overrideSelector(editingTechRecord, carTechRecord); - - const result = CustomAsyncValidators.requiredWhenCarryingDangerousGoods(store)(form.get('techRecord_make') as AbstractControl); - await expect(lastValueFrom(result)).resolves.toBeNull(); - }); - - it('should return null if the control is populated', async () => { - // Applicable vehicle tech record type - const hgvTechRecord: TechRecordType<'hgv', 'put'> = { - techRecord_vehicleType: 'hgv', - partialVin: '', - techRecord_bodyType_description: '', - techRecord_noOfAxles: 2, - techRecord_reasonForCreation: 'test', - techRecord_statusCode: 'provisional', - techRecord_vehicleClass_description: 'heavy goods vehicle', - primaryVrm: '', - vin: '', - - // Vehicle does carry dangerous goods - techRecord_adrDetails_dangerousGoods: true, - }; - - // ...but the control is populated - form.get('techRecord_make')?.patchValue('make'); - - store.overrideSelector(editingTechRecord, hgvTechRecord); - - const result = CustomAsyncValidators.requiredWhenCarryingDangerousGoods(store)(form.get('techRecord_make') as AbstractControl); - await expect(lastValueFrom(result)).resolves.toBeNull(); - }); - - it('should return null if the vehicle is an ADR vehicle, but does not carry dangerous goods', async () => { - // Applicable vehicle tech record type - const hgvTechRecord: TechRecordType<'hgv', 'put'> = { - techRecord_vehicleType: 'hgv', - partialVin: '', - techRecord_bodyType_description: '', - techRecord_noOfAxles: 2, - techRecord_reasonForCreation: 'test', - techRecord_statusCode: 'provisional', - techRecord_vehicleClass_description: 'heavy goods vehicle', - primaryVrm: '', - vin: '', - - // Vehicle doesn't carry dangerous goods - techRecord_adrDetails_dangerousGoods: false, - }; - - // ...and the control isn't populated - form.get('techRecord_make')?.patchValue(null); - - store.overrideSelector(editingTechRecord, hgvTechRecord); - - const result = CustomAsyncValidators.requiredWhenCarryingDangerousGoods(store)(form.get('techRecord_make') as AbstractControl); - await expect(lastValueFrom(result)).resolves.toBeNull(); - }); - - it('should return the required validation error when the vehicle is an ADR vehicle, and carries dangerous goods is selected', async () => { - // Applicable vehicle tech record type - const hgvTechRecord: TechRecordType<'hgv', 'put'> = { - techRecord_vehicleType: 'hgv', - partialVin: '', - techRecord_bodyType_description: '', - techRecord_noOfAxles: 2, - techRecord_reasonForCreation: 'test', - techRecord_statusCode: 'provisional', - techRecord_vehicleClass_description: 'heavy goods vehicle', - primaryVrm: '', - vin: '', - - // Vehicle does carry dangerous goods - techRecord_adrDetails_dangerousGoods: true, - }; - - // ...and the control isn't populated - form.get('techRecord_make')?.patchValue(null); - - store.overrideSelector(editingTechRecord, hgvTechRecord); - - const result = CustomAsyncValidators.requiredWhenCarryingDangerousGoods(store)(form.get('techRecord_make') as AbstractControl); - await expect(lastValueFrom(result)).resolves.toStrictEqual({ required: true }); - }); + let form: FormGroup; + let store: MockStore; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore({ initialState: initialAppState })], + }); + + store = TestBed.inject(MockStore); + + form = new FormGroup({ + techRecord_make: new CustomFormControl( + { + name: 'techRecord_make', + type: FormNodeTypes.CONTROL, + children: [], + }, + null + ), + techRecord_adrDetails_dangerousGoods: new CustomFormControl( + { + name: 'techRecord_adrDetails_dangerousGoods', + type: FormNodeTypes.CONTROL, + children: [], + }, + null + ), + }); + }); + it('should return null if the vehicle is not of type HGV or TRL', async () => { + // Not applicable tech record vehicle type + const carTechRecord: TechRecordType<'car', 'put'> = { + techRecord_vehicleType: 'car', + vin: 'car', + techRecord_reasonForCreation: 'test', + techRecord_statusCode: 'provisional', + }; + + store.overrideSelector(editingTechRecord, carTechRecord); + + const result = CustomAsyncValidators.requiredWhenCarryingDangerousGoods(store)( + form.get('techRecord_make') as AbstractControl + ); + await expect(lastValueFrom(result)).resolves.toBeNull(); + }); + + it('should return null if the control is populated', async () => { + // Applicable vehicle tech record type + const hgvTechRecord: TechRecordType<'hgv', 'put'> = { + techRecord_vehicleType: 'hgv', + partialVin: '', + techRecord_bodyType_description: '', + techRecord_noOfAxles: 2, + techRecord_reasonForCreation: 'test', + techRecord_statusCode: 'provisional', + techRecord_vehicleClass_description: 'heavy goods vehicle', + primaryVrm: '', + vin: '', + + // Vehicle does carry dangerous goods + techRecord_adrDetails_dangerousGoods: true, + }; + + // ...but the control is populated + form.get('techRecord_make')?.patchValue('make'); + + store.overrideSelector(editingTechRecord, hgvTechRecord); + + const result = CustomAsyncValidators.requiredWhenCarryingDangerousGoods(store)( + form.get('techRecord_make') as AbstractControl + ); + await expect(lastValueFrom(result)).resolves.toBeNull(); + }); + + it('should return null if the vehicle is an ADR vehicle, but does not carry dangerous goods', async () => { + // Applicable vehicle tech record type + const hgvTechRecord: TechRecordType<'hgv', 'put'> = { + techRecord_vehicleType: 'hgv', + partialVin: '', + techRecord_bodyType_description: '', + techRecord_noOfAxles: 2, + techRecord_reasonForCreation: 'test', + techRecord_statusCode: 'provisional', + techRecord_vehicleClass_description: 'heavy goods vehicle', + primaryVrm: '', + vin: '', + + // Vehicle doesn't carry dangerous goods + techRecord_adrDetails_dangerousGoods: false, + }; + + // ...and the control isn't populated + form.get('techRecord_make')?.patchValue(null); + + store.overrideSelector(editingTechRecord, hgvTechRecord); + + const result = CustomAsyncValidators.requiredWhenCarryingDangerousGoods(store)( + form.get('techRecord_make') as AbstractControl + ); + await expect(lastValueFrom(result)).resolves.toBeNull(); + }); + + it('should return the required validation error when the vehicle is an ADR vehicle, and carries dangerous goods is selected', async () => { + // Applicable vehicle tech record type + const hgvTechRecord: TechRecordType<'hgv', 'put'> = { + techRecord_vehicleType: 'hgv', + partialVin: '', + techRecord_bodyType_description: '', + techRecord_noOfAxles: 2, + techRecord_reasonForCreation: 'test', + techRecord_statusCode: 'provisional', + techRecord_vehicleClass_description: 'heavy goods vehicle', + primaryVrm: '', + vin: '', + + // Vehicle does carry dangerous goods + techRecord_adrDetails_dangerousGoods: true, + }; + + // ...and the control isn't populated + form.get('techRecord_make')?.patchValue(null); + + store.overrideSelector(editingTechRecord, hgvTechRecord); + + const result = CustomAsyncValidators.requiredWhenCarryingDangerousGoods(store)( + form.get('techRecord_make') as AbstractControl + ); + await expect(lastValueFrom(result)).resolves.toStrictEqual({ required: true }); + }); }); diff --git a/src/app/forms/validators/custom-async-validators.ts b/src/app/forms/validators/custom-async-validators.ts index 6594efecbd..228338da9e 100644 --- a/src/app/forms/validators/custom-async-validators.ts +++ b/src/app/forms/validators/custom-async-validators.ts @@ -1,6 +1,4 @@ -import { - AbstractControl, AsyncValidatorFn, ValidationErrors, Validators, -} from '@angular/forms'; +import { AbstractControl, AsyncValidatorFn, ValidationErrors, Validators } from '@angular/forms'; import { Condition, operatorEnum } from '@forms/models/condition.model'; // eslint-disable-next-line import/no-cycle import { CustomFormControl } from '@forms/services/dynamic-form.types'; @@ -14,263 +12,297 @@ import { selectUserByResourceKey } from '@store/reference-data'; import { editingTechRecord } from '@store/technical-records'; import { testResultInEdit } from '@store/test-records'; import { getTestStationFromProperty } from '@store/test-stations'; -import { - Observable, catchError, map, of, take, tap, -} from 'rxjs'; +import { Observable, catchError, map, of, take, tap } from 'rxjs'; export class CustomAsyncValidators { - static resultDependantOnCustomDefects(store: Store): AsyncValidatorFn { - return CustomAsyncValidators.checkResultDependantOnCustomDefects(store, [resultOfTestEnum.pass, resultOfTestEnum.fail, resultOfTestEnum.prs]); - } - - static resultDependantOnRequiredStandards(store: Store): AsyncValidatorFn { - return CustomAsyncValidators.checkResultDependantOnRequiredStandards(store, [resultOfTestEnum.pass, resultOfTestEnum.fail, resultOfTestEnum.prs]); - } - - static passResultDependantOnCustomDefects(store: Store): AsyncValidatorFn { - return CustomAsyncValidators.checkResultDependantOnCustomDefects(store, resultOfTestEnum.pass); - } - - static checkResultDependantOnCustomDefects(store: Store, limitToResult: resultOfTestEnum | resultOfTestEnum[]): AsyncValidatorFn { - return (control: AbstractControl): Observable => - store.pipe( - take(1), - select(testResultInEdit), - map((testResult) => { - const hasCustomDefects = testResult?.testTypes?.some((testType) => testType?.customDefects && testType.customDefects.length > 0); - - if ( - control.value === 'pass' - && hasCustomDefects - && (!limitToResult || Array.isArray(limitToResult) - ? limitToResult.includes(resultOfTestEnum.pass) : limitToResult === resultOfTestEnum.pass) - ) { - return { invalidTestResult: { message: 'Cannot pass test when defects are present' } }; - } if ( - control.value === 'fail' - && !hasCustomDefects - && (!limitToResult || Array.isArray(limitToResult) - ? limitToResult.includes(resultOfTestEnum.fail) : limitToResult === resultOfTestEnum.fail) - ) { - return { invalidTestResult: { message: 'Cannot fail test when no defects are present' } }; - } if ( - control.value === 'prs' - && !hasCustomDefects - && (!limitToResult || Array.isArray(limitToResult) - ? limitToResult.includes(resultOfTestEnum.prs) : limitToResult === resultOfTestEnum.prs) - ) { - return { invalidTestResult: { message: 'Cannot mark test as PRS when no defects are present' } }; - } - return null; - - }), - ); - } - - static checkResultDependantOnRequiredStandards(store: Store, limitToResult: resultOfTestEnum | resultOfTestEnum[]): AsyncValidatorFn { - return (control: AbstractControl): Observable => - store.pipe( - take(1), - select(testResultInEdit), - map((testResult) => { - const hasRequiredStandards = testResult?.testTypes?.some(( - testType, - ) => testType?.requiredStandards && testType.requiredStandards.length > 0); - - if ( - control.value === 'pass' - && hasRequiredStandards - && (!limitToResult || Array.isArray(limitToResult) - ? limitToResult.includes(resultOfTestEnum.pass) : limitToResult === resultOfTestEnum.pass) - ) { - return { invalidTestResult: { message: 'Cannot pass test when required standards are present' } }; - } if ( - control.value === 'fail' - && !hasRequiredStandards - && (!limitToResult || Array.isArray(limitToResult) - ? limitToResult.includes(resultOfTestEnum.fail) : limitToResult === resultOfTestEnum.fail) - ) { - return { invalidTestResult: { message: 'Cannot fail test when no required standards are present' } }; - } if ( - control.value === 'prs' - && !hasRequiredStandards - && (!limitToResult || Array.isArray(limitToResult) - ? limitToResult.includes(resultOfTestEnum.prs) : limitToResult === resultOfTestEnum.prs) - ) { - return { invalidTestResult: { message: 'Cannot mark test as PRS when no required standards are present' } }; - } - return null; - - }), - ); - } - - static updateTestStationDetails(store: Store): AsyncValidatorFn { - return (control: AbstractControl): Observable => { - return store.pipe( - select(getTestStationFromProperty((control as CustomFormControl).meta.name as keyof TestStation, control.value)), - take(1), - tap((stations) => { - const testStationName = control.parent?.get('testStationName'); - const testStationType = control.parent?.get('testStationType'); - if (stations) { - if (testStationName) { - testStationName.setValue(stations.testStationName, { emitEvent: true, onlySelf: true }); - } - if (testStationType) { - testStationType.setValue(stations.testStationType, { emitEvent: true, onlySelf: true }); - } - } - }), - map(() => null), - catchError(() => of(null)), - ); - }; - } - - static updateTesterDetails(store: Store): AsyncValidatorFn { - return (control: AbstractControl): Observable => { - return store.pipe( - select(selectUserByResourceKey(control.value)), - take(1), - tap((user) => { - const testerName = control.parent?.get('testerName'); - const testerEmail = control.parent?.get('testerEmailAddress'); - if (user && testerName && testerEmail) { - testerName.setValue((user as User).name, { emitEvent: false, onlySelf: true }); - testerEmail.setValue((user as User).email, { emitEvent: false, onlySelf: true }); - } - }), - map(() => null), - catchError(() => of(null)), - ); - }; - } - - static requiredIfNotResult(store: Store, result: resultOfTestEnum | resultOfTestEnum[]): AsyncValidatorFn { - return (control: AbstractControl): Observable => - store.pipe( - take(1), - select(testResultInEdit), - map((testResult) => { - const currentResult = testResult?.testTypes[0].testResult; - if ( - (Array.isArray(result) ? currentResult && !result.includes(currentResult) : currentResult !== result) - && (control.value == null || control.value === '') - ) { - if (Array.isArray(result)) return { requiredIfNotResult: true }; - return { [`requiredIfNot${result}`]: true }; - } - return null; - }), - ); - } - - static requiredIfNotFail(store: Store): AsyncValidatorFn { - return this.requiredIfNotResult(store, resultOfTestEnum.fail); - } - - static requiredIfNotAbandoned(store: Store): AsyncValidatorFn { - return this.requiredIfNotResult(store, resultOfTestEnum.abandoned); - } - - static requiredIfNotResultAndSiblingEquals( - store: Store, - result: resultOfTestEnum | resultOfTestEnum[], - sibling: string, - value: unknown, - ): AsyncValidatorFn { - return (control: AbstractControl): Observable => - store.pipe( - take(1), - select(testResultInEdit), - map((testResult) => { - if (control?.parent) { - const siblingControl = control.parent.get(sibling) as CustomFormControl; - const siblingValue = siblingControl.value; - const newValue = Array.isArray(value) ? value.includes(siblingValue) : siblingValue === value; - - const currentResult = testResult?.testTypes[0].testResult; - - if ( - (Array.isArray(result) ? currentResult && !result.includes(currentResult) : currentResult !== result) - && newValue - && (control.value === null || control.value === undefined || control.value === '') - ) { - return { requiredIfNotResultAndSiblingEquals: true }; - } - } - - return null; - }), - ); - } - - static hideIfEqualsWithCondition(store: Store, sibling: string, value: string, conditions: Condition | Condition[]): AsyncValidatorFn { - return (control: AbstractControl): Observable => - store.pipe( - take(1), - select(testResultInEdit), - map((testResult) => { - if (!testResult || !control?.parent) { - return null; - } - - const siblingControl = control.parent.get(sibling) as CustomFormControl; - - const conditionsPassed = CustomAsyncValidators.checkConditions(testResult, conditions); - - siblingControl.meta.hide = conditionsPassed && (Array.isArray(value) ? value.includes(control.value) : control.value === value); - - return null; - }), - ); - } - - static requiredWhenCarryingDangerousGoods = (store: Store) => { - return (control: AbstractControl): Observable => { - return store.select(editingTechRecord).pipe(take(1), map((form) => { - if ( - form - && (form.techRecord_vehicleType === 'hgv' || form.techRecord_vehicleType === 'trl') - && (form.techRecord_adrDetails_dangerousGoods)) { - return Validators.required(control); - } - - return null; - })); - }; - }; - - private static checkConditions(testResult: TestResultModel, conditions: Condition | Condition[]) { - if (!Array.isArray(conditions)) { - return CustomAsyncValidators.checkCondition(testResult, conditions); - } - - return conditions.every((condition) => CustomAsyncValidators.checkCondition(testResult, condition)); - } - - private static checkCondition(testResult: TestResultModel, condition: Condition) { - const { field, operator, value } = condition; - - // eslint-disable-next-line no-prototype-builtins - const fieldValue = testResult.testTypes[0].hasOwnProperty(field) - // eslint-disable-next-line @typescript-eslint/no-explicit-any, security/detect-object-injection - ? (testResult.testTypes[0] as any)[field] - : (testResult)[field as keyof TestResultModel]; - - const isTrue = Array.isArray(value) ? value.includes(fieldValue) : fieldValue === value; - - 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); - }; - }; + static resultDependantOnCustomDefects(store: Store): AsyncValidatorFn { + return CustomAsyncValidators.checkResultDependantOnCustomDefects(store, [ + resultOfTestEnum.pass, + resultOfTestEnum.fail, + resultOfTestEnum.prs, + ]); + } + + static resultDependantOnRequiredStandards(store: Store): AsyncValidatorFn { + return CustomAsyncValidators.checkResultDependantOnRequiredStandards(store, [ + resultOfTestEnum.pass, + resultOfTestEnum.fail, + resultOfTestEnum.prs, + ]); + } + + static passResultDependantOnCustomDefects(store: Store): AsyncValidatorFn { + return CustomAsyncValidators.checkResultDependantOnCustomDefects(store, resultOfTestEnum.pass); + } + + static checkResultDependantOnCustomDefects( + store: Store, + limitToResult: resultOfTestEnum | resultOfTestEnum[] + ): AsyncValidatorFn { + return (control: AbstractControl): Observable => + store.pipe( + take(1), + select(testResultInEdit), + map((testResult) => { + const hasCustomDefects = testResult?.testTypes?.some( + (testType) => testType?.customDefects && testType.customDefects.length > 0 + ); + + if ( + control.value === 'pass' && + hasCustomDefects && + (!limitToResult || Array.isArray(limitToResult) + ? limitToResult.includes(resultOfTestEnum.pass) + : limitToResult === resultOfTestEnum.pass) + ) { + return { invalidTestResult: { message: 'Cannot pass test when defects are present' } }; + } + if ( + control.value === 'fail' && + !hasCustomDefects && + (!limitToResult || Array.isArray(limitToResult) + ? limitToResult.includes(resultOfTestEnum.fail) + : limitToResult === resultOfTestEnum.fail) + ) { + return { invalidTestResult: { message: 'Cannot fail test when no defects are present' } }; + } + if ( + control.value === 'prs' && + !hasCustomDefects && + (!limitToResult || Array.isArray(limitToResult) + ? limitToResult.includes(resultOfTestEnum.prs) + : limitToResult === resultOfTestEnum.prs) + ) { + return { invalidTestResult: { message: 'Cannot mark test as PRS when no defects are present' } }; + } + return null; + }) + ); + } + + static checkResultDependantOnRequiredStandards( + store: Store, + limitToResult: resultOfTestEnum | resultOfTestEnum[] + ): AsyncValidatorFn { + return (control: AbstractControl): Observable => + store.pipe( + take(1), + select(testResultInEdit), + map((testResult) => { + const hasRequiredStandards = testResult?.testTypes?.some( + (testType) => testType?.requiredStandards && testType.requiredStandards.length > 0 + ); + + if ( + control.value === 'pass' && + hasRequiredStandards && + (!limitToResult || Array.isArray(limitToResult) + ? limitToResult.includes(resultOfTestEnum.pass) + : limitToResult === resultOfTestEnum.pass) + ) { + return { invalidTestResult: { message: 'Cannot pass test when required standards are present' } }; + } + if ( + control.value === 'fail' && + !hasRequiredStandards && + (!limitToResult || Array.isArray(limitToResult) + ? limitToResult.includes(resultOfTestEnum.fail) + : limitToResult === resultOfTestEnum.fail) + ) { + return { invalidTestResult: { message: 'Cannot fail test when no required standards are present' } }; + } + if ( + control.value === 'prs' && + !hasRequiredStandards && + (!limitToResult || Array.isArray(limitToResult) + ? limitToResult.includes(resultOfTestEnum.prs) + : limitToResult === resultOfTestEnum.prs) + ) { + return { invalidTestResult: { message: 'Cannot mark test as PRS when no required standards are present' } }; + } + return null; + }) + ); + } + + static updateTestStationDetails(store: Store): AsyncValidatorFn { + return (control: AbstractControl): Observable => { + return store.pipe( + select( + getTestStationFromProperty((control as CustomFormControl).meta.name as keyof TestStation, control.value) + ), + take(1), + tap((stations) => { + const testStationName = control.parent?.get('testStationName'); + const testStationType = control.parent?.get('testStationType'); + if (stations) { + if (testStationName) { + testStationName.setValue(stations.testStationName, { emitEvent: true, onlySelf: true }); + } + if (testStationType) { + testStationType.setValue(stations.testStationType, { emitEvent: true, onlySelf: true }); + } + } + }), + map(() => null), + catchError(() => of(null)) + ); + }; + } + + static updateTesterDetails(store: Store): AsyncValidatorFn { + return (control: AbstractControl): Observable => { + return store.pipe( + select(selectUserByResourceKey(control.value)), + take(1), + tap((user) => { + const testerName = control.parent?.get('testerName'); + const testerEmail = control.parent?.get('testerEmailAddress'); + if (user && testerName && testerEmail) { + testerName.setValue((user as User).name, { emitEvent: false, onlySelf: true }); + testerEmail.setValue((user as User).email, { emitEvent: false, onlySelf: true }); + } + }), + map(() => null), + catchError(() => of(null)) + ); + }; + } + + static requiredIfNotResult(store: Store, result: resultOfTestEnum | resultOfTestEnum[]): AsyncValidatorFn { + return (control: AbstractControl): Observable => + store.pipe( + take(1), + select(testResultInEdit), + map((testResult) => { + const currentResult = testResult?.testTypes[0].testResult; + if ( + (Array.isArray(result) ? currentResult && !result.includes(currentResult) : currentResult !== result) && + (control.value == null || control.value === '') + ) { + if (Array.isArray(result)) return { requiredIfNotResult: true }; + return { [`requiredIfNot${result}`]: true }; + } + return null; + }) + ); + } + + static requiredIfNotFail(store: Store): AsyncValidatorFn { + return this.requiredIfNotResult(store, resultOfTestEnum.fail); + } + + static requiredIfNotAbandoned(store: Store): AsyncValidatorFn { + return this.requiredIfNotResult(store, resultOfTestEnum.abandoned); + } + + static requiredIfNotResultAndSiblingEquals( + store: Store, + result: resultOfTestEnum | resultOfTestEnum[], + sibling: string, + value: unknown + ): AsyncValidatorFn { + return (control: AbstractControl): Observable => + store.pipe( + take(1), + select(testResultInEdit), + map((testResult) => { + if (control?.parent) { + const siblingControl = control.parent.get(sibling) as CustomFormControl; + const siblingValue = siblingControl.value; + const newValue = Array.isArray(value) ? value.includes(siblingValue) : siblingValue === value; + + const currentResult = testResult?.testTypes[0].testResult; + + if ( + (Array.isArray(result) ? currentResult && !result.includes(currentResult) : currentResult !== result) && + newValue && + (control.value === null || control.value === undefined || control.value === '') + ) { + return { requiredIfNotResultAndSiblingEquals: true }; + } + } + + return null; + }) + ); + } + + static hideIfEqualsWithCondition( + store: Store, + sibling: string, + value: string, + conditions: Condition | Condition[] + ): AsyncValidatorFn { + return (control: AbstractControl): Observable => + store.pipe( + take(1), + select(testResultInEdit), + map((testResult) => { + if (!testResult || !control?.parent) { + return null; + } + + const siblingControl = control.parent.get(sibling) as CustomFormControl; + + const conditionsPassed = CustomAsyncValidators.checkConditions(testResult, conditions); + + siblingControl.meta.hide = + conditionsPassed && (Array.isArray(value) ? value.includes(control.value) : control.value === value); + + return null; + }) + ); + } + + static requiredWhenCarryingDangerousGoods = (store: Store) => { + return (control: AbstractControl): Observable => { + return store.select(editingTechRecord).pipe( + take(1), + map((form) => { + if ( + form && + (form.techRecord_vehicleType === 'hgv' || form.techRecord_vehicleType === 'trl') && + form.techRecord_adrDetails_dangerousGoods + ) { + return Validators.required(control); + } + + return null; + }) + ); + }; + }; + + private static checkConditions(testResult: TestResultModel, conditions: Condition | Condition[]) { + if (!Array.isArray(conditions)) { + return CustomAsyncValidators.checkCondition(testResult, conditions); + } + + return conditions.every((condition) => CustomAsyncValidators.checkCondition(testResult, condition)); + } + + private static checkCondition(testResult: TestResultModel, condition: Condition) { + const { field, operator, value } = condition; + + // eslint-disable-next-line no-prototype-builtins + const fieldValue = testResult.testTypes[0].hasOwnProperty(field) + ? // eslint-disable-next-line @typescript-eslint/no-explicit-any, security/detect-object-injection + (testResult.testTypes[0] as any)[field] + : testResult[field as keyof TestResultModel]; + + const isTrue = Array.isArray(value) ? value.includes(fieldValue) : fieldValue === value; + + 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..24533c2ff9 100644 --- a/src/app/forms/validators/custom-validators.spec.ts +++ b/src/app/forms/validators/custom-validators.spec.ts @@ -1,6 +1,4 @@ -import { - AbstractControl, FormArray, FormControl, FormGroup, -} from '@angular/forms'; +import { 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'; @@ -10,2079 +8,2141 @@ import { VehicleSizes, VehicleTypes } from '@models/vehicle-tech-record.model'; import { CustomValidators } from './custom-validators'; interface CustomPatternMessage { - customPattern: { - message: string; - }; + customPattern: { + message: string; + }; } describe('Hiding validators', () => { - let form: FormGroup; - - beforeEach(() => { - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), - sibling: new CustomFormControl({ name: 'sibling', type: FormNodeTypes.CONTROL, children: [] }, null), - }); - }); - - describe('Hide if empty', () => { - it('should return null', () => { - expect(CustomValidators.hideIfEmpty('foo')(form.controls['sibling'])).toBeNull(); - }); - - it('should set meta.hide to true if content of sibling is empty', () => { - CustomValidators.hideIfEmpty('foo')(form.controls['sibling']); - expect((form.controls['foo'] as CustomFormControl).meta.hide).toBe(true); - }); - - it('should set meta.hide to false if content of sibling is not empty', () => { - (form.controls['foo'] as CustomFormControl).meta.hide = true; - form.controls['sibling'].patchValue('bar'); - CustomValidators.hideIfEmpty('foo')(form.controls['sibling']); - expect((form.controls['foo'] as CustomFormControl).meta.hide).toBe(false); - }); - }); - - describe('Hide if equals', () => { - it('should return null', () => { - expect(CustomValidators.hideIfEquals('foo', 'foo')(form.controls['sibling'])).toBeNull(); - }); - - it('should set meta.hide to true if content of sibling is equal to the value passed', () => { - const value = 'bar'; - form.controls['sibling'].patchValue(value); - CustomValidators.hideIfEquals('foo', 'bar')(form.controls['sibling']); - expect((form.controls['foo'] as CustomFormControl).meta.hide).toBe(true); - }); - - it('should set meta.hide to true if content of sibling is equal to one of the values passed in the array', () => { - const value = 'bar'; - form.controls['sibling'].patchValue(value); - CustomValidators.hideIfEquals('foo', ['bar', 'foo', 'foobar'])(form.controls['sibling']); - expect((form.controls['foo'] as CustomFormControl).meta.hide).toBe(true); - }); - - it('should set meta.hide to false if content of sibling is not equal to the value passed', () => { - const value = 'bar'; - form.controls['sibling'].patchValue(value); - (form.controls['foo'] as CustomFormControl).meta.hide = true; - CustomValidators.hideIfEquals('foo', 'foo')(form.controls['sibling']); - expect((form.controls['foo'] as CustomFormControl).meta.hide).toBe(false); - }); - }); - - describe('Hide if not equals', () => { - it('should return null', () => { - expect(CustomValidators.hideIfNotEqual('foo', 'foo')(form.controls['sibling'])).toBeNull(); - }); - - it('should set meta.hide to true if content of sibling is not equal to the value passed', () => { - const value = 'foo'; - form.controls['sibling'].patchValue(value); - CustomValidators.hideIfNotEqual('foo', 'bar')(form.controls['sibling']); - expect((form.controls['foo'] as CustomFormControl).meta.hide).toBe(true); - }); - - it('should set meta.hide to true if content of sibling is not equal to any of the values passed in the array', () => { - const value = 'value'; - form.controls['sibling'].patchValue(value); - CustomValidators.hideIfNotEqual('foo', ['bar', 'foo', 'foobar'])(form.controls['sibling']); - expect((form.controls['foo'] as CustomFormControl).meta.hide).toBe(true); - }); - - it('should set meta.hide to false if content of sibling is equal to the value passed', () => { - const value = 'bar'; - form.controls['sibling'].patchValue(value); - (form.controls['foo'] as CustomFormControl).meta.hide = true; - CustomValidators.hideIfNotEqual('foo', 'bar')(form.controls['sibling']); - expect((form.controls['foo'] as CustomFormControl).meta.hide).toBe(false); - }); - }); + let form: FormGroup; + + beforeEach(() => { + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), + sibling: new CustomFormControl({ name: 'sibling', type: FormNodeTypes.CONTROL, children: [] }, null), + }); + }); + + describe('Hide if empty', () => { + it('should return null', () => { + expect(CustomValidators.hideIfEmpty('foo')(form.controls['sibling'])).toBeNull(); + }); + + it('should set meta.hide to true if content of sibling is empty', () => { + CustomValidators.hideIfEmpty('foo')(form.controls['sibling']); + expect((form.controls['foo'] as CustomFormControl).meta.hide).toBe(true); + }); + + it('should set meta.hide to false if content of sibling is not empty', () => { + (form.controls['foo'] as CustomFormControl).meta.hide = true; + form.controls['sibling'].patchValue('bar'); + CustomValidators.hideIfEmpty('foo')(form.controls['sibling']); + expect((form.controls['foo'] as CustomFormControl).meta.hide).toBe(false); + }); + }); + + describe('Hide if equals', () => { + it('should return null', () => { + expect(CustomValidators.hideIfEquals('foo', 'foo')(form.controls['sibling'])).toBeNull(); + }); + + it('should set meta.hide to true if content of sibling is equal to the value passed', () => { + const value = 'bar'; + form.controls['sibling'].patchValue(value); + CustomValidators.hideIfEquals('foo', 'bar')(form.controls['sibling']); + expect((form.controls['foo'] as CustomFormControl).meta.hide).toBe(true); + }); + + it('should set meta.hide to true if content of sibling is equal to one of the values passed in the array', () => { + const value = 'bar'; + form.controls['sibling'].patchValue(value); + CustomValidators.hideIfEquals('foo', ['bar', 'foo', 'foobar'])(form.controls['sibling']); + expect((form.controls['foo'] as CustomFormControl).meta.hide).toBe(true); + }); + + it('should set meta.hide to false if content of sibling is not equal to the value passed', () => { + const value = 'bar'; + form.controls['sibling'].patchValue(value); + (form.controls['foo'] as CustomFormControl).meta.hide = true; + CustomValidators.hideIfEquals('foo', 'foo')(form.controls['sibling']); + expect((form.controls['foo'] as CustomFormControl).meta.hide).toBe(false); + }); + }); + + describe('Hide if not equals', () => { + it('should return null', () => { + expect(CustomValidators.hideIfNotEqual('foo', 'foo')(form.controls['sibling'])).toBeNull(); + }); + + it('should set meta.hide to true if content of sibling is not equal to the value passed', () => { + const value = 'foo'; + form.controls['sibling'].patchValue(value); + CustomValidators.hideIfNotEqual('foo', 'bar')(form.controls['sibling']); + expect((form.controls['foo'] as CustomFormControl).meta.hide).toBe(true); + }); + + it('should set meta.hide to true if content of sibling is not equal to any of the values passed in the array', () => { + const value = 'value'; + form.controls['sibling'].patchValue(value); + CustomValidators.hideIfNotEqual('foo', ['bar', 'foo', 'foobar'])(form.controls['sibling']); + expect((form.controls['foo'] as CustomFormControl).meta.hide).toBe(true); + }); + + it('should set meta.hide to false if content of sibling is equal to the value passed', () => { + const value = 'bar'; + form.controls['sibling'].patchValue(value); + (form.controls['foo'] as CustomFormControl).meta.hide = true; + CustomValidators.hideIfNotEqual('foo', 'bar')(form.controls['sibling']); + expect((form.controls['foo'] as CustomFormControl).meta.hide).toBe(false); + }); + }); }); describe('enable/disable validators', () => { - let form: FormGroup; - - beforeEach(() => { - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), - sibling: new CustomFormControl({ name: 'sibling', type: FormNodeTypes.CONTROL, children: [] }, null), - }); - }); - - describe('enable if equals', () => { - it('should return null', () => { - expect(CustomValidators.enableIfEquals('foo', 'foo')(form.controls['sibling'])).toBeNull(); - }); - - it('should set enabled to true if content of sibling is equal to the value passed', () => { - const value = 'bar'; - form.controls['sibling'].patchValue(value); - CustomValidators.enableIfEquals('foo', 'bar')(form.controls['sibling']); - expect((form.controls['foo'] as CustomFormControl).enabled).toBe(true); - }); - - it('should set enabled to true if content of sibling is equal to one of the values passed in the array', () => { - const value = 'bar'; - form.controls['sibling'].patchValue(value); - CustomValidators.enableIfEquals('foo', ['bar', 'foo', 'foobar'])(form.controls['sibling']); - expect((form.controls['foo'] as CustomFormControl).enabled).toBe(true); - }); - - it('should set enabled to false if content of sibling is not equal to the value passed', () => { - const value = 'bar'; - form.controls['sibling'].patchValue(value); - (form.controls['foo'] as CustomFormControl).enable(); - CustomValidators.enableIfEquals('foo', 'foo')(form.controls['sibling']); - expect((form.controls['foo'] as CustomFormControl).enabled).toBe(false); - }); - }); - - describe('disable if equals', () => { - it('should return null', () => { - expect(CustomValidators.disableIfEquals('foo', 'foo')(form.controls['sibling'])).toBeNull(); - }); - - it('should set disabled to true if content of sibling is equal to the value passed', () => { - const value = 'bar'; - form.controls['sibling'].patchValue(value); - CustomValidators.disableIfEquals('foo', 'bar')(form.controls['sibling']); - expect((form.controls['foo'] as CustomFormControl).disabled).toBe(true); - }); - - it('should set disabled to true if content of sibling is equal to one of the values passed in the array', () => { - const value = 'bar'; - form.controls['sibling'].patchValue(value); - CustomValidators.disableIfEquals('foo', ['bar', 'foo', 'foobar'])(form.controls['sibling']); - expect((form.controls['foo'] as CustomFormControl).disabled).toBe(true); - }); - - it('should set disabled to false if content of sibling is not equal to the value passed', () => { - const value = 'bar'; - form.controls['sibling'].patchValue(value); - (form.controls['foo'] as CustomFormControl).disable(); - CustomValidators.disableIfEquals('foo', 'foo')(form.controls['sibling']); - expect((form.controls['foo'] as CustomFormControl).disabled).toBe(false); - }); - }); + let form: FormGroup; + + beforeEach(() => { + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), + sibling: new CustomFormControl({ name: 'sibling', type: FormNodeTypes.CONTROL, children: [] }, null), + }); + }); + + describe('enable if equals', () => { + it('should return null', () => { + expect(CustomValidators.enableIfEquals('foo', 'foo')(form.controls['sibling'])).toBeNull(); + }); + + it('should set enabled to true if content of sibling is equal to the value passed', () => { + const value = 'bar'; + form.controls['sibling'].patchValue(value); + CustomValidators.enableIfEquals('foo', 'bar')(form.controls['sibling']); + expect((form.controls['foo'] as CustomFormControl).enabled).toBe(true); + }); + + it('should set enabled to true if content of sibling is equal to one of the values passed in the array', () => { + const value = 'bar'; + form.controls['sibling'].patchValue(value); + CustomValidators.enableIfEquals('foo', ['bar', 'foo', 'foobar'])(form.controls['sibling']); + expect((form.controls['foo'] as CustomFormControl).enabled).toBe(true); + }); + + it('should set enabled to false if content of sibling is not equal to the value passed', () => { + const value = 'bar'; + form.controls['sibling'].patchValue(value); + (form.controls['foo'] as CustomFormControl).enable(); + CustomValidators.enableIfEquals('foo', 'foo')(form.controls['sibling']); + expect((form.controls['foo'] as CustomFormControl).enabled).toBe(false); + }); + }); + + describe('disable if equals', () => { + it('should return null', () => { + expect(CustomValidators.disableIfEquals('foo', 'foo')(form.controls['sibling'])).toBeNull(); + }); + + it('should set disabled to true if content of sibling is equal to the value passed', () => { + const value = 'bar'; + form.controls['sibling'].patchValue(value); + CustomValidators.disableIfEquals('foo', 'bar')(form.controls['sibling']); + expect((form.controls['foo'] as CustomFormControl).disabled).toBe(true); + }); + + it('should set disabled to true if content of sibling is equal to one of the values passed in the array', () => { + const value = 'bar'; + form.controls['sibling'].patchValue(value); + CustomValidators.disableIfEquals('foo', ['bar', 'foo', 'foobar'])(form.controls['sibling']); + expect((form.controls['foo'] as CustomFormControl).disabled).toBe(true); + }); + + it('should set disabled to false if content of sibling is not equal to the value passed', () => { + const value = 'bar'; + form.controls['sibling'].patchValue(value); + (form.controls['foo'] as CustomFormControl).disable(); + CustomValidators.disableIfEquals('foo', 'foo')(form.controls['sibling']); + expect((form.controls['foo'] as CustomFormControl).disabled).toBe(false); + }); + }); }); describe('parent sibling validators', () => { - let form: FormGroup; - - beforeEach(() => { - form = new FormGroup({ - parent: new CustomFormGroup( - { name: 'parent', type: FormNodeTypes.GROUP }, - { child: new CustomFormControl({ name: 'child', type: FormNodeTypes.CONTROL }) }, - ), - sibling: new CustomFormControl({ name: 'sibling', type: FormNodeTypes.CONTROL, hide: false }), - }); - }); - - it('should return null', () => { - expect(CustomValidators.hideIfParentSiblingEquals('foo', 'bar')(form.controls['sibling'])).toBeNull(); - }); - - it('should set meta.hide to true if content of parent sibling is equal to the value passed', () => { - const value = 'bar'; - const child = form.get(['parent', 'child']); - child?.patchValue(value); - CustomValidators.hideIfParentSiblingEquals('sibling', value)(child as AbstractControl); - expect((form.controls['sibling'] as CustomFormControl).meta.hide).toBe(true); - }); - - it('should set meta.hide to true if content of parent sibling is not equal to the value passed', () => { - const value = true; - const child = form.get(['parent', 'child']); - child?.patchValue(value); - CustomValidators.hideIfParentSiblingNotEqual('sibling', !value)(child as AbstractControl); - expect((form.controls['sibling'] as CustomFormControl).meta.hide).toBe(true); - }); + let form: FormGroup; + + beforeEach(() => { + form = new FormGroup({ + parent: new CustomFormGroup( + { name: 'parent', type: FormNodeTypes.GROUP }, + { child: new CustomFormControl({ name: 'child', type: FormNodeTypes.CONTROL }) } + ), + sibling: new CustomFormControl({ name: 'sibling', type: FormNodeTypes.CONTROL, hide: false }), + }); + }); + + it('should return null', () => { + expect(CustomValidators.hideIfParentSiblingEquals('foo', 'bar')(form.controls['sibling'])).toBeNull(); + }); + + it('should set meta.hide to true if content of parent sibling is equal to the value passed', () => { + const value = 'bar'; + const child = form.get(['parent', 'child']); + child?.patchValue(value); + CustomValidators.hideIfParentSiblingEquals('sibling', value)(child as AbstractControl); + expect((form.controls['sibling'] as CustomFormControl).meta.hide).toBe(true); + }); + + it('should set meta.hide to true if content of parent sibling is not equal to the value passed', () => { + const value = true; + const child = form.get(['parent', 'child']); + child?.patchValue(value); + CustomValidators.hideIfParentSiblingNotEqual('sibling', !value)(child as AbstractControl); + expect((form.controls['sibling'] as CustomFormControl).meta.hide).toBe(true); + }); }); describe('Required validators', () => { - let form: FormGroup; - - beforeEach(() => { - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), - sibling: new CustomFormControl( - { - name: 'sibling', - label: 'Sibling', - type: FormNodeTypes.CONTROL, - children: [], - }, - null, - ), - }); - form.controls['sibling'].patchValue('some value'); - }); - - describe('Required if equals', () => { - it('should be required (return ValidationErrors) if content of sibling matches a value', () => { - const result = CustomValidators.requiredIfEquals('sibling', ['some value'])(form.controls['foo']); - expect(result).toEqual({ requiredIfEquals: { sibling: 'Sibling' } }); - }); - - it('should not be required (return null) if content of sibling does not match a value', () => { - form.controls['sibling'].patchValue('some other value'); - const result = CustomValidators.requiredIfEquals('sibling', ['some value'])(form.controls['foo']); - expect(result).toBeNull(); - }); - - it('should not be required (return null) if content of sibling does matches a value and we have a value', () => { - form.controls['foo'].patchValue('some foo value'); - const result = CustomValidators.requiredIfEquals('sibling', ['some value'])(form.controls['foo']); - expect(result).toBeNull(); - }); - - it('should not be required (return null) when the sibling and control values overlap (for arrays)', () => { - form.controls['foo'].patchValue(['battery']); - form.controls['sibling'].patchValue(['battery']); - const result = CustomValidators.requiredIfEquals('sibling', ['battery'])(form.controls['foo']); - expect(result).toBeNull(); - }); - - it('should not be required (return null) when sibling value does not match passed value', () => { - form.controls['foo'].patchValue(['not a battery']); - const result = CustomValidators.requiredIfEquals('sibling', ['battery'])(form.controls['foo']); - expect(result).toBeNull(); - }); - - it('should be required (return null) when sibling value overlaps with values passed, and control is empty', () => { - form.controls['sibling'].patchValue(['battery']); - form.controls['foo'].patchValue([null]); // array with only falsy values is considered empty - const result = CustomValidators.requiredIfEquals('sibling', ['battery'])(form.controls['foo']); - expect(result).toEqual({ requiredIfEquals: { sibling: 'Sibling' } }); - }); - - it('should not be required (return null) when sibling value overlaps with values passed, and control is not empty', () => { - form.controls['sibling'].patchValue(['battery']); - form.controls['foo'].patchValue([null, 'truthy']); // array with a falsy value, but some truthy values is considered NOT empty - const result = CustomValidators.requiredIfEquals('sibling', ['battery'])(form.controls['foo']); - expect(result).toBeNull(); - }); - }); - - describe('Required if not equal', () => { - it('should not be required (return null) if content of sibling does not match a value', () => { - const result = CustomValidators.requiredIfNotEquals('sibling', 'some value')(form.controls['foo']); - expect(result).toBeNull(); - }); - - it('should be required (return ValidationErrors) if content of sibling does not match a value', () => { - const result = CustomValidators.requiredIfNotEquals('sibling', 'some other value')(form.controls['foo']); - expect(result).toEqual({ requiredIfNotEquals: { sibling: 'Sibling' } }); - }); - - it('should not be required (return null) if content of sibling does matches a value and we have a value', () => { - form.controls['foo'].patchValue('some foo value'); - const result = CustomValidators.requiredIfEquals('sibling', ['some othervalue'])(form.controls['foo']); - expect(result).toBeNull(); - }); - }); - - describe('Must Equal Sibling', () => { - it('should return null if content of sibling matches a value', () => { - const value = 'some value'; - form.controls['foo'].patchValue(value); - form.controls['sibling'].patchValue(value); - const result = CustomValidators.mustEqualSibling('sibling')(form.controls['foo']); - expect(result).toBeNull(); - }); - - it('should return ValidationErrors if content of sibling does not match the value', () => { - const value = 'some value'; - form.controls['foo'].patchValue(value); - form.controls['sibling'].patchValue('some other value'); - const result = CustomValidators.mustEqualSibling('sibling')(form.controls['foo']); - expect(result).toEqual({ mustEqualSibling: { sibling: 'Sibling' } }); - }); - }); + let form: FormGroup; + + beforeEach(() => { + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), + sibling: new CustomFormControl( + { + name: 'sibling', + label: 'Sibling', + type: FormNodeTypes.CONTROL, + children: [], + }, + null + ), + }); + form.controls['sibling'].patchValue('some value'); + }); + + describe('Required if equals', () => { + it('should be required (return ValidationErrors) if content of sibling matches a value', () => { + const result = CustomValidators.requiredIfEquals('sibling', ['some value'])(form.controls['foo']); + expect(result).toEqual({ requiredIfEquals: { sibling: 'Sibling' } }); + }); + + it('should not be required (return null) if content of sibling does not match a value', () => { + form.controls['sibling'].patchValue('some other value'); + const result = CustomValidators.requiredIfEquals('sibling', ['some value'])(form.controls['foo']); + expect(result).toBeNull(); + }); + + it('should not be required (return null) if content of sibling does matches a value and we have a value', () => { + form.controls['foo'].patchValue('some foo value'); + const result = CustomValidators.requiredIfEquals('sibling', ['some value'])(form.controls['foo']); + expect(result).toBeNull(); + }); + + it('should not be required (return null) when the sibling and control values overlap (for arrays)', () => { + form.controls['foo'].patchValue(['battery']); + form.controls['sibling'].patchValue(['battery']); + const result = CustomValidators.requiredIfEquals('sibling', ['battery'])(form.controls['foo']); + expect(result).toBeNull(); + }); + + it('should not be required (return null) when sibling value does not match passed value', () => { + form.controls['foo'].patchValue(['not a battery']); + const result = CustomValidators.requiredIfEquals('sibling', ['battery'])(form.controls['foo']); + expect(result).toBeNull(); + }); + + it('should be required (return null) when sibling value overlaps with values passed, and control is empty', () => { + form.controls['sibling'].patchValue(['battery']); + form.controls['foo'].patchValue([null]); // array with only falsy values is considered empty + const result = CustomValidators.requiredIfEquals('sibling', ['battery'])(form.controls['foo']); + expect(result).toEqual({ requiredIfEquals: { sibling: 'Sibling' } }); + }); + + it('should not be required (return null) when sibling value overlaps with values passed, and control is not empty', () => { + form.controls['sibling'].patchValue(['battery']); + form.controls['foo'].patchValue([null, 'truthy']); // array with a falsy value, but some truthy values is considered NOT empty + const result = CustomValidators.requiredIfEquals('sibling', ['battery'])(form.controls['foo']); + expect(result).toBeNull(); + }); + }); + + describe('Required if not equal', () => { + it('should not be required (return null) if content of sibling does not match a value', () => { + const result = CustomValidators.requiredIfNotEquals('sibling', 'some value')(form.controls['foo']); + expect(result).toBeNull(); + }); + + it('should be required (return ValidationErrors) if content of sibling does not match a value', () => { + const result = CustomValidators.requiredIfNotEquals('sibling', 'some other value')(form.controls['foo']); + expect(result).toEqual({ requiredIfNotEquals: { sibling: 'Sibling' } }); + }); + + it('should not be required (return null) if content of sibling does matches a value and we have a value', () => { + form.controls['foo'].patchValue('some foo value'); + const result = CustomValidators.requiredIfEquals('sibling', ['some othervalue'])(form.controls['foo']); + expect(result).toBeNull(); + }); + }); + + describe('Must Equal Sibling', () => { + it('should return null if content of sibling matches a value', () => { + const value = 'some value'; + form.controls['foo'].patchValue(value); + form.controls['sibling'].patchValue(value); + const result = CustomValidators.mustEqualSibling('sibling')(form.controls['foo']); + expect(result).toBeNull(); + }); + + it('should return ValidationErrors if content of sibling does not match the value', () => { + const value = 'some value'; + form.controls['foo'].patchValue(value); + form.controls['sibling'].patchValue('some other value'); + const result = CustomValidators.mustEqualSibling('sibling')(form.controls['foo']); + expect(result).toEqual({ mustEqualSibling: { sibling: 'Sibling' } }); + }); + }); }); describe('numeric', () => { - it.each([ - [null, 123456789], - [null, 0], - [null, ''], - [{ customPattern: { message: 'must be a whole number' } }, 'foobar'], - [{ customPattern: { message: 'must be a whole number' } }, '123456bar'], - [{ customPattern: { message: 'must be a whole number' } }, 'foo123456'], - [null, '123546789'], - [null, null], - ])('should return %o for %r', (expected: null | CustomPatternMessage, input: unknown) => { - const numberValidator = CustomValidators.numeric(); - expect(numberValidator(new FormControl(input))).toEqual(expected); - }); + it.each([ + [null, 123456789], + [null, 0], + [null, ''], + [{ customPattern: { message: 'must be a whole number' } }, 'foobar'], + [{ customPattern: { message: 'must be a whole number' } }, '123456bar'], + [{ customPattern: { message: 'must be a whole number' } }, 'foo123456'], + [null, '123546789'], + [null, null], + ])('should return %o for %r', (expected: null | CustomPatternMessage, input: unknown) => { + const numberValidator = CustomValidators.numeric(); + expect(numberValidator(new FormControl(input))).toEqual(expected); + }); }); describe('defined', () => { - it.each([ - [{ defined: false }, undefined], - [null, ''], - [null, null], - [null, 'hello world!'], - [null, 1234], - ])('should return %o for %r', (expected: null | { [index: string]: boolean }, input: unknown) => { - const definedValidator = CustomValidators.defined(); - const form = new FormControl(input); - if (typeof input === 'undefined') { - // Unable to instantiate form with a value that is not defined... - form.patchValue(undefined); - } - expect(definedValidator(form)).toEqual(expected); - }); + it.each([ + [{ defined: false }, undefined], + [null, ''], + [null, null], + [null, 'hello world!'], + [null, 1234], + ])('should return %o for %r', (expected: null | { [index: string]: boolean }, input: unknown) => { + const definedValidator = CustomValidators.defined(); + const form = new FormControl(input); + if (typeof input === 'undefined') { + // Unable to instantiate form with a value that is not defined... + form.patchValue(undefined); + } + expect(definedValidator(form)).toEqual(expected); + }); }); describe('alphanumeric', () => { - it.each([ - [null, '12dc9a'], - [null, 0], - [null, 'asas'], - [{ customPattern: { message: 'must be alphanumeric' } }, 'foobar+'], - [{ customPattern: { message: 'must be alphanumeric' } }, '123456bar-'], - [{ customPattern: { message: 'must be alphanumeric' } }, 'foo123456^@'], - [null, '123546789abcdefghijklmnopqrstuvwxyz'], - [null, null], - ])('should return %o for %r', (expected: null | CustomPatternMessage, input: unknown) => { - const numberValidator = CustomValidators.alphanumeric(); - expect(numberValidator(new FormControl(input))).toEqual(expected); - }); + it.each([ + [null, '12dc9a'], + [null, 0], + [null, 'asas'], + [{ customPattern: { message: 'must be alphanumeric' } }, 'foobar+'], + [{ customPattern: { message: 'must be alphanumeric' } }, '123456bar-'], + [{ customPattern: { message: 'must be alphanumeric' } }, 'foo123456^@'], + [null, '123546789abcdefghijklmnopqrstuvwxyz'], + [null, null], + ])('should return %o for %r', (expected: null | CustomPatternMessage, input: unknown) => { + const numberValidator = CustomValidators.alphanumeric(); + expect(numberValidator(new FormControl(input))).toEqual(expected); + }); }); describe('customPattern', () => { - it.each([ - [null, 123456789, '.*', 'this should always pass'], - [null, 'jkl', 'c*', 'this should be a character'], - [{ customPattern: { message: 'this should not be a number' } }, 123456789, '\\D+', 'this should not be a number'], - [null, '%^', '^\\W+$', 'this should be a symbol'], - [null, null, '.*', 'pass on null'], - ])('should return %o for %r', (expected: null | CustomPatternMessage, input: unknown, regex: string, msg: string) => { - const customPattern = CustomValidators.customPattern([regex, msg]); - const validation = customPattern(new FormControl(input)); - expect(validation).toEqual(expected); - if (validation) { - const { - customPattern: { message }, - } = validation; - // eslint-disable-next-line jest/no-conditional-expect - expect(message).toEqual(msg); - } else { - // eslint-disable-next-line jest/no-conditional-expect - expect(validation).toBeNull(); - } - }); - - it('should throw an error if an invalid regex is given', () => { - expect(CustomValidators.customPattern(['regex', 'msg'])).toThrow(); - }); + it.each([ + [null, 123456789, '.*', 'this should always pass'], + [null, 'jkl', 'c*', 'this should be a character'], + [{ customPattern: { message: 'this should not be a number' } }, 123456789, '\\D+', 'this should not be a number'], + [null, '%^', '^\\W+$', 'this should be a symbol'], + [null, null, '.*', 'pass on null'], + ])('should return %o for %r', (expected: null | CustomPatternMessage, input: unknown, regex: string, msg: string) => { + const customPattern = CustomValidators.customPattern([regex, msg]); + const validation = customPattern(new FormControl(input)); + expect(validation).toEqual(expected); + if (validation) { + const { + customPattern: { message }, + } = validation; + // eslint-disable-next-line jest/no-conditional-expect + expect(message).toEqual(msg); + } else { + // eslint-disable-next-line jest/no-conditional-expect + expect(validation).toBeNull(); + } + }); + + it('should throw an error if an invalid regex is given', () => { + expect(CustomValidators.customPattern(['regex', 'msg'])).toThrow(); + }); }); describe('invalidOption', () => { - it.each([ - [null, ''], - [{ invalidOption: true }, '[INVALID_OPTION]'], - ])('should return %p when control value is %s', (expected: object | null, input: string) => { - expect(CustomValidators.invalidOption(new FormControl(input))).toEqual(expected); - }); + it.each([ + [null, ''], + [{ invalidOption: true }, '[INVALID_OPTION]'], + ])('should return %p when control value is %s', (expected: object | null, input: string) => { + expect(CustomValidators.invalidOption(new FormControl(input))).toEqual(expected); + }); }); describe('pastDate', () => { - beforeAll(() => { - jest.useFakeTimers().setSystemTime(new Date('2022-01-01T00:00:00.000Z')); - }); - - afterAll(() => { - jest.useRealTimers(); - }); - - it.each([ - [null, ''], - [null, null], - [null, '2020-01-01T00:00:00.000Z'], - [{ pastDate: true }, '2022-01-01T00:00:01.000Z'], - ])('should return %p when control value is %s', (expected: object | null, input: string | null) => { - expect(CustomValidators.pastDate(new FormControl(input))).toEqual(expected); - }); + beforeAll(() => { + jest.useFakeTimers().setSystemTime(new Date('2022-01-01T00:00:00.000Z')); + }); + + afterAll(() => { + jest.useRealTimers(); + }); + + it.each([ + [null, ''], + [null, null], + [null, '2020-01-01T00:00:00.000Z'], + [{ pastDate: true }, '2022-01-01T00:00:01.000Z'], + ])('should return %p when control value is %s', (expected: object | null, input: string | null) => { + expect(CustomValidators.pastDate(new FormControl(input))).toEqual(expected); + }); }); describe('futureDate', () => { - beforeAll(() => { - jest.useFakeTimers().setSystemTime(new Date('2022-01-01T00:00:00.000Z')); - }); - - afterAll(() => { - jest.useRealTimers(); - }); - - it.each([ - [null, ''], - [null, null], - [null, '2022-01-01T00:00:01.000Z'], - [{ futureDate: true }, '2020-01-01T00:00:00.000Z'], - ])('should return %p when control value is %s', (expected: object | null, input: string | null) => { - expect(CustomValidators.futureDate(new FormControl(input))).toEqual(expected); - }); + beforeAll(() => { + jest.useFakeTimers().setSystemTime(new Date('2022-01-01T00:00:00.000Z')); + }); + + afterAll(() => { + jest.useRealTimers(); + }); + + it.each([ + [null, ''], + [null, null], + [null, '2022-01-01T00:00:01.000Z'], + [{ futureDate: true }, '2020-01-01T00:00:00.000Z'], + ])('should return %p when control value is %s', (expected: object | null, input: string | null) => { + expect(CustomValidators.futureDate(new FormControl(input))).toEqual(expected); + }); }); describe('pastYear', () => { - beforeAll(() => { - jest.useFakeTimers().setSystemTime(new Date('2022-01-01T00:00:00.000Z')); - }); - - afterAll(() => { - jest.useRealTimers(); - }); - - it.each([ - [null, null], - [{ pastYear: true }, 2023], - [null, 2020], - ])('should return %p when control value is %s', (expected: object | null, input: number | null) => { - expect(CustomValidators.pastYear(new FormControl(input))).toEqual(expected); - }); + beforeAll(() => { + jest.useFakeTimers().setSystemTime(new Date('2022-01-01T00:00:00.000Z')); + }); + + afterAll(() => { + jest.useRealTimers(); + }); + + it.each([ + [null, null], + [{ pastYear: true }, 2023], + [null, 2020], + ])('should return %p when control value is %s', (expected: object | null, input: number | null) => { + expect(CustomValidators.pastYear(new FormControl(input))).toEqual(expected); + }); }); describe('aheadOfDate', () => { - let form: FormGroup; - beforeEach(() => { - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), - sibling: new CustomFormControl( - { - name: 'sibling', - label: 'sibling', - type: FormNodeTypes.CONTROL, - children: [], - }, - null, - ), - }); - }); - - describe('tests', () => { - it('should return an error message if sibling date is ahead of foo', () => { - form.controls['foo'].patchValue(new Date('2020-01-01T00:00:00.000Z').toISOString()); - form.controls['sibling'].patchValue(new Date('2021-01-01T00:00:00.000Z').toISOString()); - - const result = CustomValidators.aheadOfDate('sibling')(form.controls['foo']); - expect(result).toEqual({ aheadOfDate: { sibling: 'sibling', date: new Date('2021-01-01T00:00:00.000Z') } }); - }); - - it('should return null if sibling date is not ahead of foo', () => { - form.controls['foo'].patchValue(new Date('2021-01-01T00:00:00.000Z').toISOString()); - form.controls['sibling'].patchValue(new Date('2020-01-01T00:00:00.000Z').toISOString()); - - const result = CustomValidators.aheadOfDate('sibling')(form.controls['foo']); - expect(result).toBeNull(); - }); - }); + let form: FormGroup; + beforeEach(() => { + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), + sibling: new CustomFormControl( + { + name: 'sibling', + label: 'sibling', + type: FormNodeTypes.CONTROL, + children: [], + }, + null + ), + }); + }); + + describe('tests', () => { + it('should return an error message if sibling date is ahead of foo', () => { + form.controls['foo'].patchValue(new Date('2020-01-01T00:00:00.000Z').toISOString()); + form.controls['sibling'].patchValue(new Date('2021-01-01T00:00:00.000Z').toISOString()); + + const result = CustomValidators.aheadOfDate('sibling')(form.controls['foo']); + expect(result).toEqual({ aheadOfDate: { sibling: 'sibling', date: new Date('2021-01-01T00:00:00.000Z') } }); + }); + + it('should return null if sibling date is not ahead of foo', () => { + form.controls['foo'].patchValue(new Date('2021-01-01T00:00:00.000Z').toISOString()); + form.controls['sibling'].patchValue(new Date('2020-01-01T00:00:00.000Z').toISOString()); + + const result = CustomValidators.aheadOfDate('sibling')(form.controls['foo']); + expect(result).toBeNull(); + }); + }); }); describe('dateNotExceed', () => { - let form: FormGroup; - beforeEach(() => { - form = new FormGroup({ - foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), - sibling: new CustomFormControl( - { - name: 'sibling', - label: 'sibling', - type: FormNodeTypes.CONTROL, - children: [], - }, - null, - ), - }); - }); - - describe('dateNotExceed tests', () => { - it('should return an error message if sibling date plus 10 months is not ahead of foo', () => { - form.controls['foo'].patchValue(new Date('2020-12-01T00:00:00.000Z').toISOString()); - form.controls['sibling'].patchValue(new Date('2020-01-01T00:00:00.000Z').toISOString()); - - const result = CustomValidators.dateNotExceed('sibling', 10)(form.controls['foo']); - expect(result).toEqual({ dateNotExceed: { sibling: 'sibling', months: 10 } }); - }); - - it('should return an error message if sibling date plus 14 months is not ahead of foo', () => { - form.controls['foo'].patchValue(new Date('2021-04-01T00:00:00.000Z').toISOString()); - form.controls['sibling'].patchValue(new Date('2020-01-01T00:00:00.000Z').toISOString()); - - const result = CustomValidators.dateNotExceed('sibling', 14)(form.controls['foo']); - expect(result).toEqual({ dateNotExceed: { sibling: 'sibling', months: 14 } }); - }); - - it('should return null if sibling date plus 10 months is ahead of foo', () => { - form.controls['foo'].patchValue(new Date('2020-09-01T00:00:00.000Z').toISOString()); - form.controls['sibling'].patchValue(new Date('2020-01-01T00:00:00.000Z').toISOString()); - - const result = CustomValidators.dateNotExceed('sibling', 10)(form.controls['foo']); - expect(result).toBeNull(); - }); - - it('should return null if sibling date plus 14 months is ahead of foo', () => { - form.controls['foo'].patchValue(new Date('2021-02-01T00:00:00.000Z').toISOString()); - form.controls['sibling'].patchValue(new Date('2020-01-01T00:00:00.000Z').toISOString()); - - const result = CustomValidators.dateNotExceed('sibling', 14)(form.controls['foo']); - expect(result).toBeNull(); - }); - }); + let form: FormGroup; + beforeEach(() => { + form = new FormGroup({ + foo: new CustomFormControl({ name: 'foo', type: FormNodeTypes.CONTROL, children: [] }, null), + sibling: new CustomFormControl( + { + name: 'sibling', + label: 'sibling', + type: FormNodeTypes.CONTROL, + children: [], + }, + null + ), + }); + }); + + describe('dateNotExceed tests', () => { + it('should return an error message if sibling date plus 10 months is not ahead of foo', () => { + form.controls['foo'].patchValue(new Date('2020-12-01T00:00:00.000Z').toISOString()); + form.controls['sibling'].patchValue(new Date('2020-01-01T00:00:00.000Z').toISOString()); + + const result = CustomValidators.dateNotExceed('sibling', 10)(form.controls['foo']); + expect(result).toEqual({ dateNotExceed: { sibling: 'sibling', months: 10 } }); + }); + + it('should return an error message if sibling date plus 14 months is not ahead of foo', () => { + form.controls['foo'].patchValue(new Date('2021-04-01T00:00:00.000Z').toISOString()); + form.controls['sibling'].patchValue(new Date('2020-01-01T00:00:00.000Z').toISOString()); + + const result = CustomValidators.dateNotExceed('sibling', 14)(form.controls['foo']); + expect(result).toEqual({ dateNotExceed: { sibling: 'sibling', months: 14 } }); + }); + + it('should return null if sibling date plus 10 months is ahead of foo', () => { + form.controls['foo'].patchValue(new Date('2020-09-01T00:00:00.000Z').toISOString()); + form.controls['sibling'].patchValue(new Date('2020-01-01T00:00:00.000Z').toISOString()); + + const result = CustomValidators.dateNotExceed('sibling', 10)(form.controls['foo']); + expect(result).toBeNull(); + }); + + it('should return null if sibling date plus 14 months is ahead of foo', () => { + form.controls['foo'].patchValue(new Date('2021-02-01T00:00:00.000Z').toISOString()); + form.controls['sibling'].patchValue(new Date('2020-01-01T00:00:00.000Z').toISOString()); + + const result = CustomValidators.dateNotExceed('sibling', 14)(form.controls['foo']); + expect(result).toBeNull(); + }); + }); }); describe('validate VRM/TrailerId Length', () => { - let form: FormGroup; - - beforeEach(() => { - form = new FormGroup({ - parent: new CustomFormGroup( - { name: 'parent', type: FormNodeTypes.GROUP }, - { - child: new CustomFormControl({ name: 'child', type: FormNodeTypes.CONTROL }), - sibling: new CustomFormControl({ name: 'sibling', type: FormNodeTypes.CONTROL }), - }, - ), - }); - }); - - it('should return null when value is null', () => { - const value = null; - const child = form.get(['parent', 'child']); - child?.patchValue(value); - - const result = CustomValidators.validateVRMTrailerIdLength('sibling')(child as AbstractControl); - expect(result).toBeNull(); - }); - - it('should return null when value is 7 characters long and Trailer is selected', () => { - const value = 'TESTTRL'; - const child = form.get(['parent', 'child']); - const sibling = form.get(['parent', 'sibling']); - child?.patchValue(value); - sibling?.patchValue(VehicleTypes.TRL); - - const result = CustomValidators.validateVRMTrailerIdLength('sibling')(child as AbstractControl); - expect(result).toBeNull(); - }); - - it('should return null when value is 8 characters long and Trailer is selected', () => { - const value = 'TESTTRLR'; - const child = form.get(['parent', 'child']); - const sibling = form.get(['parent', 'sibling']); - child?.patchValue(value); - sibling?.patchValue(VehicleTypes.TRL); - - const result = CustomValidators.validateVRMTrailerIdLength('sibling')(child as AbstractControl); - expect(result).toBeNull(); - }); - - it('should return null when value is 8 characters long', () => { - const value = 'TESTTRLR'; - const child = form.get(['parent', 'child']); - child?.patchValue(value); - - const result = CustomValidators.validateVRMTrailerIdLength('sibling')(child as AbstractControl); - expect(result).toBeNull(); - }); - - it('should return VRM max length error when value length is greater than 9', () => { - const value = 'TESTVRM123'; - const child = form.get(['parent', 'child']); - child?.patchValue(value); - - const result = CustomValidators.validateVRMTrailerIdLength('sibling')(child as AbstractControl); - expect(result?.['validateVRMTrailerIdLength'].message).toBe('VRM must be less than or equal to 9 characters'); - }); - - it('should return TrailerId min length error when value length is less than 7 and Trailer is selected', () => { - const value = 'TESTTR'; - const child = form.get(['parent', 'child']); - const sibling = form.get(['parent', 'sibling']); - child?.patchValue(value); - sibling?.patchValue(VehicleTypes.TRL); - - const result = CustomValidators.validateVRMTrailerIdLength('sibling')(child as AbstractControl); - expect(result?.['validateVRMTrailerIdLength'].message).toBe('Trailer ID must be greater than or equal to 7 characters'); - }); - - it('should return TrailerId max length error when value length is greater than 8 and Trailer is selected', () => { - const value = 'TESTTRLRR'; - const child = form.get(['parent', 'child']); - const sibling = form.get(['parent', 'sibling']); - child?.patchValue(value); - sibling?.patchValue(VehicleTypes.TRL); - - const result = CustomValidators.validateVRMTrailerIdLength('sibling')(child as AbstractControl); - expect(result?.['validateVRMTrailerIdLength'].message).toBe('Trailer ID must be less than or equal to 8 characters'); - }); + let form: FormGroup; + + beforeEach(() => { + form = new FormGroup({ + parent: new CustomFormGroup( + { name: 'parent', type: FormNodeTypes.GROUP }, + { + child: new CustomFormControl({ name: 'child', type: FormNodeTypes.CONTROL }), + sibling: new CustomFormControl({ name: 'sibling', type: FormNodeTypes.CONTROL }), + } + ), + }); + }); + + it('should return null when value is null', () => { + const value = null; + const child = form.get(['parent', 'child']); + child?.patchValue(value); + + const result = CustomValidators.validateVRMTrailerIdLength('sibling')(child as AbstractControl); + expect(result).toBeNull(); + }); + + it('should return null when value is 7 characters long and Trailer is selected', () => { + const value = 'TESTTRL'; + const child = form.get(['parent', 'child']); + const sibling = form.get(['parent', 'sibling']); + child?.patchValue(value); + sibling?.patchValue(VehicleTypes.TRL); + + const result = CustomValidators.validateVRMTrailerIdLength('sibling')(child as AbstractControl); + expect(result).toBeNull(); + }); + + it('should return null when value is 8 characters long and Trailer is selected', () => { + const value = 'TESTTRLR'; + const child = form.get(['parent', 'child']); + const sibling = form.get(['parent', 'sibling']); + child?.patchValue(value); + sibling?.patchValue(VehicleTypes.TRL); + + const result = CustomValidators.validateVRMTrailerIdLength('sibling')(child as AbstractControl); + expect(result).toBeNull(); + }); + + it('should return null when value is 8 characters long', () => { + const value = 'TESTTRLR'; + const child = form.get(['parent', 'child']); + child?.patchValue(value); + + const result = CustomValidators.validateVRMTrailerIdLength('sibling')(child as AbstractControl); + expect(result).toBeNull(); + }); + + it('should return VRM max length error when value length is greater than 9', () => { + const value = 'TESTVRM123'; + const child = form.get(['parent', 'child']); + child?.patchValue(value); + + const result = CustomValidators.validateVRMTrailerIdLength('sibling')(child as AbstractControl); + expect(result?.['validateVRMTrailerIdLength'].message).toBe('VRM must be less than or equal to 9 characters'); + }); + + it('should return TrailerId min length error when value length is less than 7 and Trailer is selected', () => { + const value = 'TESTTR'; + const child = form.get(['parent', 'child']); + const sibling = form.get(['parent', 'sibling']); + child?.patchValue(value); + sibling?.patchValue(VehicleTypes.TRL); + + const result = CustomValidators.validateVRMTrailerIdLength('sibling')(child as AbstractControl); + expect(result?.['validateVRMTrailerIdLength'].message).toBe( + 'Trailer ID must be greater than or equal to 7 characters' + ); + }); + + it('should return TrailerId max length error when value length is greater than 8 and Trailer is selected', () => { + const value = 'TESTTRLRR'; + const child = form.get(['parent', 'child']); + const sibling = form.get(['parent', 'sibling']); + child?.patchValue(value); + sibling?.patchValue(VehicleTypes.TRL); + + const result = CustomValidators.validateVRMTrailerIdLength('sibling')(child as AbstractControl); + expect(result?.['validateVRMTrailerIdLength'].message).toBe( + 'Trailer ID must be less than or equal to 8 characters' + ); + }); }); describe('handlePsvPassengersChange', () => { - let form: FormGroup; - beforeEach(() => { - form = new FormGroup({ - techRecord_vehicleSize: new CustomFormControl({ name: 'techRecord_vehicleSize', type: FormNodeTypes.CONTROL }, undefined), - techRecord_vehicleClass_description: new CustomFormControl( - { name: 'techRecord_vehicleClass_description', type: FormNodeTypes.CONTROL }, - undefined, - ), - techRecord_seatsLowerDeck: new CustomFormControl({ name: 'techRecord_seatsLowerDeck', type: FormNodeTypes.CONTROL }, undefined), - techRecord_seatsUpperDeck: new CustomFormControl({ name: 'techRecord_seatsUpperDeck', type: FormNodeTypes.CONTROL }, undefined), - techRecord_standingCapacity: new CustomFormControl({ name: 'techRecord_standingCapacity', type: FormNodeTypes.CONTROL }, undefined), - }); - }); - it('should calculate small vehicle size and class based on passenger numbers', () => { - const upper = form.get('techRecord_seatsUpperDeck'); - const lower = form.get('techRecord_seatsLowerDeck'); - const standing = form.get('techRecord_standingCapacity'); - - upper?.patchValue(1); - lower?.patchValue(2); - standing?.patchValue(3); - standing?.markAsDirty(); - - CustomValidators.handlePsvPassengersChange('techRecord_seatsUpperDeck', 'techRecord_seatsLowerDeck')(standing as AbstractControl); - const vehicleSize = form.get('techRecord_vehicleSize')?.value; - const vehicleClass = form.get('techRecord_vehicleClass_description')?.value; - - expect(vehicleSize).toBe(VehicleSizes.SMALL); - expect(vehicleClass).toBe(VehicleClassDescription.SmallPsvIeLessThanOrEqualTo22Seats); - }); - it('should calculate large vehicle size and class based on passenger numbers', () => { - const upper = form.get('techRecord_seatsUpperDeck'); - const lower = form.get('techRecord_seatsLowerDeck'); - const standing = form.get('techRecord_standingCapacity'); - - upper?.patchValue(13); - lower?.patchValue(22); - standing?.patchValue(1); - standing?.markAsDirty(); - - CustomValidators.handlePsvPassengersChange('techRecord_seatsUpperDeck', 'techRecord_seatsLowerDeck')(standing as AbstractControl); - const vehicleSize = form.get('techRecord_vehicleSize')?.value; - const vehicleClass = form.get('techRecord_vehicleClass_description')?.value; - - expect(vehicleSize).toBe(VehicleSizes.LARGE); - expect(vehicleClass).toBe(VehicleClassDescription.LargePsvIeGreaterThan23Seats); - }); + let form: FormGroup; + beforeEach(() => { + form = new FormGroup({ + techRecord_vehicleSize: new CustomFormControl( + { name: 'techRecord_vehicleSize', type: FormNodeTypes.CONTROL }, + undefined + ), + techRecord_vehicleClass_description: new CustomFormControl( + { name: 'techRecord_vehicleClass_description', type: FormNodeTypes.CONTROL }, + undefined + ), + techRecord_seatsLowerDeck: new CustomFormControl( + { name: 'techRecord_seatsLowerDeck', type: FormNodeTypes.CONTROL }, + undefined + ), + techRecord_seatsUpperDeck: new CustomFormControl( + { name: 'techRecord_seatsUpperDeck', type: FormNodeTypes.CONTROL }, + undefined + ), + techRecord_standingCapacity: new CustomFormControl( + { name: 'techRecord_standingCapacity', type: FormNodeTypes.CONTROL }, + undefined + ), + }); + }); + it('should calculate small vehicle size and class based on passenger numbers', () => { + const upper = form.get('techRecord_seatsUpperDeck'); + const lower = form.get('techRecord_seatsLowerDeck'); + const standing = form.get('techRecord_standingCapacity'); + + upper?.patchValue(1); + lower?.patchValue(2); + standing?.patchValue(3); + standing?.markAsDirty(); + + CustomValidators.handlePsvPassengersChange( + 'techRecord_seatsUpperDeck', + 'techRecord_seatsLowerDeck' + )(standing as AbstractControl); + const vehicleSize = form.get('techRecord_vehicleSize')?.value; + const vehicleClass = form.get('techRecord_vehicleClass_description')?.value; + + expect(vehicleSize).toBe(VehicleSizes.SMALL); + expect(vehicleClass).toBe(VehicleClassDescription.SmallPsvIeLessThanOrEqualTo22Seats); + }); + it('should calculate large vehicle size and class based on passenger numbers', () => { + const upper = form.get('techRecord_seatsUpperDeck'); + const lower = form.get('techRecord_seatsLowerDeck'); + const standing = form.get('techRecord_standingCapacity'); + + upper?.patchValue(13); + lower?.patchValue(22); + standing?.patchValue(1); + standing?.markAsDirty(); + + CustomValidators.handlePsvPassengersChange( + 'techRecord_seatsUpperDeck', + 'techRecord_seatsLowerDeck' + )(standing as AbstractControl); + const vehicleSize = form.get('techRecord_vehicleSize')?.value; + const vehicleClass = form.get('techRecord_vehicleClass_description')?.value; + + expect(vehicleSize).toBe(VehicleSizes.LARGE); + expect(vehicleClass).toBe(VehicleClassDescription.LargePsvIeGreaterThan23Seats); + }); }); describe('updateFunctionCode', () => { - let form: FormGroup; - beforeEach(() => { - form = new FormGroup({ - techRecord_vehicleConfiguration: new CustomFormControl({ name: 'techRecord_vehicleConfiguration', type: FormNodeTypes.CONTROL }, undefined), - techRecord_functionCode: new CustomFormControl({ name: 'techRecord_functionCode', type: FormNodeTypes.CONTROL }, undefined), - }); - }); - it('should set the function code to R if given a rigid vehicle configuration', () => { - const functionCode = form.get('techRecord_functionCode'); - const vehicleConfiguration = form.get('techRecord_vehicleConfiguration'); - - vehicleConfiguration?.patchValue('rigid'); - vehicleConfiguration?.markAsDirty(); - - CustomValidators.updateFunctionCode()(vehicleConfiguration as AbstractControl); - const value = functionCode?.value; - expect(value).toBe('R'); - }); - it('should set the function code to A if given a articulated vehicle configuration', () => { - const functionCode = form.get('techRecord_functionCode'); - const vehicleConfiguration = form.get('techRecord_vehicleConfiguration'); - - vehicleConfiguration?.patchValue('articulated'); - vehicleConfiguration?.markAsDirty(); - - CustomValidators.updateFunctionCode()(vehicleConfiguration as AbstractControl); - const value = functionCode?.value; - expect(value).toBe('A'); - }); - it('should set the function code to A if given a semi-trailer vehicle configuration', () => { - const functionCode = form.get('techRecord_functionCode'); - const vehicleConfiguration = form.get('techRecord_vehicleConfiguration'); - - vehicleConfiguration?.patchValue('semi-trailer'); - vehicleConfiguration?.markAsDirty(); - - CustomValidators.updateFunctionCode()(vehicleConfiguration as AbstractControl); - const value = functionCode?.value; - expect(value).toBe('A'); - }); - it('should not set the function code if vehicle configuration is not in the map', () => { - const functionCode = form.get('techRecord_functionCode'); - const vehicleConfiguration = form.get('techRecord_vehicleConfiguration'); - - vehicleConfiguration?.patchValue('invalid'); - vehicleConfiguration?.markAsDirty(); - - CustomValidators.updateFunctionCode()(vehicleConfiguration as AbstractControl); - const value = functionCode?.value; - expect(value).toBeUndefined(); - }); + let form: FormGroup; + beforeEach(() => { + form = new FormGroup({ + techRecord_vehicleConfiguration: new CustomFormControl( + { name: 'techRecord_vehicleConfiguration', type: FormNodeTypes.CONTROL }, + undefined + ), + techRecord_functionCode: new CustomFormControl( + { name: 'techRecord_functionCode', type: FormNodeTypes.CONTROL }, + undefined + ), + }); + }); + it('should set the function code to R if given a rigid vehicle configuration', () => { + const functionCode = form.get('techRecord_functionCode'); + const vehicleConfiguration = form.get('techRecord_vehicleConfiguration'); + + vehicleConfiguration?.patchValue('rigid'); + vehicleConfiguration?.markAsDirty(); + + CustomValidators.updateFunctionCode()(vehicleConfiguration as AbstractControl); + const value = functionCode?.value; + expect(value).toBe('R'); + }); + it('should set the function code to A if given a articulated vehicle configuration', () => { + const functionCode = form.get('techRecord_functionCode'); + const vehicleConfiguration = form.get('techRecord_vehicleConfiguration'); + + vehicleConfiguration?.patchValue('articulated'); + vehicleConfiguration?.markAsDirty(); + + CustomValidators.updateFunctionCode()(vehicleConfiguration as AbstractControl); + const value = functionCode?.value; + expect(value).toBe('A'); + }); + it('should set the function code to A if given a semi-trailer vehicle configuration', () => { + const functionCode = form.get('techRecord_functionCode'); + const vehicleConfiguration = form.get('techRecord_vehicleConfiguration'); + + vehicleConfiguration?.patchValue('semi-trailer'); + vehicleConfiguration?.markAsDirty(); + + CustomValidators.updateFunctionCode()(vehicleConfiguration as AbstractControl); + const value = functionCode?.value; + expect(value).toBe('A'); + }); + it('should not set the function code if vehicle configuration is not in the map', () => { + const functionCode = form.get('techRecord_functionCode'); + const vehicleConfiguration = form.get('techRecord_vehicleConfiguration'); + + vehicleConfiguration?.patchValue('invalid'); + vehicleConfiguration?.markAsDirty(); + + CustomValidators.updateFunctionCode()(vehicleConfiguration as AbstractControl); + const value = functionCode?.value; + expect(value).toBeUndefined(); + }); }); describe('showGroupsWhenEqualTo', () => { - let form: FormGroup; - beforeEach(() => { - form = new CustomFormGroup( - { - 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'], - }, - ], - }, - { - dangerousGoods: new CustomFormControl( - { - name: 'dangerousGoods', - type: FormNodeTypes.CONTROL, - }, - undefined, - ), - techRecord_adrDetails_applicantDetails_name: new CustomFormControl( - { - name: 'techRecord_adrDetails_applicantDetails_name', - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['adr', 'name'], - }, - undefined, - ), - techRecord_adrDetails_applicantDetails_street: new CustomFormControl( - { - name: 'techRecord_adrDetails_applicantDetails_street', - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['adr'], - }, - undefined, - ), - techRecord_adrDetails_applicantDetails_town: new CustomFormControl( - { - name: 'techRecord_adrDetails_applicantDetails_town', - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['adr'], - }, - undefined, - ), - }, - ); - }); - it('should set hide as false on a control if it is in a group included in the array passed and values match true', () => { - const adr = form.get('dangerousGoods'); - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const street = form.get('techRecord_adrDetails_applicantDetails_street') as CustomFormControl; - const town = form.get('techRecord_adrDetails_applicantDetails_town') as CustomFormControl; - - adr?.patchValue(true); - - CustomValidators.showGroupsWhenEqualTo([true], ['adr'])(adr as AbstractControl); - - expect(name?.meta.hide).toBe(false); - expect(street?.meta.hide).toBe(false); - expect(town?.meta.hide).toBe(false); - }); - it('should set hide as false on a control if it is in a group included in the array passed and values match false', () => { - const adr = form.get('dangerousGoods'); - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const street = form.get('techRecord_adrDetails_applicantDetails_street') as CustomFormControl; - const town = form.get('techRecord_adrDetails_applicantDetails_town') as CustomFormControl; - - adr?.patchValue(false); - - CustomValidators.showGroupsWhenEqualTo([false], ['adr'])(adr as AbstractControl); - - expect(name?.meta.hide).toBe(false); - expect(street?.meta.hide).toBe(false); - expect(town?.meta.hide).toBe(false); - }); - it('should not change the hide flag if values dont match', () => { - const adr = form.get('dangerousGoods'); - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const street = form.get('techRecord_adrDetails_applicantDetails_street') as CustomFormControl; - const town = form.get('techRecord_adrDetails_applicantDetails_town') as CustomFormControl; - - adr?.patchValue(true); - - CustomValidators.showGroupsWhenEqualTo([false], ['adr'])(adr as AbstractControl); - - expect(name?.meta.hide).toBe(true); - expect(street?.meta.hide).toBe(true); - expect(town?.meta.hide).toBe(true); - }); - it('should only change hide on groups included in array', () => { - const adr = form.get('dangerousGoods'); - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const street = form.get('techRecord_adrDetails_applicantDetails_street') as CustomFormControl; - const town = form.get('techRecord_adrDetails_applicantDetails_town') as CustomFormControl; - - adr?.patchValue(true); - - CustomValidators.showGroupsWhenEqualTo([true], ['name'])(adr as AbstractControl); - - expect(name?.meta.hide).toBe(false); - expect(street?.meta.hide).toBe(true); - expect(town?.meta.hide).toBe(true); - }); + let form: FormGroup; + beforeEach(() => { + form = new CustomFormGroup( + { + 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'], + }, + ], + }, + { + dangerousGoods: new CustomFormControl( + { + name: 'dangerousGoods', + type: FormNodeTypes.CONTROL, + }, + undefined + ), + techRecord_adrDetails_applicantDetails_name: new CustomFormControl( + { + name: 'techRecord_adrDetails_applicantDetails_name', + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['adr', 'name'], + }, + undefined + ), + techRecord_adrDetails_applicantDetails_street: new CustomFormControl( + { + name: 'techRecord_adrDetails_applicantDetails_street', + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['adr'], + }, + undefined + ), + techRecord_adrDetails_applicantDetails_town: new CustomFormControl( + { + name: 'techRecord_adrDetails_applicantDetails_town', + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['adr'], + }, + undefined + ), + } + ); + }); + it('should set hide as false on a control if it is in a group included in the array passed and values match true', () => { + const adr = form.get('dangerousGoods'); + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const street = form.get('techRecord_adrDetails_applicantDetails_street') as CustomFormControl; + const town = form.get('techRecord_adrDetails_applicantDetails_town') as CustomFormControl; + + adr?.patchValue(true); + + CustomValidators.showGroupsWhenEqualTo([true], ['adr'])(adr as AbstractControl); + + expect(name?.meta.hide).toBe(false); + expect(street?.meta.hide).toBe(false); + expect(town?.meta.hide).toBe(false); + }); + it('should set hide as false on a control if it is in a group included in the array passed and values match false', () => { + const adr = form.get('dangerousGoods'); + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const street = form.get('techRecord_adrDetails_applicantDetails_street') as CustomFormControl; + const town = form.get('techRecord_adrDetails_applicantDetails_town') as CustomFormControl; + + adr?.patchValue(false); + + CustomValidators.showGroupsWhenEqualTo([false], ['adr'])(adr as AbstractControl); + + expect(name?.meta.hide).toBe(false); + expect(street?.meta.hide).toBe(false); + expect(town?.meta.hide).toBe(false); + }); + it('should not change the hide flag if values dont match', () => { + const adr = form.get('dangerousGoods'); + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const street = form.get('techRecord_adrDetails_applicantDetails_street') as CustomFormControl; + const town = form.get('techRecord_adrDetails_applicantDetails_town') as CustomFormControl; + + adr?.patchValue(true); + + CustomValidators.showGroupsWhenEqualTo([false], ['adr'])(adr as AbstractControl); + + expect(name?.meta.hide).toBe(true); + expect(street?.meta.hide).toBe(true); + expect(town?.meta.hide).toBe(true); + }); + it('should only change hide on groups included in array', () => { + const adr = form.get('dangerousGoods'); + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const street = form.get('techRecord_adrDetails_applicantDetails_street') as CustomFormControl; + const town = form.get('techRecord_adrDetails_applicantDetails_town') as CustomFormControl; + + adr?.patchValue(true); + + CustomValidators.showGroupsWhenEqualTo([true], ['name'])(adr as AbstractControl); + + expect(name?.meta.hide).toBe(false); + expect(street?.meta.hide).toBe(true); + expect(town?.meta.hide).toBe(true); + }); }); describe('hideGroupsWhenEqualTo', () => { - let form: CustomFormGroup; - beforeEach(() => { - form = new CustomFormGroup( - { - 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'], - }, - ], - }, - { - dangerousGoods: new CustomFormControl( - { - name: 'dangerousGoods', - type: FormNodeTypes.CONTROL, - }, - undefined, - ), - techRecord_adrDetails_applicantDetails_name: new CustomFormControl( - { - name: 'techRecord_adrDetails_applicantDetails_name', - type: FormNodeTypes.CONTROL, - hide: false, - groups: ['adr', 'name'], - }, - undefined, - ), - techRecord_adrDetails_applicantDetails_street: new CustomFormControl( - { - name: 'techRecord_adrDetails_applicantDetails_street', - type: FormNodeTypes.CONTROL, - hide: false, - groups: ['adr'], - }, - undefined, - ), - techRecord_adrDetails_applicantDetails_town: new CustomFormControl( - { - name: 'techRecord_adrDetails_applicantDetails_town', - type: FormNodeTypes.CONTROL, - hide: false, - groups: ['adr'], - }, - undefined, - ), - }, - ); - }); - it('should set hide as true on a control if it is in a group included in the array passed and values match true', () => { - const adr = form.get('dangerousGoods'); - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const street = form.get('techRecord_adrDetails_applicantDetails_street') as CustomFormControl; - const town = form.get('techRecord_adrDetails_applicantDetails_town') as CustomFormControl; - - adr?.patchValue(true); - - CustomValidators.hideGroupsWhenEqualTo([true], ['adr'])(adr as AbstractControl); - - expect(name?.meta.hide).toBe(true); - expect(street?.meta.hide).toBe(true); - expect(town?.meta.hide).toBe(true); - }); - it('should set hide as true on a control if it is in a group included in the array passed and values match false', () => { - const adr = form.get('dangerousGoods'); - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const street = form.get('techRecord_adrDetails_applicantDetails_street') as CustomFormControl; - const town = form.get('techRecord_adrDetails_applicantDetails_town') as CustomFormControl; - - adr?.patchValue(false); - - CustomValidators.hideGroupsWhenEqualTo([false], ['adr'])(adr as AbstractControl); - - expect(name?.meta.hide).toBe(true); - expect(street?.meta.hide).toBe(true); - expect(town?.meta.hide).toBe(true); - }); - it('should not change the hide flag if values dont match', () => { - const adr = form.get('dangerousGoods'); - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const street = form.get('techRecord_adrDetails_applicantDetails_street') as CustomFormControl; - const town = form.get('techRecord_adrDetails_applicantDetails_town') as CustomFormControl; - - adr?.patchValue(true); - - CustomValidators.hideGroupsWhenEqualTo([false], ['adr'])(adr as AbstractControl); - - expect(name?.meta.hide).toBe(false); - expect(street?.meta.hide).toBe(false); - expect(town?.meta.hide).toBe(false); - }); - it('should only change hide on groups included in array', () => { - const adr = form.get('dangerousGoods'); - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const street = form.get('techRecord_adrDetails_applicantDetails_street') as CustomFormControl; - const town = form.get('techRecord_adrDetails_applicantDetails_town') as CustomFormControl; - - adr?.patchValue(true); - - CustomValidators.hideGroupsWhenEqualTo([true], ['name'])(adr as AbstractControl); - - expect(name?.meta.hide).toBe(true); - expect(street?.meta.hide).toBe(false); - expect(town?.meta.hide).toBe(false); - }); + let form: CustomFormGroup; + beforeEach(() => { + form = new CustomFormGroup( + { + 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'], + }, + ], + }, + { + dangerousGoods: new CustomFormControl( + { + name: 'dangerousGoods', + type: FormNodeTypes.CONTROL, + }, + undefined + ), + techRecord_adrDetails_applicantDetails_name: new CustomFormControl( + { + name: 'techRecord_adrDetails_applicantDetails_name', + type: FormNodeTypes.CONTROL, + hide: false, + groups: ['adr', 'name'], + }, + undefined + ), + techRecord_adrDetails_applicantDetails_street: new CustomFormControl( + { + name: 'techRecord_adrDetails_applicantDetails_street', + type: FormNodeTypes.CONTROL, + hide: false, + groups: ['adr'], + }, + undefined + ), + techRecord_adrDetails_applicantDetails_town: new CustomFormControl( + { + name: 'techRecord_adrDetails_applicantDetails_town', + type: FormNodeTypes.CONTROL, + hide: false, + groups: ['adr'], + }, + undefined + ), + } + ); + }); + it('should set hide as true on a control if it is in a group included in the array passed and values match true', () => { + const adr = form.get('dangerousGoods'); + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const street = form.get('techRecord_adrDetails_applicantDetails_street') as CustomFormControl; + const town = form.get('techRecord_adrDetails_applicantDetails_town') as CustomFormControl; + + adr?.patchValue(true); + + CustomValidators.hideGroupsWhenEqualTo([true], ['adr'])(adr as AbstractControl); + + expect(name?.meta.hide).toBe(true); + expect(street?.meta.hide).toBe(true); + expect(town?.meta.hide).toBe(true); + }); + it('should set hide as true on a control if it is in a group included in the array passed and values match false', () => { + const adr = form.get('dangerousGoods'); + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const street = form.get('techRecord_adrDetails_applicantDetails_street') as CustomFormControl; + const town = form.get('techRecord_adrDetails_applicantDetails_town') as CustomFormControl; + + adr?.patchValue(false); + + CustomValidators.hideGroupsWhenEqualTo([false], ['adr'])(adr as AbstractControl); + + expect(name?.meta.hide).toBe(true); + expect(street?.meta.hide).toBe(true); + expect(town?.meta.hide).toBe(true); + }); + it('should not change the hide flag if values dont match', () => { + const adr = form.get('dangerousGoods'); + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const street = form.get('techRecord_adrDetails_applicantDetails_street') as CustomFormControl; + const town = form.get('techRecord_adrDetails_applicantDetails_town') as CustomFormControl; + + adr?.patchValue(true); + + CustomValidators.hideGroupsWhenEqualTo([false], ['adr'])(adr as AbstractControl); + + expect(name?.meta.hide).toBe(false); + expect(street?.meta.hide).toBe(false); + expect(town?.meta.hide).toBe(false); + }); + it('should only change hide on groups included in array', () => { + const adr = form.get('dangerousGoods'); + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const street = form.get('techRecord_adrDetails_applicantDetails_street') as CustomFormControl; + const town = form.get('techRecord_adrDetails_applicantDetails_town') as CustomFormControl; + + adr?.patchValue(true); + + CustomValidators.hideGroupsWhenEqualTo([true], ['name'])(adr as AbstractControl); + + expect(name?.meta.hide).toBe(true); + expect(street?.meta.hide).toBe(false); + expect(town?.meta.hide).toBe(false); + }); }); describe('addWarningIfFalse', () => { - let form: CustomFormGroup; - beforeEach(() => { - form = new CustomFormGroup( - { - name: 'form-group', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'dangerousGoods', - value: true, - type: FormNodeTypes.CONTROL, - }, - { - name: 'techRecord_adrDetails_applicantDetails_name', - type: FormNodeTypes.CONTROL, - hide: false, - }, - ], - }, - { - dangerousGoods: new CustomFormControl( - { - name: 'dangerousGoods', - type: FormNodeTypes.CONTROL, - }, - undefined, - ), - techRecord_adrDetails_applicantDetails_name: new CustomFormControl( - { - name: 'techRecord_adrDetails_applicantDetails_name', - type: FormNodeTypes.CONTROL, - hide: false, - }, - undefined, - ), - }, - ); - }); - it('should display a warning if the value is false and it has adr fields on record', () => { - const adr = form.get('dangerousGoods') as CustomFormControl; - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - - name.patchValue('test'); - name.markAsTouched(); - adr.patchValue(false); - adr.markAsDirty(); - - CustomValidators.addWarningForAdrField('Test warning')(adr as AbstractControl); - expect(adr.meta.warning).toBe('Test warning'); - }); - it('should remove the warning if the value true', () => { - const adr = form.get('dangerousGoods') as CustomFormControl; - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - - name.patchValue('test'); - name.markAsTouched(); - adr.patchValue(false); - adr.markAsDirty(); - - CustomValidators.addWarningForAdrField('Test warning')(adr as AbstractControl); - expect(adr.meta.warning).toBe('Test warning'); - - adr?.patchValue(true); - - CustomValidators.addWarningForAdrField('Test warning')(adr as AbstractControl); - expect(adr.meta.warning).toBeUndefined(); - }); - it('should not have a warning if the control is pristine and value is false', () => { - const adr = form.get('dangerousGoods') as CustomFormControl; - - adr.patchValue(false); - - CustomValidators.addWarningForAdrField('Test warning')(adr as AbstractControl); - expect(adr.meta.warning).toBeUndefined(); - }); - it('should not have a warning if the value is false but there is no adr information on the record', () => { - const adr = form.get('dangerousGoods') as CustomFormControl; - - adr.patchValue(false); - adr.markAsDirty(); - - CustomValidators.addWarningForAdrField('Test warning')(adr as AbstractControl); - expect(adr.meta.warning).toBeUndefined(); - }); - it('should not have a warning if the control is pristine and value is true', () => { - const adr = form.get('dangerousGoods') as CustomFormControl; - - adr?.patchValue(true); - - CustomValidators.addWarningForAdrField('Test warning')(adr as AbstractControl); - expect(adr.meta.warning).toBeUndefined(); - }); + let form: CustomFormGroup; + beforeEach(() => { + form = new CustomFormGroup( + { + name: 'form-group', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'dangerousGoods', + value: true, + type: FormNodeTypes.CONTROL, + }, + { + name: 'techRecord_adrDetails_applicantDetails_name', + type: FormNodeTypes.CONTROL, + hide: false, + }, + ], + }, + { + dangerousGoods: new CustomFormControl( + { + name: 'dangerousGoods', + type: FormNodeTypes.CONTROL, + }, + undefined + ), + techRecord_adrDetails_applicantDetails_name: new CustomFormControl( + { + name: 'techRecord_adrDetails_applicantDetails_name', + type: FormNodeTypes.CONTROL, + hide: false, + }, + undefined + ), + } + ); + }); + it('should display a warning if the value is false and it has adr fields on record', () => { + const adr = form.get('dangerousGoods') as CustomFormControl; + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + + name.patchValue('test'); + name.markAsTouched(); + adr.patchValue(false); + adr.markAsDirty(); + + CustomValidators.addWarningForAdrField('Test warning')(adr as AbstractControl); + expect(adr.meta.warning).toBe('Test warning'); + }); + it('should remove the warning if the value true', () => { + const adr = form.get('dangerousGoods') as CustomFormControl; + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + + name.patchValue('test'); + name.markAsTouched(); + adr.patchValue(false); + adr.markAsDirty(); + + CustomValidators.addWarningForAdrField('Test warning')(adr as AbstractControl); + expect(adr.meta.warning).toBe('Test warning'); + + adr?.patchValue(true); + + CustomValidators.addWarningForAdrField('Test warning')(adr as AbstractControl); + expect(adr.meta.warning).toBeUndefined(); + }); + it('should not have a warning if the control is pristine and value is false', () => { + const adr = form.get('dangerousGoods') as CustomFormControl; + + adr.patchValue(false); + + CustomValidators.addWarningForAdrField('Test warning')(adr as AbstractControl); + expect(adr.meta.warning).toBeUndefined(); + }); + it('should not have a warning if the value is false but there is no adr information on the record', () => { + const adr = form.get('dangerousGoods') as CustomFormControl; + + adr.patchValue(false); + adr.markAsDirty(); + + CustomValidators.addWarningForAdrField('Test warning')(adr as AbstractControl); + expect(adr.meta.warning).toBeUndefined(); + }); + it('should not have a warning if the control is pristine and value is true', () => { + const adr = form.get('dangerousGoods') as CustomFormControl; + + adr?.patchValue(true); + + CustomValidators.addWarningForAdrField('Test warning')(adr as AbstractControl); + expect(adr.meta.warning).toBeUndefined(); + }); }); describe('enum', () => { - it.each([ - [{ enum: true }, NaN], - [{ enum: true }, undefined], - [{ enum: true }, null], - [{ enum: true }, ''], - [{ enum: true }, 'Small series'], - [null, 'NTA'], - [null, 'ECTA'], - [null, 'IVA'], - [null, 'NSSTA'], - [null, 'ECSSTA'], - [null, 'GB WVTA'], - [null, 'UKNI WVTA'], - [null, 'EU WVTA Pre 23'], - [null, 'EU WVTA 23 on'], - [null, 'QNIG'], - [null, 'Prov.GB WVTA'], - [null, 'Small series NKSXX'], - [null, 'Small series NKS'], - [null, 'IVA - VCA'], - [null, 'IVA - DVSA/NI'], - ])('should return %p when control value is %s', (expected: object | null, input) => { - expect(CustomValidators.isMemberOfEnum(ApprovalType, { allowFalsy: false })(new FormControl(input))).toEqual(expected); - }); - - it.each([ - [null, NaN], - [null, undefined], - [null, null], - [null, ''], - [{ enum: true }, 'Small series'], - [null, 'NTA'], - [null, 'ECTA'], - [null, 'IVA'], - [null, 'NSSTA'], - [null, 'ECSSTA'], - [null, 'GB WVTA'], - [null, 'UKNI WVTA'], - [null, 'EU WVTA Pre 23'], - [null, 'EU WVTA 23 on'], - [null, 'QNIG'], - [null, 'Prov.GB WVTA'], - [null, 'Small series NKSXX'], - [null, 'Small series NKS'], - [null, 'IVA - VCA'], - [null, 'IVA - DVSA/NI'], - ])('should return %p when control value is %s', (expected: object | null, input) => { - expect(CustomValidators.isMemberOfEnum(ApprovalType, { allowFalsy: true })(new FormControl(input))).toEqual(expected); - }); + it.each([ + [{ enum: true }, Number.NaN], + [{ enum: true }, undefined], + [{ enum: true }, null], + [{ enum: true }, ''], + [{ enum: true }, 'Small series'], + [null, 'NTA'], + [null, 'ECTA'], + [null, 'IVA'], + [null, 'NSSTA'], + [null, 'ECSSTA'], + [null, 'GB WVTA'], + [null, 'UKNI WVTA'], + [null, 'EU WVTA Pre 23'], + [null, 'EU WVTA 23 on'], + [null, 'QNIG'], + [null, 'Prov.GB WVTA'], + [null, 'Small series NKSXX'], + [null, 'Small series NKS'], + [null, 'IVA - VCA'], + [null, 'IVA - DVSA/NI'], + ])('should return %p when control value is %s', (expected: object | null, input) => { + expect(CustomValidators.isMemberOfEnum(ApprovalType, { allowFalsy: false })(new FormControl(input))).toEqual( + expected + ); + }); + + it.each([ + [null, Number.NaN], + [null, undefined], + [null, null], + [null, ''], + [{ enum: true }, 'Small series'], + [null, 'NTA'], + [null, 'ECTA'], + [null, 'IVA'], + [null, 'NSSTA'], + [null, 'ECSSTA'], + [null, 'GB WVTA'], + [null, 'UKNI WVTA'], + [null, 'EU WVTA Pre 23'], + [null, 'EU WVTA 23 on'], + [null, 'QNIG'], + [null, 'Prov.GB WVTA'], + [null, 'Small series NKSXX'], + [null, 'Small series NKS'], + [null, 'IVA - VCA'], + [null, 'IVA - DVSA/NI'], + ])('should return %p when control value is %s', (expected: object | null, input) => { + expect(CustomValidators.isMemberOfEnum(ApprovalType, { allowFalsy: true })(new FormControl(input))).toEqual( + expected + ); + }); }); describe('showGroupsWhenIncludes', () => { - let form: CustomFormGroup; - beforeEach(() => { - form = new CustomFormGroup( - { - 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'], - }, - ], - }, - { - dangerousGoods: new CustomFormControl( - { - name: 'dangerousGoods', - type: FormNodeTypes.CONTROL, - groups: ['adr'], - }, - undefined, - ), - techRecord_adrDetails_applicantDetails_name: new CustomFormControl( - { - name: 'techRecord_adrDetails_applicantDetails_name', - type: FormNodeTypes.CONTROL, - hide: false, - groups: ['adr', 'name'], - }, - undefined, - ), - techRecord_adrDetails_permittedDangerousGoods: new CustomFormControl( - { - name: 'techRecord_adrDetails_permittedDangerousGoods', - type: FormNodeTypes.CONTROL, - hide: false, - groups: ['adr', 'details'], - validators: [ - { - name: ValidatorNames.ShowGroupsWhenIncludes, - args: { - values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], - groups: ['compat'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenExcludes, - args: { - values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], - groups: ['compat'], - }, - }, - ], - }, - undefined, - ), - techRecord_adrDetails_compatibilityGroupJ: new CustomFormControl({ - name: 'techRecord_adrDetails_compatibilityGroupJ', - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['compat', 'details'], - }), - }, - ); - }); - - it('should set hide to FALSE when its value DOES include one of the values passed, and IS part of the group whitelist', () => { - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; - const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; - - permitted?.patchValue([ADRDangerousGood.EXPLOSIVES_TYPE_2]); - permitted?.markAsDirty(); - - CustomValidators.showGroupsWhenIncludes([ADRDangerousGood.EXPLOSIVES_TYPE_2], ['compat'])(permitted as AbstractControl); - - expect(name?.meta.hide).toBe(false); - expect(compat?.meta.hide).toBe(false); - }); - - it('should NOT set hide to FALSE when its value DOES include one of the values passed, but is NOT part of the group whitelist', () => { - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; - const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; - - permitted?.patchValue(['I']); - permitted?.markAsDirty(); - - CustomValidators.showGroupsWhenIncludes(['I'], ['random_group', 'other_random_group'])(permitted as AbstractControl); - - expect(name?.meta.hide).toBe(false); - expect(compat?.meta.hide).toBe(true); - }); - - it('should NOT set hide to FALSE when its value DOES NOT include one of the values passed, but IS part of the group whitelist', () => { - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; - const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; - - permitted?.patchValue(['E']); - permitted?.markAsDirty(); - - CustomValidators.showGroupsWhenIncludes(['I'], ['compat', 'other_random_group'])(permitted as AbstractControl); - - expect(name?.meta.hide).toBe(false); - expect(compat?.meta.hide).toBe(true); - }); + let form: CustomFormGroup; + beforeEach(() => { + form = new CustomFormGroup( + { + 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'], + }, + ], + }, + { + dangerousGoods: new CustomFormControl( + { + name: 'dangerousGoods', + type: FormNodeTypes.CONTROL, + groups: ['adr'], + }, + undefined + ), + techRecord_adrDetails_applicantDetails_name: new CustomFormControl( + { + name: 'techRecord_adrDetails_applicantDetails_name', + type: FormNodeTypes.CONTROL, + hide: false, + groups: ['adr', 'name'], + }, + undefined + ), + techRecord_adrDetails_permittedDangerousGoods: new CustomFormControl( + { + name: 'techRecord_adrDetails_permittedDangerousGoods', + type: FormNodeTypes.CONTROL, + hide: false, + groups: ['adr', 'details'], + validators: [ + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], + groups: ['compat'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], + groups: ['compat'], + }, + }, + ], + }, + undefined + ), + techRecord_adrDetails_compatibilityGroupJ: new CustomFormControl({ + name: 'techRecord_adrDetails_compatibilityGroupJ', + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['compat', 'details'], + }), + } + ); + }); + + it('should set hide to FALSE when its value DOES include one of the values passed, and IS part of the group whitelist', () => { + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; + const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; + + permitted?.patchValue([ADRDangerousGood.EXPLOSIVES_TYPE_2]); + permitted?.markAsDirty(); + + CustomValidators.showGroupsWhenIncludes( + [ADRDangerousGood.EXPLOSIVES_TYPE_2], + ['compat'] + )(permitted as AbstractControl); + + expect(name?.meta.hide).toBe(false); + expect(compat?.meta.hide).toBe(false); + }); + + it('should NOT set hide to FALSE when its value DOES include one of the values passed, but is NOT part of the group whitelist', () => { + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; + const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; + + permitted?.patchValue(['I']); + permitted?.markAsDirty(); + + CustomValidators.showGroupsWhenIncludes( + ['I'], + ['random_group', 'other_random_group'] + )(permitted as AbstractControl); + + expect(name?.meta.hide).toBe(false); + expect(compat?.meta.hide).toBe(true); + }); + + it('should NOT set hide to FALSE when its value DOES NOT include one of the values passed, but IS part of the group whitelist', () => { + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; + const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; + + permitted?.patchValue(['E']); + permitted?.markAsDirty(); + + CustomValidators.showGroupsWhenIncludes(['I'], ['compat', 'other_random_group'])(permitted as AbstractControl); + + expect(name?.meta.hide).toBe(false); + expect(compat?.meta.hide).toBe(true); + }); }); describe('hideGroupsWhenIncludes', () => { - let form: CustomFormGroup; - beforeEach(() => { - form = new CustomFormGroup( - { - 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'], - }, - ], - }, - { - dangerousGoods: new CustomFormControl( - { - name: 'dangerousGoods', - type: FormNodeTypes.CONTROL, - groups: ['adr'], - }, - undefined, - ), - techRecord_adrDetails_applicantDetails_name: new CustomFormControl( - { - name: 'techRecord_adrDetails_applicantDetails_name', - type: FormNodeTypes.CONTROL, - hide: false, - groups: ['adr', 'name'], - }, - undefined, - ), - techRecord_adrDetails_permittedDangerousGoods: new CustomFormControl( - { - name: 'techRecord_adrDetails_permittedDangerousGoods', - type: FormNodeTypes.CONTROL, - hide: false, - groups: ['adr', 'details'], - validators: [ - { - name: ValidatorNames.ShowGroupsWhenIncludes, - args: { - values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], - groups: ['compat'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenExcludes, - args: { - values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], - groups: ['compat'], - }, - }, - ], - }, - undefined, - ), - techRecord_adrDetails_compatibilityGroupJ: new CustomFormControl({ - name: 'techRecord_adrDetails_compatibilityGroupJ', - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['compat', 'details'], - }), - }, - ); - }); - it('should set hide to TRUE when its value DOES include one of the values passed, and IS part of the group whitelist', () => { - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; - const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; - - permitted?.patchValue([ADRDangerousGood.EXPLOSIVES_TYPE_2]); - permitted?.markAsDirty(); - - CustomValidators.hideGroupsWhenIncludes([ADRDangerousGood.EXPLOSIVES_TYPE_2], ['compat'])(permitted as AbstractControl); - - expect(name?.meta.hide).toBe(false); - expect(compat?.meta.hide).toBe(true); - }); - - it('should NOT set hide to TRUE when its value DOES include one of the values passed, but is NOT part of the group whitelist', () => { - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; - const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; - compat.meta.hide = false; - - permitted?.patchValue([ADRDangerousGood.EXPLOSIVES_TYPE_2]); - permitted?.markAsDirty(); - - CustomValidators.hideGroupsWhenEqualTo([ADRDangerousGood.EXPLOSIVES_TYPE_2], ['compat', 'other_random_group'])(permitted as AbstractControl); - - expect(name?.meta.hide).toBe(false); - expect(compat?.meta.hide).toBe(false); - }); - - it('should NOT set hide to TRUE when its value DOES NOT include one of the values passed, but IS part of the group whitelist', () => { - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; - const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; - compat.meta.hide = false; - - permitted?.patchValue(['E']); - permitted?.markAsDirty(); - - CustomValidators.hideGroupsWhenIncludes(['I'], ['compat', 'other_random_group'])(permitted as AbstractControl); - - expect(name?.meta.hide).toBe(false); - expect(compat?.meta.hide).toBe(false); - }); + let form: CustomFormGroup; + beforeEach(() => { + form = new CustomFormGroup( + { + 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'], + }, + ], + }, + { + dangerousGoods: new CustomFormControl( + { + name: 'dangerousGoods', + type: FormNodeTypes.CONTROL, + groups: ['adr'], + }, + undefined + ), + techRecord_adrDetails_applicantDetails_name: new CustomFormControl( + { + name: 'techRecord_adrDetails_applicantDetails_name', + type: FormNodeTypes.CONTROL, + hide: false, + groups: ['adr', 'name'], + }, + undefined + ), + techRecord_adrDetails_permittedDangerousGoods: new CustomFormControl( + { + name: 'techRecord_adrDetails_permittedDangerousGoods', + type: FormNodeTypes.CONTROL, + hide: false, + groups: ['adr', 'details'], + validators: [ + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], + groups: ['compat'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], + groups: ['compat'], + }, + }, + ], + }, + undefined + ), + techRecord_adrDetails_compatibilityGroupJ: new CustomFormControl({ + name: 'techRecord_adrDetails_compatibilityGroupJ', + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['compat', 'details'], + }), + } + ); + }); + it('should set hide to TRUE when its value DOES include one of the values passed, and IS part of the group whitelist', () => { + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; + const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; + + permitted?.patchValue([ADRDangerousGood.EXPLOSIVES_TYPE_2]); + permitted?.markAsDirty(); + + CustomValidators.hideGroupsWhenIncludes( + [ADRDangerousGood.EXPLOSIVES_TYPE_2], + ['compat'] + )(permitted as AbstractControl); + + expect(name?.meta.hide).toBe(false); + expect(compat?.meta.hide).toBe(true); + }); + + it('should NOT set hide to TRUE when its value DOES include one of the values passed, but is NOT part of the group whitelist', () => { + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; + const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; + compat.meta.hide = false; + + permitted?.patchValue([ADRDangerousGood.EXPLOSIVES_TYPE_2]); + permitted?.markAsDirty(); + + CustomValidators.hideGroupsWhenEqualTo( + [ADRDangerousGood.EXPLOSIVES_TYPE_2], + ['compat', 'other_random_group'] + )(permitted as AbstractControl); + + expect(name?.meta.hide).toBe(false); + expect(compat?.meta.hide).toBe(false); + }); + + it('should NOT set hide to TRUE when its value DOES NOT include one of the values passed, but IS part of the group whitelist', () => { + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; + const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; + compat.meta.hide = false; + + permitted?.patchValue(['E']); + permitted?.markAsDirty(); + + CustomValidators.hideGroupsWhenIncludes(['I'], ['compat', 'other_random_group'])(permitted as AbstractControl); + + expect(name?.meta.hide).toBe(false); + expect(compat?.meta.hide).toBe(false); + }); }); describe('showGroupsWhenExcludes', () => { - let form: CustomFormGroup; - beforeEach(() => { - form = new CustomFormGroup( - { - 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'], - }, - ], - }, - { - dangerousGoods: new CustomFormControl( - { - name: 'dangerousGoods', - type: FormNodeTypes.CONTROL, - groups: ['adr'], - }, - undefined, - ), - techRecord_adrDetails_applicantDetails_name: new CustomFormControl( - { - name: 'techRecord_adrDetails_applicantDetails_name', - type: FormNodeTypes.CONTROL, - hide: false, - groups: ['adr', 'name'], - }, - undefined, - ), - techRecord_adrDetails_permittedDangerousGoods: new CustomFormControl( - { - name: 'techRecord_adrDetails_permittedDangerousGoods', - type: FormNodeTypes.CONTROL, - hide: false, - groups: ['adr', 'details'], - validators: [ - { - name: ValidatorNames.ShowGroupsWhenIncludes, - args: { - values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], - groups: ['compat'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenExcludes, - args: { - values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], - groups: ['compat'], - }, - }, - ], - }, - undefined, - ), - techRecord_adrDetails_compatibilityGroupJ: new CustomFormControl({ - name: 'techRecord_adrDetails_compatibilityGroupJ', - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['compat', 'details'], - }), - }, - ); - }); - it('should set hide to FALSE when its value DOES NOT include one of the values passed, and IS part of the group whitelist', () => { - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; - const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; - - permitted?.patchValue([ADRDangerousGood.CARBON_DISULPHIDE]); - permitted?.markAsDirty(); - - CustomValidators.showGroupsWhenExcludes([ADRDangerousGood.EXPLOSIVES_TYPE_2], ['compat'])(permitted as AbstractControl); - - expect(name?.meta.hide).toBe(false); - expect(compat?.meta.hide).toBe(false); - }); - - it('should NOT set hide to FALSE when its value DOES NOT include one of the values passed, but is NOT part of the group whitelist', () => { - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; - const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; - - permitted?.patchValue([ADRDangerousGood.CARBON_DISULPHIDE]); - permitted?.markAsDirty(); - - CustomValidators.showGroupsWhenExcludes([ADRDangerousGood.EXPLOSIVES_TYPE_2], ['other_group'])(permitted as AbstractControl); - - expect(name?.meta.hide).toBe(false); - expect(compat?.meta.hide).toBe(true); - }); - - it('should NOT set hide to FALSE when its value DOES include one of the values passed, but IS part of the group whitelist', () => { - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; - const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; - - permitted?.patchValue([ADRDangerousGood.EXPLOSIVES_TYPE_2]); - permitted?.markAsDirty(); - - CustomValidators.showGroupsWhenExcludes([ADRDangerousGood.EXPLOSIVES_TYPE_2], ['compat'])(permitted as AbstractControl); - - expect(name?.meta.hide).toBe(false); - expect(compat?.meta.hide).toBe(true); - }); + let form: CustomFormGroup; + beforeEach(() => { + form = new CustomFormGroup( + { + 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'], + }, + ], + }, + { + dangerousGoods: new CustomFormControl( + { + name: 'dangerousGoods', + type: FormNodeTypes.CONTROL, + groups: ['adr'], + }, + undefined + ), + techRecord_adrDetails_applicantDetails_name: new CustomFormControl( + { + name: 'techRecord_adrDetails_applicantDetails_name', + type: FormNodeTypes.CONTROL, + hide: false, + groups: ['adr', 'name'], + }, + undefined + ), + techRecord_adrDetails_permittedDangerousGoods: new CustomFormControl( + { + name: 'techRecord_adrDetails_permittedDangerousGoods', + type: FormNodeTypes.CONTROL, + hide: false, + groups: ['adr', 'details'], + validators: [ + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], + groups: ['compat'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], + groups: ['compat'], + }, + }, + ], + }, + undefined + ), + techRecord_adrDetails_compatibilityGroupJ: new CustomFormControl({ + name: 'techRecord_adrDetails_compatibilityGroupJ', + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['compat', 'details'], + }), + } + ); + }); + it('should set hide to FALSE when its value DOES NOT include one of the values passed, and IS part of the group whitelist', () => { + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; + const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; + + permitted?.patchValue([ADRDangerousGood.CARBON_DISULPHIDE]); + permitted?.markAsDirty(); + + CustomValidators.showGroupsWhenExcludes( + [ADRDangerousGood.EXPLOSIVES_TYPE_2], + ['compat'] + )(permitted as AbstractControl); + + expect(name?.meta.hide).toBe(false); + expect(compat?.meta.hide).toBe(false); + }); + + it('should NOT set hide to FALSE when its value DOES NOT include one of the values passed, but is NOT part of the group whitelist', () => { + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; + const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; + + permitted?.patchValue([ADRDangerousGood.CARBON_DISULPHIDE]); + permitted?.markAsDirty(); + + CustomValidators.showGroupsWhenExcludes( + [ADRDangerousGood.EXPLOSIVES_TYPE_2], + ['other_group'] + )(permitted as AbstractControl); + + expect(name?.meta.hide).toBe(false); + expect(compat?.meta.hide).toBe(true); + }); + + it('should NOT set hide to FALSE when its value DOES include one of the values passed, but IS part of the group whitelist', () => { + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; + const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; + + permitted?.patchValue([ADRDangerousGood.EXPLOSIVES_TYPE_2]); + permitted?.markAsDirty(); + + CustomValidators.showGroupsWhenExcludes( + [ADRDangerousGood.EXPLOSIVES_TYPE_2], + ['compat'] + )(permitted as AbstractControl); + + expect(name?.meta.hide).toBe(false); + expect(compat?.meta.hide).toBe(true); + }); }); describe('hideGroupsWhenExcludes', () => { - let form: CustomFormGroup; - beforeEach(() => { - form = new CustomFormGroup( - { - 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'], - }, - ], - }, - { - dangerousGoods: new CustomFormControl( - { - name: 'dangerousGoods', - type: FormNodeTypes.CONTROL, - groups: ['adr'], - }, - undefined, - ), - techRecord_adrDetails_applicantDetails_name: new CustomFormControl( - { - name: 'techRecord_adrDetails_applicantDetails_name', - type: FormNodeTypes.CONTROL, - hide: false, - groups: ['adr', 'name'], - }, - undefined, - ), - techRecord_adrDetails_permittedDangerousGoods: new CustomFormControl( - { - name: 'techRecord_adrDetails_permittedDangerousGoods', - type: FormNodeTypes.CONTROL, - hide: false, - groups: ['adr', 'details'], - validators: [ - { - name: ValidatorNames.ShowGroupsWhenIncludes, - args: { - values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], - groups: ['compat'], - }, - }, - { - name: ValidatorNames.HideGroupsWhenExcludes, - args: { - values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], - groups: ['compat'], - }, - }, - ], - }, - undefined, - ), - techRecord_adrDetails_compatibilityGroupJ: new CustomFormControl({ - name: 'techRecord_adrDetails_compatibilityGroupJ', - type: FormNodeTypes.CONTROL, - hide: true, - groups: ['compat', 'details'], - }), - }, - ); - }); - it('should set hide to TRUE when its value DOES NOT include one of the values passed, and IS part of the group whitelist', () => { - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; - const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; - compat.meta.hide = false; - - permitted?.patchValue([ADRDangerousGood.CARBON_DISULPHIDE]); - permitted?.markAsDirty(); - - CustomValidators.hideGroupsWhenExcludes([ADRDangerousGood.EXPLOSIVES_TYPE_2], ['compat'])(permitted as AbstractControl); - - expect(name?.meta.hide).toBe(false); - expect(compat?.meta.hide).toBe(true); - }); - - it('should NOT set hide to TRUE when its value DOES NOT include one of the values passed, but is NOT part of the group whitelist', () => { - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; - const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; - compat.meta.hide = false; - - permitted?.patchValue([ADRDangerousGood.CARBON_DISULPHIDE]); - permitted?.markAsDirty(); - - CustomValidators.hideGroupsWhenExcludes([ADRDangerousGood.EXPLOSIVES_TYPE_2], ['other_group'])(permitted as AbstractControl); - - expect(name?.meta.hide).toBe(false); - expect(compat?.meta.hide).toBe(false); - }); - - it('should NOT set hide to TRUE when its value DOES include one of the values passed, but IS part of the group whitelist', () => { - const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; - const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; - const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; - compat.meta.hide = false; - - permitted?.patchValue([ADRDangerousGood.EXPLOSIVES_TYPE_2]); - permitted?.markAsDirty(); - - CustomValidators.hideGroupsWhenExcludes([ADRDangerousGood.EXPLOSIVES_TYPE_2], ['compat'])(permitted as AbstractControl); - - expect(name?.meta.hide).toBe(false); - expect(compat?.meta.hide).toBe(false); - }); + let form: CustomFormGroup; + beforeEach(() => { + form = new CustomFormGroup( + { + 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'], + }, + ], + }, + { + dangerousGoods: new CustomFormControl( + { + name: 'dangerousGoods', + type: FormNodeTypes.CONTROL, + groups: ['adr'], + }, + undefined + ), + techRecord_adrDetails_applicantDetails_name: new CustomFormControl( + { + name: 'techRecord_adrDetails_applicantDetails_name', + type: FormNodeTypes.CONTROL, + hide: false, + groups: ['adr', 'name'], + }, + undefined + ), + techRecord_adrDetails_permittedDangerousGoods: new CustomFormControl( + { + name: 'techRecord_adrDetails_permittedDangerousGoods', + type: FormNodeTypes.CONTROL, + hide: false, + groups: ['adr', 'details'], + validators: [ + { + name: ValidatorNames.ShowGroupsWhenIncludes, + args: { + values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], + groups: ['compat'], + }, + }, + { + name: ValidatorNames.HideGroupsWhenExcludes, + args: { + values: [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3], + groups: ['compat'], + }, + }, + ], + }, + undefined + ), + techRecord_adrDetails_compatibilityGroupJ: new CustomFormControl({ + name: 'techRecord_adrDetails_compatibilityGroupJ', + type: FormNodeTypes.CONTROL, + hide: true, + groups: ['compat', 'details'], + }), + } + ); + }); + it('should set hide to TRUE when its value DOES NOT include one of the values passed, and IS part of the group whitelist', () => { + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; + const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; + compat.meta.hide = false; + + permitted?.patchValue([ADRDangerousGood.CARBON_DISULPHIDE]); + permitted?.markAsDirty(); + + CustomValidators.hideGroupsWhenExcludes( + [ADRDangerousGood.EXPLOSIVES_TYPE_2], + ['compat'] + )(permitted as AbstractControl); + + expect(name?.meta.hide).toBe(false); + expect(compat?.meta.hide).toBe(true); + }); + + it('should NOT set hide to TRUE when its value DOES NOT include one of the values passed, but is NOT part of the group whitelist', () => { + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; + const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; + compat.meta.hide = false; + + permitted?.patchValue([ADRDangerousGood.CARBON_DISULPHIDE]); + permitted?.markAsDirty(); + + CustomValidators.hideGroupsWhenExcludes( + [ADRDangerousGood.EXPLOSIVES_TYPE_2], + ['other_group'] + )(permitted as AbstractControl); + + expect(name?.meta.hide).toBe(false); + expect(compat?.meta.hide).toBe(false); + }); + + it('should NOT set hide to TRUE when its value DOES include one of the values passed, but IS part of the group whitelist', () => { + const name = form.get('techRecord_adrDetails_applicantDetails_name') as CustomFormControl; + const permitted = form.get('techRecord_adrDetails_permittedDangerousGoods') as CustomFormControl; + const compat = form.get('techRecord_adrDetails_compatibilityGroupJ') as CustomFormControl; + compat.meta.hide = false; + + permitted?.patchValue([ADRDangerousGood.EXPLOSIVES_TYPE_2]); + permitted?.markAsDirty(); + + CustomValidators.hideGroupsWhenExcludes( + [ADRDangerousGood.EXPLOSIVES_TYPE_2], + ['compat'] + )(permitted as AbstractControl); + + expect(name?.meta.hide).toBe(false); + expect(compat?.meta.hide).toBe(false); + }); }); describe('isArray', () => { - let form: CustomFormGroup; - beforeEach(() => { - form = new CustomFormGroup( - { - name: 'form-group', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'techRecord_adrDetails_additionalNotes_number', - type: FormNodeTypes.CONTROL, - value: [], - }, - ], - }, - { - techRecord_adrDetails_additionalNotes_number: new CustomFormControl( - { - name: 'techRecord_adrDetails_additionalNotes_number', - type: FormNodeTypes.CONTROL, - }, - undefined, - ), - }, - ); - }); - - it('should NOT mark additional notes as INVALID when its value IS an ARRAY', () => { - const control = form.get('techRecord_adrDetails_additionalNotes_number') as CustomFormControl; - control.patchValue([]); - - expect(CustomValidators.isArray()(control)).toBeNull(); - }); - - it('should mark additional notes as INVALID when its values is NOT an ARRAY', () => { - const control = form.get('techRecord_adrDetails_additionalNotes_number') as CustomFormControl; - control.patchValue('not an array'); - - expect(CustomValidators.isArray()(control)).toBeTruthy(); - }); - - it('should NOT mark additional notes as INVALID when its value is an ARRAY of type provided in the ofType argument', () => { - const control = form.get('techRecord_adrDetails_additionalNotes_number') as CustomFormControl; - control.patchValue(['1 string', '2 string']); - expect(CustomValidators.isArray({ ofType: 'string' })(control)).toBeNull(); - - control.patchValue([1, 2, 3]); - expect(CustomValidators.isArray({ ofType: 'number' })(control)).toBeNull(); - - // apparently null is object type in JS - control.patchValue([null, null, null]); - expect(CustomValidators.isArray({ ofType: 'object' })(control)).toBeNull(); - - control.patchValue([undefined, undefined, undefined]); - expect(CustomValidators.isArray({ ofType: 'undefined' })(control)).toBeNull(); - }); - - it('should mark additional notes as INVALID when its value is an ARRAY but not of the type provided in the ofType argument', () => { - const control = form.get('techRecord_adrDetails_additionalNotes_number') as CustomFormControl; - control.patchValue(['1 string', '2 string']); - expect(CustomValidators.isArray({ ofType: 'number' })(control)).toBeTruthy(); - - control.patchValue([1, 2, 3]); - expect(CustomValidators.isArray({ ofType: 'undefined' })(control)).toBeTruthy(); - - control.patchValue([null, null, null]); - expect(CustomValidators.isArray({ ofType: 'string' })(control)).toBeTruthy(); - - control.patchValue([undefined, undefined, undefined]); - expect(CustomValidators.isArray({ ofType: 'object' })(control)).toBeTruthy(); - }); - - it('should NOT mark additional notes as INVALID when its value is an ARRAY and ALL of the values at indices in requiredIndices are truthy', () => { - const control = form.get('techRecord_adrDetails_additionalNotes_number') as CustomFormControl; - control.patchValue(['1 string', '2 string']); - - expect(CustomValidators.isArray({ requiredIndices: [1] })(control)).toBeNull(); - }); - - it('should mark additional notes as INVALID when its value is an ARRAY but AT LEAST ONE of its values at requiredIndices is falsy', () => { - const control = form.get('techRecord_adrDetails_additionalNotes_number') as CustomFormControl; - control.patchValue([null, '2 string']); - - expect(CustomValidators.isArray({ requiredIndices: [0] })(control)).toBeTruthy(); - }); + let form: CustomFormGroup; + beforeEach(() => { + form = new CustomFormGroup( + { + name: 'form-group', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'techRecord_adrDetails_additionalNotes_number', + type: FormNodeTypes.CONTROL, + value: [], + }, + ], + }, + { + techRecord_adrDetails_additionalNotes_number: new CustomFormControl( + { + name: 'techRecord_adrDetails_additionalNotes_number', + type: FormNodeTypes.CONTROL, + }, + undefined + ), + } + ); + }); + + it('should NOT mark additional notes as INVALID when its value IS an ARRAY', () => { + const control = form.get('techRecord_adrDetails_additionalNotes_number') as CustomFormControl; + control.patchValue([]); + + expect(CustomValidators.isArray()(control)).toBeNull(); + }); + + it('should mark additional notes as INVALID when its values is NOT an ARRAY', () => { + const control = form.get('techRecord_adrDetails_additionalNotes_number') as CustomFormControl; + control.patchValue('not an array'); + + expect(CustomValidators.isArray()(control)).toBeTruthy(); + }); + + it('should NOT mark additional notes as INVALID when its value is an ARRAY of type provided in the ofType argument', () => { + const control = form.get('techRecord_adrDetails_additionalNotes_number') as CustomFormControl; + control.patchValue(['1 string', '2 string']); + expect(CustomValidators.isArray({ ofType: 'string' })(control)).toBeNull(); + + control.patchValue([1, 2, 3]); + expect(CustomValidators.isArray({ ofType: 'number' })(control)).toBeNull(); + + // apparently null is object type in JS + control.patchValue([null, null, null]); + expect(CustomValidators.isArray({ ofType: 'object' })(control)).toBeNull(); + + control.patchValue([undefined, undefined, undefined]); + expect(CustomValidators.isArray({ ofType: 'undefined' })(control)).toBeNull(); + }); + + it('should mark additional notes as INVALID when its value is an ARRAY but not of the type provided in the ofType argument', () => { + const control = form.get('techRecord_adrDetails_additionalNotes_number') as CustomFormControl; + control.patchValue(['1 string', '2 string']); + expect(CustomValidators.isArray({ ofType: 'number' })(control)).toBeTruthy(); + + control.patchValue([1, 2, 3]); + expect(CustomValidators.isArray({ ofType: 'undefined' })(control)).toBeTruthy(); + + control.patchValue([null, null, null]); + expect(CustomValidators.isArray({ ofType: 'string' })(control)).toBeTruthy(); + + control.patchValue([undefined, undefined, undefined]); + expect(CustomValidators.isArray({ ofType: 'object' })(control)).toBeTruthy(); + }); + + it('should NOT mark additional notes as INVALID when its value is an ARRAY and ALL of the values at indices in requiredIndices are truthy', () => { + const control = form.get('techRecord_adrDetails_additionalNotes_number') as CustomFormControl; + control.patchValue(['1 string', '2 string']); + + expect(CustomValidators.isArray({ requiredIndices: [1] })(control)).toBeNull(); + }); + + it('should mark additional notes as INVALID when its value is an ARRAY but AT LEAST ONE of its values at requiredIndices is falsy', () => { + const control = form.get('techRecord_adrDetails_additionalNotes_number') as CustomFormControl; + control.patchValue([null, '2 string']); + + expect(CustomValidators.isArray({ requiredIndices: [0] })(control)).toBeTruthy(); + }); }); 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({ - 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); - - 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; - const date = form.get('tc3PeriodicExpiryDate') as CustomFormControl; - const number = form.get('tc3PeriodicNumber') as CustomFormControl; - - type.patchValue(undefined); - date.patchValue(undefined); - number.patchValue(undefined); - - 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', - }, - }); - }); - it('should give an error if fields passed to the validator are empty strings', () => { - const type = form.get('tc3Type') as CustomFormControl; - const date = form.get('tc3PeriodicExpiryDate') as CustomFormControl; - const number = form.get('tc3PeriodicNumber') as CustomFormControl; - - type.patchValue(''); - date.patchValue(''); - number.patchValue(''); - - 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', - }, - }); - }); - it('should give an error if fields to the validator have a variety of empty values', () => { - const type = form.get('tc3Type') as CustomFormControl; - const date = form.get('tc3PeriodicExpiryDate') as CustomFormControl; - const number = form.get('tc3PeriodicNumber') as CustomFormControl; - - type.patchValue(''); - date.patchValue(null); - number.patchValue(undefined); - - 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', - }, - }); - }); - it('should return null if one field passed to the validator has a value', () => { - const type = form.get('tc3Type') as CustomFormControl; - const number = form.get('tc3PeriodicNumber') as CustomFormControl; - - number.patchValue('test'); - - const validator = CustomValidators.tc3TestValidator({ - inspectionNumber: 1, - })(type as AbstractControl); - - expect(validator).toBeNull(); - }); + 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({ + 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); + + 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; + const date = form.get('tc3PeriodicExpiryDate') as CustomFormControl; + const number = form.get('tc3PeriodicNumber') as CustomFormControl; + + type.patchValue(undefined); + date.patchValue(undefined); + number.patchValue(undefined); + + 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', + }, + }); + }); + it('should give an error if fields passed to the validator are empty strings', () => { + const type = form.get('tc3Type') as CustomFormControl; + const date = form.get('tc3PeriodicExpiryDate') as CustomFormControl; + const number = form.get('tc3PeriodicNumber') as CustomFormControl; + + type.patchValue(''); + date.patchValue(''); + number.patchValue(''); + + 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', + }, + }); + }); + it('should give an error if fields to the validator have a variety of empty values', () => { + const type = form.get('tc3Type') as CustomFormControl; + const date = form.get('tc3PeriodicExpiryDate') as CustomFormControl; + const number = form.get('tc3PeriodicNumber') as CustomFormControl; + + type.patchValue(''); + date.patchValue(null); + number.patchValue(undefined); + + 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', + }, + }); + }); + it('should return null if one field passed to the validator has a value', () => { + const type = form.get('tc3Type') as CustomFormControl; + const number = form.get('tc3PeriodicNumber') as CustomFormControl; + + number.patchValue('test'); + + const validator = CustomValidators.tc3TestValidator({ + inspectionNumber: 1, + })(type as AbstractControl); + + expect(validator).toBeNull(); + }); }); 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({ - 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; - - details.patchValue([{ tc3Type: null, tc3PeriodicNumber: null, tc3PeriodicExpiryDate: null }]); - - 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', - }, - }); - }); - it('should give an error if fields passed to the validator are undefined', () => { - const details = form.get('techRecord_adrDetails_tank_tankDetails_tc3Details') as CustomFormControl; - - details.patchValue([{ tc3Type: undefined, tc3PeriodicNumber: undefined, tc3PeriodicExpiryDate: undefined }]); - - 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', - }, - }); - }); - 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; - - details.patchValue([{ tc3Type: '', tc3PeriodicNumber: '', tc3PeriodicExpiryDate: '' }]); - - 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', - }, - }); - }); - 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; - - details.patchValue([{ tc3Type: null, tc3PeriodicNumber: undefined, tc3PeriodicExpiryDate: '' }]); - - 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', - }, - }); - }); - it('should tell you which test needs to be filled out', () => { - const details = form.get('techRecord_adrDetails_tank_tankDetails_tc3Details') as CustomFormControl; - - details.patchValue([ - { tc3Type: null, tc3PeriodicNumber: 'test', tc3PeriodicExpiryDate: '' }, - { tc3Type: null, tc3PeriodicNumber: undefined, tc3PeriodicExpiryDate: '' }, - { tc3Type: null, tc3PeriodicNumber: 'test', tc3PeriodicExpiryDate: '' }, - ]); - - 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', - }, - }); - }); - 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; - - details.patchValue([ - { tc3Type: null, tc3PeriodicNumber: 'test', tc3PeriodicExpiryDate: '' }, - { tc3Type: null, tc3PeriodicNumber: undefined, tc3PeriodicExpiryDate: '' }, - { tc3Type: null, tc3PeriodicNumber: 'test', tc3PeriodicExpiryDate: '' }, - { tc3Type: null, tc3PeriodicNumber: '', tc3PeriodicExpiryDate: '' }, - { tc3Type: null, tc3PeriodicNumber: '', tc3PeriodicExpiryDate: '' }, - ]); - - 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', - }, - }); - }); - 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; - - details.patchValue([{ tc3Type: 'test', tc3PeriodicNumber: null, tc3PeriodicExpiryDate: null }]); - const validator = CustomValidators.tc3TestValidator({ inspectionNumber: 0 })(details as AbstractControl); - - expect(validator).toBeNull(); - }); - - describe('dateIsValid', () => { - it.each([ - [{ dateIsInvalid: { message: '\'Date\' day must be a number' } }, null], - [{ dateIsInvalid: { message: '\'Date\' day must be a number' } }, undefined], - [{ dateIsInvalid: { message: '\'Date\' day must be a number' } }, ''], - [{ dateIsInvalid: { message: '\'Date\' day must be a number' } }, '---'], - [{ dateIsInvalid: { message: '\'Date\' day must be a number' } }, '2000--'], - [{ dateIsInvalid: { message: '\'Date\' day must be a number' } }, '2000-12-'], - [{ dateIsInvalid: { message: '\'Date\' day must be a number' } }, '2000-12-A'], - [null, '2000-12-01'], - [null, '2000-12-11'], - [null, '2000-12-31'], - [{ dateIsInvalid: { message: '\'Date\' month must be a number' } }, '2000--11'], - [{ dateIsInvalid: { message: '\'Date\' month must be a number' } }, '2000-C-11'], - [{ dateIsInvalid: { message: '\'Date\' month must be between 1 and 12' } }, '2000-31-11'], - [{ dateIsInvalid: { message: '\'Date\' month must be between 1 and 12' } }, '2000-00-11'], - [{ dateIsInvalid: { message: '\'Date\' year must be a number' } }, '-12-11'], - [{ dateIsInvalid: { message: '\'Date\' year must be a number' } }, 'C-12-11'], - - [null, '2020-02-29'], - [{ dateIsInvalid: { message: '\'Date\' day must be between 1 and 28 in the month of February' } }, '2019-02-29'], - ])('should return %p when control value is %s', (expected: object | null, input) => { - expect(CustomValidators.dateIsInvalid(new FormControl(input))).toEqual(expected); - }); - }); + 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({ + 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; + + details.patchValue([{ tc3Type: null, tc3PeriodicNumber: null, tc3PeriodicExpiryDate: null }]); + + 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', + }, + }); + }); + it('should give an error if fields passed to the validator are undefined', () => { + const details = form.get('techRecord_adrDetails_tank_tankDetails_tc3Details') as CustomFormControl; + + details.patchValue([{ tc3Type: undefined, tc3PeriodicNumber: undefined, tc3PeriodicExpiryDate: undefined }]); + + 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', + }, + }); + }); + 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; + + details.patchValue([{ tc3Type: '', tc3PeriodicNumber: '', tc3PeriodicExpiryDate: '' }]); + + 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', + }, + }); + }); + 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; + + details.patchValue([{ tc3Type: null, tc3PeriodicNumber: undefined, tc3PeriodicExpiryDate: '' }]); + + 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', + }, + }); + }); + it('should tell you which test needs to be filled out', () => { + const details = form.get('techRecord_adrDetails_tank_tankDetails_tc3Details') as CustomFormControl; + + details.patchValue([ + { tc3Type: null, tc3PeriodicNumber: 'test', tc3PeriodicExpiryDate: '' }, + { tc3Type: null, tc3PeriodicNumber: undefined, tc3PeriodicExpiryDate: '' }, + { tc3Type: null, tc3PeriodicNumber: 'test', tc3PeriodicExpiryDate: '' }, + ]); + + 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', + }, + }); + }); + 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; + + details.patchValue([ + { tc3Type: null, tc3PeriodicNumber: 'test', tc3PeriodicExpiryDate: '' }, + { tc3Type: null, tc3PeriodicNumber: undefined, tc3PeriodicExpiryDate: '' }, + { tc3Type: null, tc3PeriodicNumber: 'test', tc3PeriodicExpiryDate: '' }, + { tc3Type: null, tc3PeriodicNumber: '', tc3PeriodicExpiryDate: '' }, + { tc3Type: null, tc3PeriodicNumber: '', tc3PeriodicExpiryDate: '' }, + ]); + + 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', + }, + }); + }); + 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; + + details.patchValue([{ tc3Type: 'test', tc3PeriodicNumber: null, tc3PeriodicExpiryDate: null }]); + const validator = CustomValidators.tc3TestValidator({ inspectionNumber: 0 })(details as AbstractControl); + + expect(validator).toBeNull(); + }); + + describe('dateIsValid', () => { + it.each([ + [{ dateIsInvalid: { message: "'Date' day must be a number" } }, null], + [{ dateIsInvalid: { message: "'Date' day must be a number" } }, undefined], + [{ dateIsInvalid: { message: "'Date' day must be a number" } }, ''], + [{ dateIsInvalid: { message: "'Date' day must be a number" } }, '---'], + [{ dateIsInvalid: { message: "'Date' day must be a number" } }, '2000--'], + [{ dateIsInvalid: { message: "'Date' day must be a number" } }, '2000-12-'], + [{ dateIsInvalid: { message: "'Date' day must be a number" } }, '2000-12-A'], + [null, '2000-12-01'], + [null, '2000-12-11'], + [null, '2000-12-31'], + [{ dateIsInvalid: { message: "'Date' month must be a number" } }, '2000--11'], + [{ dateIsInvalid: { message: "'Date' month must be a number" } }, '2000-C-11'], + [{ dateIsInvalid: { message: "'Date' month must be between 1 and 12" } }, '2000-31-11'], + [{ dateIsInvalid: { message: "'Date' month must be between 1 and 12" } }, '2000-00-11'], + [{ dateIsInvalid: { message: "'Date' year must be a number" } }, '-12-11'], + [{ dateIsInvalid: { message: "'Date' year must be a number" } }, 'C-12-11'], + + [null, '2020-02-29'], + [{ dateIsInvalid: { message: "'Date' day must be between 1 and 28 in the month of February" } }, '2019-02-29'], + ])('should return %p when control value is %s', (expected: object | null, input) => { + expect(CustomValidators.dateIsInvalid(new FormControl(input))).toEqual(expected); + }); + }); }); describe('minArrayLengthIfNotEmpty', () => { - it('should return null if the form array is empty', () => { - const formArray = new FormArray([]); - expect(CustomValidators.minArrayLengthIfNotEmpty(2, 'Error message')(formArray)).toBeNull(); - }); - - it('should return an error if the array is not empty but doesnt reach minimum length', () => { - const formArray = new FormArray([ - new FormControl({ - axleNumber: 1, - tyres_tyreSize: null, - tyres_fitmentCode: null, - tyres_dataTrAxles: null, - tyres_plyRating: null, - tyres_tyreCode: null, - weights_gbWeight: null, - weights_designWeight: null, - parkingBrakeMrk: false, - weights_eecWeight: null, - }), - ]); - - expect(CustomValidators.minArrayLengthIfNotEmpty(2, 'Error message')(formArray)).toStrictEqual( - expect.objectContaining({ - minArrayLengthIfNotEmpty: { message: 'Error message' }, - }), - ); - }); - - it('should return null if the minimum length is reached', () => { - const formArray = new FormArray([ - new FormControl({ - axleNumber: 1, - tyres_tyreSize: null, - tyres_fitmentCode: null, - tyres_dataTrAxles: null, - tyres_plyRating: null, - tyres_tyreCode: null, - weights_gbWeight: null, - weights_designWeight: null, - parkingBrakeMrk: false, - weights_eecWeight: null, - }), - new FormControl({ - axleNumber: 2, - tyres_tyreSize: null, - tyres_fitmentCode: null, - tyres_dataTrAxles: null, - tyres_plyRating: null, - tyres_tyreCode: null, - weights_gbWeight: null, - weights_designWeight: null, - parkingBrakeMrk: false, - weights_eecWeight: null, - }), - ]); - - expect(CustomValidators.minArrayLengthIfNotEmpty(2, 'Error message')(formArray)).toBeNull(); - }); + it('should return null if the form array is empty', () => { + const formArray = new FormArray([]); + expect(CustomValidators.minArrayLengthIfNotEmpty(2, 'Error message')(formArray)).toBeNull(); + }); + + it('should return an error if the array is not empty but doesnt reach minimum length', () => { + const formArray = new FormArray([ + new FormControl({ + axleNumber: 1, + tyres_tyreSize: null, + tyres_fitmentCode: null, + tyres_dataTrAxles: null, + tyres_plyRating: null, + tyres_tyreCode: null, + weights_gbWeight: null, + weights_designWeight: null, + parkingBrakeMrk: false, + weights_eecWeight: null, + }), + ]); + + expect(CustomValidators.minArrayLengthIfNotEmpty(2, 'Error message')(formArray)).toStrictEqual( + expect.objectContaining({ + minArrayLengthIfNotEmpty: { message: 'Error message' }, + }) + ); + }); + + it('should return null if the minimum length is reached', () => { + const formArray = new FormArray([ + new FormControl({ + axleNumber: 1, + tyres_tyreSize: null, + tyres_fitmentCode: null, + tyres_dataTrAxles: null, + tyres_plyRating: null, + tyres_tyreCode: null, + weights_gbWeight: null, + weights_designWeight: null, + parkingBrakeMrk: false, + weights_eecWeight: null, + }), + new FormControl({ + axleNumber: 2, + tyres_tyreSize: null, + tyres_fitmentCode: null, + tyres_dataTrAxles: null, + tyres_plyRating: null, + tyres_tyreCode: null, + weights_gbWeight: null, + weights_designWeight: null, + parkingBrakeMrk: false, + weights_eecWeight: null, + }), + ]); + + 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 }, - }); - }); - }); + 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..a677459a20 100644 --- a/src/app/forms/validators/custom-validators.ts +++ b/src/app/forms/validators/custom-validators.ts @@ -6,606 +6,655 @@ import { VehicleSizes, VehicleTypes } from '@models/vehicle-tech-record.model'; import validateDate from 'validate-govuk-date'; export class CustomValidators { - static hideIfEmpty = (sibling: string): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (control?.parent) { - const siblingControl = control.parent.get(sibling) as CustomFormControl; - siblingControl.meta.hide = !control.value; - } - - return null; - }; - }; - - static hideIfEquals = (sibling: string, value: unknown): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (control?.parent) { - const siblingControl = control.parent.get(sibling) as CustomFormControl; - - siblingControl.meta.hide = Array.isArray(value) && control.value ? value.includes(control.value) : control.value === value; - } - - return null; - }; - }; - - static hideIfNotEqual = (sibling: string, value: unknown): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (control?.parent) { - const siblingControl = control.parent.get(sibling) as CustomFormControl; - - siblingControl.meta.hide = Array.isArray(value) ? !value.includes(control.value) : control.value !== value; - } - - return null; - }; - }; - - static enableIfEquals = (sibling: string, value: unknown): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (control?.parent) { - const siblingControl = control.parent.get(sibling) as CustomFormControl; - const isEqual = Array.isArray(value) ? value.includes(control.value) : control.value === value; - if (isEqual) { - siblingControl.enable(); - } else { - siblingControl.disable(); - } - } - return null; - }; - }; - - static disableIfEquals = (sibling: string, value: unknown): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (control?.parent) { - const siblingControl = control.parent.get(sibling) as CustomFormControl; - const isEqual = Array.isArray(value) ? value.includes(control.value) : control.value === value; - if (isEqual) { - siblingControl.disable(); - } else { - siblingControl.enable(); - } - } - return null; - }; - }; - - static hideIfParentSiblingNotEqual = (parentSibling: string, value: unknown): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (control?.parent && control.parent.parent) { - const siblingControl = control.parent.parent.get(parentSibling) as CustomFormControl; - - siblingControl.meta.hide = Array.isArray(value) ? !value.includes(control.value) : control.value !== value; - } - - return null; - }; - }; - - static hideIfParentSiblingEquals = (parentSibling: string, value: unknown): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (control?.parent && control.parent.parent) { - const siblingControl = control.parent.parent.get(parentSibling) as CustomFormControl; - siblingControl.meta.hide = Array.isArray(value) && control.value ? value.includes(control.value) : control.value === value; - } - - return null; - }; - }; - - static requiredIfNotHidden = (): ValidatorFn => - (control: AbstractControl): ValidationErrors | null => { - const customControl = control as CustomFormControl; - if (!control?.parent) return null; - if (customControl.meta.hide === false && !control.value) { - // If meta.hide is false and control value is empty, return a validation error - return { requiredIfNotHidden: customControl.meta.label }; - } - return null; - }; - - static requiredIfEquals = (sibling: string, values: unknown[], customErrorMessage?: string): ValidatorFn => - (control: AbstractControl): ValidationErrors | null => { - if (!control?.parent) return null; - - const siblingControl = control.parent.get(sibling) as CustomFormControl; - const siblingValue = siblingControl.value; - - const isSiblingVisible = !siblingControl.meta.hide; - - const isSiblingValueIncluded = Array.isArray(siblingValue) - ? values.some((value) => siblingValue.includes(value)) - : 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, customErrorMessage } } - : null; - }; - - static requiredIfAllEquals = (sibling: string, values: unknown[]): ValidatorFn => - (control: AbstractControl): ValidationErrors | null => { - if (!control?.parent) return null; - - const siblingControl = control.parent.get(sibling) as CustomFormControl; - const siblingValue = siblingControl.value; - - const isSiblingVisible = !siblingControl.meta.hide; - - 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; - }; - - static requiredIfNotEquals = (sibling: string, value: unknown): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (control?.parent) { - const siblingControl = control.parent.get(sibling) as CustomFormControl; - const siblingValue = siblingControl.value; - const newValue = Array.isArray(value) ? value.includes(siblingValue) : siblingValue === value; - - if (!newValue && (control.value === null || control.value === undefined || control.value === '')) { - return { requiredIfNotEquals: { sibling: siblingControl.meta.label } }; - } - } - - return null; - }; - }; - - static mustEqualSibling = (sibling: string): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (control?.parent) { - const siblingControl = control.parent.get(sibling) as CustomFormControl; - const siblingValue = siblingControl.value; - const isEqual = Array.isArray(control.value) ? control.value.includes(siblingValue) : siblingValue === control.value; - - if (!isEqual) { - return { mustEqualSibling: { sibling: siblingControl.meta.label } }; - } - } - - return null; - }; - }; - - static validateVRMTrailerIdLength = (sibling: string): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (!control.value) { - return null; - } - - if (control?.parent) { - const siblingControl = control.parent.get(sibling) as CustomFormControl; - const siblingValue = siblingControl.value; - - const isTrailerValueSelected = siblingValue === VehicleTypes.TRL; - - if (isTrailerValueSelected) { - if (control.value.length < 7) { - return { validateVRMTrailerIdLength: { message: 'Trailer ID must be greater than or equal to 7 characters' } }; - } - if (control.value.length > 8) { - return { validateVRMTrailerIdLength: { message: 'Trailer ID must be less than or equal to 8 characters' } }; - } - } else { - if (control.value.length < 1) { - return { validateVRMTrailerIdLength: { message: 'VRM must be greater than or equal to 1 character' } }; - } - if (control.value.length > 9) { - return { validateVRMTrailerIdLength: { message: 'VRM must be less than or equal to 9 characters' } }; - } - } - } - - return null; - }; - }; - - static defined = (): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (typeof control.value === 'undefined') { - return { defined: false }; - } - return null; - }; - }; - - static validateVinCharacters() { - return this.customPattern(['^(?!.*[OIQ]).*$', 'should not contain O, I or Q']); - } - static alphanumeric(): ValidatorFn { - return this.customPattern(['^[a-zA-Z0-9]*$', 'must be alphanumeric']); - } - - static numeric(): ValidatorFn { - return this.customPattern(['^\\d*$', 'must be a whole number']); - } - - static email(): ValidatorFn { - return this.customPattern(['^[\\w\\-\\.\\+]+@([\\w-]+\\.)+[\\w-]{2,}$', 'Enter an email address in the correct format, like name@example.com']); - } - - static customPattern([regEx, message]: string[]): ValidatorFn { - return (control: AbstractControl): ValidationErrors | null => { - if (!control.value) { - return null; - } - - // eslint-disable-next-line security/detect-non-literal-regexp - const valid = new RegExp(regEx).test(control.value); - - return valid ? null : { customPattern: { message } }; - }; - } - - static invalidOption: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { - return control.value === '[INVALID_OPTION]' ? { invalidOption: true } : null; - }; - - static dateIsInvalid: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { - if (control instanceof CustomFormControl && control.meta.hide) return null; - const [yyyy, mm, dd] = (control.value ?? '').split('-'); - const label = control instanceof CustomFormControl ? control.meta.label : undefined; - const checks = validateDate(parseInt(dd ?? '', 10), parseInt(mm ?? '', 10), parseInt(yyyy ?? '', 10), label); - return checks && checks.error ? { dateIsInvalid: { message: checks.errors?.[0]?.reason } } : null; - }; - - static pastDate: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { - const now = new Date(); - const date = control.value; - - if (date && new Date(date).getTime() > now.getTime()) { - return { pastDate: true }; - } - return null; - }; - - static futureDate: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { - const now = new Date(); - const date = control.value; - if (date && new Date(date).getTime() < now.getTime()) { - return { futureDate: true }; - } - return null; - }; - - static pastYear: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { - const currentYear = new Date().getFullYear(); - const inputYear = control.value; - if (inputYear && inputYear > currentYear) { - return { pastYear: true }; - } - return null; - }; - - static aheadOfDate = (sibling: string): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - const siblingControl = control?.parent?.get(sibling); - if (siblingControl?.value && control.value && new Date(control.value) < new Date(siblingControl.value)) { - return { aheadOfDate: { sibling: (siblingControl as CustomFormControl).meta.label, date: new Date(siblingControl.value) } }; - } - - return null; - }; - }; - - static dateNotExceed = (sibling: string, months: number): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - const siblingControl = control?.parent?.get(sibling); - if (siblingControl?.value && control.value) { - const maxDate = new Date(siblingControl.value); - maxDate.setMonth(maxDate.getMonth() + months); - - if (new Date(control.value) > maxDate) { - return { dateNotExceed: { sibling: (siblingControl as CustomFormControl).meta.label, months } }; - } - } - - return null; - }; - }; - - /** - * Validator that copies control value to control of given name at the top-level ancestor of control. - * @param rootControlName - control in top-level ancestor of this control - * @returns null - */ - static copyValueToRootControl = (rootControlName: string): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - const rootControl = control.root.get(rootControlName); - if (rootControl) { - rootControl.setValue(control.value, { onlySelf: true, emitEvent: false }); - } - return null; - }; - }; - - static notZNumber = (control: AbstractControl): ValidationErrors | null => { - if (!control.value) return null; - - const isZNumber = /^[0-9]{7}[zZ]$/.test(control.value); - - return !isZNumber ? null : { notZNumber: true }; - }; - - static handlePsvPassengersChange = (passengersOne: string, passengersTwo: string): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (control.dirty) { - const controlOne: number = control.root.get(passengersOne)?.value; - const controlTwo: number = control.root.get(passengersTwo)?.value; - const controlThree: number = control.value; - - const classControl = control.root.get('techRecord_vehicleClass_description'); - const sizeControl = control.root.get('techRecord_vehicleSize'); - - const totalPassengers = controlOne + controlTwo + controlThree; - - switch (true) { - case totalPassengers <= 22: { - sizeControl?.setValue(VehicleSizes.SMALL, { emitEvent: false }); - classControl?.setValue(VehicleClassDescription.SmallPsvIeLessThanOrEqualTo22Seats, { emitEvent: false }); - break; - } - default: { - sizeControl?.setValue(VehicleSizes.LARGE, { emitEvent: false }); - classControl?.setValue(VehicleClassDescription.LargePsvIeGreaterThan23Seats, { emitEvent: false }); - } - } - control.markAsPristine(); - } - return null; - }; - }; - - static isMemberOfEnum = (checkEnum: Record, options: Partial = {}): ValidatorFn => { - options = { allowFalsy: false, ...options }; - - return (control: AbstractControl): ValidationErrors | null => { - if (options.allowFalsy && !control.value) return null; - return Object.values(checkEnum).includes(control.value) ? null : { enum: true }; - }; - }; - - static updateFunctionCode = (): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - const vehicleFunctionCode = control.root.get('techRecord_functionCode'); - const functionCodes: Record = { - rigid: 'R', - articulated: 'A', - 'semi-trailer': 'A', - }; - - if (control.dirty) { - vehicleFunctionCode?.setValue(functionCodes[control?.value], { emitEvent: false }); - control.markAsPristine(); - } - return null; - }; - }; - - static modifyControlsByGroup = (control: AbstractControl, groups: string[], modifyFunc: (control: CustomFormControl) => void): void => { - if ((control as CustomFormControl).meta.hide) return; - - const parentGroup = control.parent as CustomFormGroup; - parentGroup.meta.children?.forEach((child) => { - const childControl = parentGroup.get(child.name) as CustomFormControl; - const childGroups = childControl?.meta.groups; - childGroups?.forEach((group) => { - if (groups.includes(group)) { - modifyFunc(childControl); - } - }); - }); - }; - - static setHidePropertyForGroups = (control: AbstractControl, groups: string[], hide: boolean): void => { - this.modifyControlsByGroup(control, groups, (childControl) => { - childControl.meta.hide = hide; - }); - }; - - static showGroupsWhenEqualTo = (values: unknown[] | undefined, groups: string[]): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (values && !values.includes(control.value)) return null; - this.setHidePropertyForGroups(control, groups, false); - - return null; - }; - }; - - static showGroupsWhenIncludes = (values: unknown[] | undefined, groups: string[]): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (values && !values.some((value) => control.value?.includes(value))) return null; - this.setHidePropertyForGroups(control, groups, false); - return null; - }; - }; - - static hideGroupsWhenIncludes = (values: unknown[] | undefined, groups: string[]): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (values && values.some((value) => control.value?.includes(value))) { - this.setHidePropertyForGroups(control, groups, true); - } - - return null; - }; - }; - - static showGroupsWhenExcludes = (values: unknown[] | undefined, groups: string[]): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (values && values.some((value) => control.value?.includes(value))) return null; - this.setHidePropertyForGroups(control, groups, false); - - return null; - }; - }; - - static hideGroupsWhenExcludes = (values: unknown[] | undefined, groups: string[]): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (values && values.some((value) => control.value?.includes(value))) return null; - this.setHidePropertyForGroups(control, groups, true); - - return null; - }; - }; - - static hideGroupsWhenEqualTo = (values: unknown[] | undefined, groups: string[]): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (values && !values.includes(control.value)) return null; - this.setHidePropertyForGroups(control, groups, true); - - return null; - }; - }; - - static addWarningForAdrField = (warning: string): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (control instanceof CustomFormControl) { - if (control.value) { - control.meta.warning = undefined; - return null; - } - - if (control.dirty) { - const { parent } = control; - if (parent instanceof CustomFormGroup) { - const touched = Object.values(parent.controls).some((child) => child !== control && child.touched && child.value); - if (touched) { - control.meta.warning = warning; - } - } - } - } - - return null; - }; - }; - - static isArray = (options: Partial = {}) => { - return (control: AbstractControl): ValidationErrors | null => { - // Only perform subsequent logic if this condition is met, e.g. sibling control has value true - if (options.whenEquals) { - 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); - - if (!isSiblingValueIncluded) return null; - } - - if (!Array.isArray(control.value)) return { isArray: 'must be a non-empty array' }; - - 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}` } }; - } - - 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 null; - }; - }; - - static custom = (func: (...args: unknown[]) => ValidationErrors | null, ...args: unknown[]) => { - return (control: AbstractControl): ValidationErrors | null => func(control, ...args); - }; - - static tc3TestValidator = (args: { inspectionNumber: number }) => { - return (control: AbstractControl): ValidationErrors | null => { - if (!control?.parent) return null; - let areControlsEmpty: boolean[] = []; - let inspection = ''; - // the inspection numbers for individual tests start form 1 so this checks if its an individual test or the control that contains the component - if (args.inspectionNumber !== 0) { - const tc3Type = control.parent?.get('tc3Type')?.value; - const tc3PeriodicNumber = control.parent?.get('tc3PeriodicNumber')?.value; - const tc3PeriodicExpiryDate = control.parent?.get('tc3PeriodicExpiryDate')?.value; - // areTc3FieldsEmpty takes an array of tc3 test values and checks that at least one of the fields is filled out for each test - areControlsEmpty = areTc3FieldsEmpty([{ tc3Type, tc3PeriodicExpiryDate, tc3PeriodicNumber }]); - inspection = args.inspectionNumber as unknown as string; - return areControlsEmpty.includes(true) - ? { tc3TestValidator: { message: `TC3 Subsequent inspection ${inspection} must have at least one populated field` } } - : null; - } - // this statement is the same logic but applied to the control that holds all of the tests. - // This allows the error to be displayed in the Global error service - if (!control.value) return null; - areControlsEmpty = areTc3FieldsEmpty(control.value); - areControlsEmpty.forEach((value, index) => { - if (value) { - if (inspection.length === 0) { - inspection = `${index + 1}`; - } else { - inspection += `, ${index + 1}`; - } - } - }); - return areControlsEmpty.includes(true) - ? { tc3TestValidator: { message: `TC3 Subsequent inspection ${inspection} must have at least one populated field` } } - : null; - }; - }; - - static minArrayLengthIfNotEmpty = (minimumLength: number, message: string): ValidatorFn => { - return (control: AbstractControl): ValidationErrors | null => { - if (control.value?.length && control.value.length < minimumLength) { - return { minArrayLengthIfNotEmpty: { message } }; - } - 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); - }; - }; + static hideIfEmpty = (sibling: string): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (control?.parent) { + const siblingControl = control.parent.get(sibling) as CustomFormControl; + siblingControl.meta.hide = !control.value; + } + + return null; + }; + }; + + static hideIfEquals = (sibling: string, value: unknown): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (control?.parent) { + const siblingControl = control.parent.get(sibling) as CustomFormControl; + + siblingControl.meta.hide = + Array.isArray(value) && control.value ? value.includes(control.value) : control.value === value; + } + + return null; + }; + }; + + static hideIfNotEqual = (sibling: string, value: unknown): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (control?.parent) { + const siblingControl = control.parent.get(sibling) as CustomFormControl; + + siblingControl.meta.hide = Array.isArray(value) ? !value.includes(control.value) : control.value !== value; + } + + return null; + }; + }; + + static enableIfEquals = (sibling: string, value: unknown): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (control?.parent) { + const siblingControl = control.parent.get(sibling) as CustomFormControl; + const isEqual = Array.isArray(value) ? value.includes(control.value) : control.value === value; + if (isEqual) { + siblingControl.enable(); + } else { + siblingControl.disable(); + } + } + return null; + }; + }; + + static disableIfEquals = (sibling: string, value: unknown): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (control?.parent) { + const siblingControl = control.parent.get(sibling) as CustomFormControl; + const isEqual = Array.isArray(value) ? value.includes(control.value) : control.value === value; + if (isEqual) { + siblingControl.disable(); + } else { + siblingControl.enable(); + } + } + return null; + }; + }; + + static hideIfParentSiblingNotEqual = (parentSibling: string, value: unknown): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (control?.parent && control.parent.parent) { + const siblingControl = control.parent.parent.get(parentSibling) as CustomFormControl; + + siblingControl.meta.hide = Array.isArray(value) ? !value.includes(control.value) : control.value !== value; + } + + return null; + }; + }; + + static hideIfParentSiblingEquals = (parentSibling: string, value: unknown): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (control?.parent && control.parent.parent) { + const siblingControl = control.parent.parent.get(parentSibling) as CustomFormControl; + siblingControl.meta.hide = + Array.isArray(value) && control.value ? value.includes(control.value) : control.value === value; + } + + return null; + }; + }; + + static requiredIfNotHidden = + (): ValidatorFn => + (control: AbstractControl): ValidationErrors | null => { + const customControl = control as CustomFormControl; + if (!control?.parent) return null; + if (customControl.meta.hide === false && !control.value) { + // If meta.hide is false and control value is empty, return a validation error + return { requiredIfNotHidden: customControl.meta.label }; + } + return null; + }; + + static requiredIfEquals = + (sibling: string, values: unknown[], customErrorMessage?: string): ValidatorFn => + (control: AbstractControl): ValidationErrors | null => { + if (!control?.parent) return null; + + const siblingControl = control.parent.get(sibling) as CustomFormControl; + const siblingValue = siblingControl.value; + + const isSiblingVisible = !siblingControl.meta.hide; + + const isSiblingValueIncluded = Array.isArray(siblingValue) + ? values.some((value) => siblingValue.includes(value)) + : 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, customErrorMessage } } + : null; + }; + + static requiredIfAllEquals = + (sibling: string, values: unknown[]): ValidatorFn => + (control: AbstractControl): ValidationErrors | null => { + if (!control?.parent) return null; + + const siblingControl = control.parent.get(sibling) as CustomFormControl; + const siblingValue = siblingControl.value; + + const isSiblingVisible = !siblingControl.meta.hide; + + 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; + }; + + static requiredIfNotEquals = (sibling: string, value: unknown): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (control?.parent) { + const siblingControl = control.parent.get(sibling) as CustomFormControl; + const siblingValue = siblingControl.value; + const newValue = Array.isArray(value) ? value.includes(siblingValue) : siblingValue === value; + + if (!newValue && (control.value === null || control.value === undefined || control.value === '')) { + return { requiredIfNotEquals: { sibling: siblingControl.meta.label } }; + } + } + + return null; + }; + }; + + static mustEqualSibling = (sibling: string): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (control?.parent) { + const siblingControl = control.parent.get(sibling) as CustomFormControl; + const siblingValue = siblingControl.value; + const isEqual = Array.isArray(control.value) + ? control.value.includes(siblingValue) + : siblingValue === control.value; + + if (!isEqual) { + return { mustEqualSibling: { sibling: siblingControl.meta.label } }; + } + } + + return null; + }; + }; + + static validateVRMTrailerIdLength = (sibling: string): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (!control.value) { + return null; + } + + if (control?.parent) { + const siblingControl = control.parent.get(sibling) as CustomFormControl; + const siblingValue = siblingControl.value; + + const isTrailerValueSelected = siblingValue === VehicleTypes.TRL; + + if (isTrailerValueSelected) { + if (control.value.length < 7) { + return { + validateVRMTrailerIdLength: { message: 'Trailer ID must be greater than or equal to 7 characters' }, + }; + } + if (control.value.length > 8) { + return { validateVRMTrailerIdLength: { message: 'Trailer ID must be less than or equal to 8 characters' } }; + } + } else { + if (control.value.length < 1) { + return { validateVRMTrailerIdLength: { message: 'VRM must be greater than or equal to 1 character' } }; + } + if (control.value.length > 9) { + return { validateVRMTrailerIdLength: { message: 'VRM must be less than or equal to 9 characters' } }; + } + } + } + + return null; + }; + }; + + static defined = (): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (typeof control.value === 'undefined') { + return { defined: false }; + } + return null; + }; + }; + + static validateVinCharacters() { + return this.customPattern(['^(?!.*[OIQ]).*$', 'should not contain O, I or Q']); + } + static alphanumeric(): ValidatorFn { + return this.customPattern(['^[a-zA-Z0-9]*$', 'must be alphanumeric']); + } + + static numeric(): ValidatorFn { + return this.customPattern(['^\\d*$', 'must be a whole number']); + } + + static email(): ValidatorFn { + return this.customPattern([ + '^[\\w\\-\\.\\+]+@([\\w-]+\\.)+[\\w-]{2,}$', + 'Enter an email address in the correct format, like name@example.com', + ]); + } + + static customPattern([regEx, message]: string[]): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + if (!control.value) { + return null; + } + + // eslint-disable-next-line security/detect-non-literal-regexp + const valid = new RegExp(regEx).test(control.value); + + return valid ? null : { customPattern: { message } }; + }; + } + + static invalidOption: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { + return control.value === '[INVALID_OPTION]' ? { invalidOption: true } : null; + }; + + static dateIsInvalid: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { + if (control instanceof CustomFormControl && control.meta.hide) return null; + const [yyyy, mm, dd] = (control.value ?? '').split('-'); + const label = control instanceof CustomFormControl ? control.meta.label : undefined; + const checks = validateDate( + Number.parseInt(dd ?? '', 10), + Number.parseInt(mm ?? '', 10), + Number.parseInt(yyyy ?? '', 10), + label + ); + return checks && checks.error ? { dateIsInvalid: { message: checks.errors?.[0]?.reason } } : null; + }; + + static pastDate: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { + const now = new Date(); + const date = control.value; + + if (date && new Date(date).getTime() > now.getTime()) { + return { pastDate: true }; + } + return null; + }; + + static futureDate: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { + const now = new Date(); + const date = control.value; + if (date && new Date(date).getTime() < now.getTime()) { + return { futureDate: true }; + } + return null; + }; + + static pastYear: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { + const currentYear = new Date().getFullYear(); + const inputYear = control.value; + if (inputYear && inputYear > currentYear) { + return { pastYear: true }; + } + return null; + }; + + static aheadOfDate = (sibling: string): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + const siblingControl = control?.parent?.get(sibling); + if (siblingControl?.value && control.value && new Date(control.value) < new Date(siblingControl.value)) { + return { + aheadOfDate: { + sibling: (siblingControl as CustomFormControl).meta.label, + date: new Date(siblingControl.value), + }, + }; + } + + return null; + }; + }; + + static dateNotExceed = (sibling: string, months: number): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + const siblingControl = control?.parent?.get(sibling); + if (siblingControl?.value && control.value) { + const maxDate = new Date(siblingControl.value); + maxDate.setMonth(maxDate.getMonth() + months); + + if (new Date(control.value) > maxDate) { + return { dateNotExceed: { sibling: (siblingControl as CustomFormControl).meta.label, months } }; + } + } + + return null; + }; + }; + + /** + * Validator that copies control value to control of given name at the top-level ancestor of control. + * @param rootControlName - control in top-level ancestor of this control + * @returns null + */ + static copyValueToRootControl = (rootControlName: string): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + const rootControl = control.root.get(rootControlName); + if (rootControl) { + rootControl.setValue(control.value, { onlySelf: true, emitEvent: false }); + } + return null; + }; + }; + + static notZNumber = (control: AbstractControl): ValidationErrors | null => { + if (!control.value) return null; + + const isZNumber = /^[0-9]{7}[zZ]$/.test(control.value); + + return !isZNumber ? null : { notZNumber: true }; + }; + + static handlePsvPassengersChange = (passengersOne: string, passengersTwo: string): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (control.dirty) { + const controlOne: number = control.root.get(passengersOne)?.value; + const controlTwo: number = control.root.get(passengersTwo)?.value; + const controlThree: number = control.value; + + const classControl = control.root.get('techRecord_vehicleClass_description'); + const sizeControl = control.root.get('techRecord_vehicleSize'); + + const totalPassengers = controlOne + controlTwo + controlThree; + + switch (true) { + case totalPassengers <= 22: { + sizeControl?.setValue(VehicleSizes.SMALL, { emitEvent: false }); + classControl?.setValue(VehicleClassDescription.SmallPsvIeLessThanOrEqualTo22Seats, { emitEvent: false }); + break; + } + default: { + sizeControl?.setValue(VehicleSizes.LARGE, { emitEvent: false }); + classControl?.setValue(VehicleClassDescription.LargePsvIeGreaterThan23Seats, { emitEvent: false }); + } + } + control.markAsPristine(); + } + return null; + }; + }; + + static isMemberOfEnum = ( + checkEnum: Record, + options: Partial = {} + ): ValidatorFn => { + options = { allowFalsy: false, ...options }; + + return (control: AbstractControl): ValidationErrors | null => { + if (options.allowFalsy && !control.value) return null; + return Object.values(checkEnum).includes(control.value) ? null : { enum: true }; + }; + }; + + static updateFunctionCode = (): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + const vehicleFunctionCode = control.root.get('techRecord_functionCode'); + const functionCodes: Record = { + rigid: 'R', + articulated: 'A', + 'semi-trailer': 'A', + }; + + if (control.dirty) { + vehicleFunctionCode?.setValue(functionCodes[control?.value], { emitEvent: false }); + control.markAsPristine(); + } + return null; + }; + }; + + static modifyControlsByGroup = ( + control: AbstractControl, + groups: string[], + modifyFunc: (control: CustomFormControl) => void + ): void => { + if ((control as CustomFormControl).meta.hide) return; + + const parentGroup = control.parent as CustomFormGroup; + parentGroup.meta.children?.forEach((child) => { + const childControl = parentGroup.get(child.name) as CustomFormControl; + const childGroups = childControl?.meta.groups; + childGroups?.forEach((group) => { + if (groups.includes(group)) { + modifyFunc(childControl); + } + }); + }); + }; + + static setHidePropertyForGroups = (control: AbstractControl, groups: string[], hide: boolean): void => { + this.modifyControlsByGroup(control, groups, (childControl) => { + childControl.meta.hide = hide; + }); + }; + + static showGroupsWhenEqualTo = (values: unknown[] | undefined, groups: string[]): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (values && !values.includes(control.value)) return null; + this.setHidePropertyForGroups(control, groups, false); + + return null; + }; + }; + + static showGroupsWhenIncludes = (values: unknown[] | undefined, groups: string[]): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (values && !values.some((value) => control.value?.includes(value))) return null; + this.setHidePropertyForGroups(control, groups, false); + return null; + }; + }; + + static hideGroupsWhenIncludes = (values: unknown[] | undefined, groups: string[]): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (values && values.some((value) => control.value?.includes(value))) { + this.setHidePropertyForGroups(control, groups, true); + } + + return null; + }; + }; + + static showGroupsWhenExcludes = (values: unknown[] | undefined, groups: string[]): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (values && values.some((value) => control.value?.includes(value))) return null; + this.setHidePropertyForGroups(control, groups, false); + + return null; + }; + }; + + static hideGroupsWhenExcludes = (values: unknown[] | undefined, groups: string[]): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (values && values.some((value) => control.value?.includes(value))) return null; + this.setHidePropertyForGroups(control, groups, true); + + return null; + }; + }; + + static hideGroupsWhenEqualTo = (values: unknown[] | undefined, groups: string[]): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (values && !values.includes(control.value)) return null; + this.setHidePropertyForGroups(control, groups, true); + + return null; + }; + }; + + static addWarningForAdrField = (warning: string): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (control instanceof CustomFormControl) { + if (control.value) { + control.meta.warning = undefined; + return null; + } + + if (control.dirty) { + const { parent } = control; + if (parent instanceof CustomFormGroup) { + const touched = Object.values(parent.controls).some( + (child) => child !== control && child.touched && child.value + ); + if (touched) { + control.meta.warning = warning; + } + } + } + } + + return null; + }; + }; + + static isArray = (options: Partial = {}) => { + return (control: AbstractControl): ValidationErrors | null => { + // Only perform subsequent logic if this condition is met, e.g. sibling control has value true + if (options.whenEquals) { + 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); + + if (!isSiblingValueIncluded) return null; + } + + if (!Array.isArray(control.value)) return { isArray: 'must be a non-empty array' }; + + 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}` } }; + } + + 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 null; + }; + }; + + static custom = (func: (...args: unknown[]) => ValidationErrors | null, ...args: unknown[]) => { + return (control: AbstractControl): ValidationErrors | null => func(control, ...args); + }; + + static tc3TestValidator = (args: { inspectionNumber: number }) => { + return (control: AbstractControl): ValidationErrors | null => { + if (!control?.parent) return null; + let areControlsEmpty: boolean[] = []; + let inspection = ''; + // the inspection numbers for individual tests start form 1 so this checks if its an individual test or the control that contains the component + if (args.inspectionNumber !== 0) { + const tc3Type = control.parent?.get('tc3Type')?.value; + const tc3PeriodicNumber = control.parent?.get('tc3PeriodicNumber')?.value; + const tc3PeriodicExpiryDate = control.parent?.get('tc3PeriodicExpiryDate')?.value; + // areTc3FieldsEmpty takes an array of tc3 test values and checks that at least one of the fields is filled out for each test + areControlsEmpty = areTc3FieldsEmpty([{ tc3Type, tc3PeriodicExpiryDate, tc3PeriodicNumber }]); + inspection = args.inspectionNumber as unknown as string; + return areControlsEmpty.includes(true) + ? { + tc3TestValidator: { + message: `TC3 Subsequent inspection ${inspection} must have at least one populated field`, + }, + } + : null; + } + // this statement is the same logic but applied to the control that holds all of the tests. + // This allows the error to be displayed in the Global error service + if (!control.value) return null; + areControlsEmpty = areTc3FieldsEmpty(control.value); + areControlsEmpty.forEach((value, index) => { + if (value) { + if (inspection.length === 0) { + inspection = `${index + 1}`; + } else { + inspection += `, ${index + 1}`; + } + } + }); + return areControlsEmpty.includes(true) + ? { + tc3TestValidator: { + message: `TC3 Subsequent inspection ${inspection} must have at least one populated field`, + }, + } + : null; + }; + }; + + static minArrayLengthIfNotEmpty = (minimumLength: number, message: string): ValidatorFn => { + return (control: AbstractControl): ValidationErrors | null => { + if (control.value?.length && control.value.length < minimumLength) { + return { minArrayLengthIfNotEmpty: { message } }; + } + 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 = { - allowFalsy: boolean; + allowFalsy: boolean; }; export type IsArrayValidatorOptions = { - ofType: string; - requiredIndices: number[]; - whenEquals: { sibling: string; value: unknown[] }; + ofType: string; + requiredIndices: number[]; + whenEquals: { sibling: string; value: unknown[] }; }; const areTc3FieldsEmpty = (values: { tc3Type: string; tc3PeriodicNumber: string; tc3PeriodicExpiryDate: string }[]) => { - const isValueEmpty: boolean[] = []; - - values.forEach((value) => { - if ( - (value.tc3Type === null || value.tc3Type === undefined || value.tc3Type === '') - && (value.tc3PeriodicNumber === null || value.tc3PeriodicNumber === undefined || value.tc3PeriodicNumber === '') - && (value.tc3PeriodicExpiryDate === null || value.tc3PeriodicExpiryDate === undefined || value.tc3PeriodicExpiryDate === '') - ) { - isValueEmpty.push(true); - } else { - isValueEmpty.push(false); - } - }); - return isValueEmpty; + const isValueEmpty: boolean[] = []; + + values.forEach((value) => { + if ( + (value.tc3Type === null || value.tc3Type === undefined || value.tc3Type === '') && + (value.tc3PeriodicNumber === null || value.tc3PeriodicNumber === undefined || value.tc3PeriodicNumber === '') && + (value.tc3PeriodicExpiryDate === null || + value.tc3PeriodicExpiryDate === undefined || + value.tc3PeriodicExpiryDate === '') + ) { + isValueEmpty.push(true); + } else { + isValueEmpty.push(false); + } + }); + return isValueEmpty; }; diff --git a/src/app/forms/validators/date/date.validators.spec.ts b/src/app/forms/validators/date/date.validators.spec.ts index c15b30f561..605f118c1b 100644 --- a/src/app/forms/validators/date/date.validators.spec.ts +++ b/src/app/forms/validators/date/date.validators.spec.ts @@ -2,75 +2,83 @@ import { FormControl } from '@angular/forms'; import { DateValidators } from './date.validators'; describe('validDate', () => { - it.each([ - [ - { - invalidDate: { - error: true, - index: 0, - reason: '\'Date\' day must be between 1 and 31 in the month of January', - }, - }, - '2000-01-00', - ], - [ - { - invalidDate: { - error: true, - index: 1, - reason: '\'Date\' month must be between 1 and 12', - }, - }, - '2000-00-01', - ], - [ - { - invalidDate: { - error: true, - index: 0, - reason: '\'Date\' must include a day', - }, - }, - '20-01-', - ], - [ - { - invalidDate: { - error: true, - index: 1, - reason: '\'Date\' must include a month', - }, - }, - '20--01', - ], - [ - { - invalidDate: { - error: true, - index: 2, - reason: '\'Date\' must include a year', - }, - }, - '-01-00', - ], - [ - { - invalidDate: { - error: true, - reason: '\'Date\' year must be four digits', - }, - }, - '20-01-01', - ], - [{ invalidDate: { error: true, reason: '\'Date\' must include time' } }, '2022-01-01T:00:00:000Z', true], - [{ invalidDate: { error: true, reason: '\'Date\' hours must be between 0 and 23' } }, '2022-01-01T24:00:00:000Z', true], - [{ invalidDate: { error: true, reason: '\'Date\' must include time' } }, '2022-01-01T00::00:000Z', true], - [{ invalidDate: { error: true, reason: '\'Date\' minutes must be between 0 and 59' } }, '2022-01-01T00:60:00:000Z', true], - [null, ''], - [null, '2022-01-01T00:00:00.000Z'], - ])('should validate date and return %s for %p', (expected, date: string, displayTime = false) => { - const control = new FormControl(date); + it.each([ + [ + { + invalidDate: { + error: true, + index: 0, + reason: "'Date' day must be between 1 and 31 in the month of January", + }, + }, + '2000-01-00', + ], + [ + { + invalidDate: { + error: true, + index: 1, + reason: "'Date' month must be between 1 and 12", + }, + }, + '2000-00-01', + ], + [ + { + invalidDate: { + error: true, + index: 0, + reason: "'Date' must include a day", + }, + }, + '20-01-', + ], + [ + { + invalidDate: { + error: true, + index: 1, + reason: "'Date' must include a month", + }, + }, + '20--01', + ], + [ + { + invalidDate: { + error: true, + index: 2, + reason: "'Date' must include a year", + }, + }, + '-01-00', + ], + [ + { + invalidDate: { + error: true, + reason: "'Date' year must be four digits", + }, + }, + '20-01-01', + ], + [{ invalidDate: { error: true, reason: "'Date' must include time" } }, '2022-01-01T:00:00:000Z', true], + [ + { invalidDate: { error: true, reason: "'Date' hours must be between 0 and 23" } }, + '2022-01-01T24:00:00:000Z', + true, + ], + [{ invalidDate: { error: true, reason: "'Date' must include time" } }, '2022-01-01T00::00:000Z', true], + [ + { invalidDate: { error: true, reason: "'Date' minutes must be between 0 and 59" } }, + '2022-01-01T00:60:00:000Z', + true, + ], + [null, ''], + [null, '2022-01-01T00:00:00.000Z'], + ])('should validate date and return %s for %p', (expected, date: string, displayTime = false) => { + const control = new FormControl(date); - expect(DateValidators.validDate(displayTime)(control)).toEqual(expected); - }); + expect(DateValidators.validDate(displayTime)(control)).toEqual(expected); + }); }); diff --git a/src/app/forms/validators/date/date.validators.ts b/src/app/forms/validators/date/date.validators.ts index 23dafbc4dc..591d60f018 100644 --- a/src/app/forms/validators/date/date.validators.ts +++ b/src/app/forms/validators/date/date.validators.ts @@ -2,45 +2,45 @@ import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; import validateDate from 'validate-govuk-date'; export class DateValidators { - static validDate(displayTime = false, label?: string): ValidatorFn { - return (control: AbstractControl): ValidationErrors | null => { - if (!control.value) { - return null; - } - - const [d, t] = (control.value as string).split('T'); - const [year, month, day] = d.split('-'); - const { error, errors } = validateDate(day || '', month || '', year || '', label); - - if (error && errors?.length) { - return { invalidDate: errors[0] }; - } - - if (year.length !== 4) { - return { invalidDate: { error: true, reason: `'${label || 'Date'}' year must be four digits` } }; - } - - if (displayTime) { - return this.validateTime(t, label); - } - - return null; - }; - } - - private static validateTime(time: string, label: string | undefined) { - const [hours, minutes] = time.split(':'); - - if (!hours || !minutes) { - return { invalidDate: { error: true, reason: `'${label || 'Date'}' must include time` } }; - } - if (Number.parseInt(hours, 10) > 23) { - return { invalidDate: { error: true, reason: `'${label || 'Date'}' hours must be between 0 and 23` } }; - } - if (Number.parseInt(minutes, 10) > 59) { - return { invalidDate: { error: true, reason: `'${label || 'Date'}' minutes must be between 0 and 59` } }; - } - - return null; - } + static validDate(displayTime = false, label?: string): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + if (!control.value) { + return null; + } + + const [d, t] = (control.value as string).split('T'); + const [year, month, day] = d.split('-'); + const { error, errors } = validateDate(day || '', month || '', year || '', label); + + if (error && errors?.length) { + return { invalidDate: errors[0] }; + } + + if (year.length !== 4) { + return { invalidDate: { error: true, reason: `'${label || 'Date'}' year must be four digits` } }; + } + + if (displayTime) { + return this.validateTime(t, label); + } + + return null; + }; + } + + private static validateTime(time: string, label: string | undefined) { + const [hours, minutes] = time.split(':'); + + if (!hours || !minutes) { + return { invalidDate: { error: true, reason: `'${label || 'Date'}' must include time` } }; + } + if (Number.parseInt(hours, 10) > 23) { + return { invalidDate: { error: true, reason: `'${label || 'Date'}' hours must be between 0 and 23` } }; + } + if (Number.parseInt(minutes, 10) > 59) { + return { invalidDate: { error: true, reason: `'${label || 'Date'}' minutes must be between 0 and 59` } }; + } + + return null; + } } diff --git a/src/app/forms/validators/defects/defect.validators.spec.ts b/src/app/forms/validators/defects/defect.validators.spec.ts index 17c2c65d32..b5ec5e6cc0 100644 --- a/src/app/forms/validators/defects/defect.validators.spec.ts +++ b/src/app/forms/validators/defects/defect.validators.spec.ts @@ -1,150 +1,152 @@ -import { FormGroup, AbstractControl } from '@angular/forms'; -import { CustomFormGroup, FormNodeTypes, CustomFormControl } from '@forms/services/dynamic-form.types'; +import { AbstractControl, FormGroup } from '@angular/forms'; +import { CustomFormControl, CustomFormGroup, FormNodeTypes } from '@forms/services/dynamic-form.types'; import { deficiencyCategory } from '@models/defects/deficiency-category.enum'; import { DefectValidators } from './defect.validators'; describe('parent sibling validators', () => { - let form: FormGroup; - - beforeEach(() => { - form = new FormGroup({ - parent: new CustomFormGroup( - { name: 'parent', type: FormNodeTypes.GROUP }, - { notes: new CustomFormControl({ name: 'notes', type: FormNodeTypes.CONTROL }) }, - ), - prohibitionIssued: new CustomFormControl({ name: 'prohibitionIssued', type: FormNodeTypes.CONTROL }), - deficiencyCategory: new CustomFormControl({ name: 'deficiencyCategory', type: FormNodeTypes.CONTROL }), - stdForProhibition: new CustomFormControl({ name: 'stdForProhibition', type: FormNodeTypes.CONTROL }), - }); - }); - - it('should return null', () => { - expect(DefectValidators.validateDefectNotes(form.controls['foo'])).toBeNull(); - }); - - it('should return error if deficiency category is dangerous* and prohibition issued is no and value of control is not defined', () => { - const notes = form.get(['parent', 'notes']); - const prohibitionIssued = form.get('prohibitionIssued'); - const defCategory = form.get('deficiencyCategory'); - const stdForProhibition = form.get('stdForProhibition'); - - prohibitionIssued?.patchValue(false); - defCategory?.patchValue(deficiencyCategory.Dangerous); - stdForProhibition?.patchValue(true); - - expect(DefectValidators.validateDefectNotes(notes as AbstractControl)).toEqual({ validateDefectNotes: true }); - }); - - it('should return null if deficiency category is dangerous* and prohibition issued is yes and value of control is not defined', () => { - const notes = form.get(['parent', 'notes']); - const prohibitionIssued = form.get('prohibitionIssued'); - const defCategory = form.get('deficiencyCategory'); - const stdForProhibition = form.get('stdForProhibition'); - - prohibitionIssued?.patchValue(true); - defCategory?.patchValue(deficiencyCategory.Dangerous); - stdForProhibition?.patchValue(true); - - expect(DefectValidators.validateDefectNotes(notes as AbstractControl)).toBeNull(); - }); - - it('should return null if deficiency category is not dangerous* and prohibition issued is yes and value of control is not defined', () => { - const notes = form.get(['parent', 'notes']); - const prohibitionIssued = form.get('prohibitionIssued'); - const defCategory = form.get('deficiencyCategory'); - - prohibitionIssued?.patchValue(true); - defCategory?.patchValue('foo'); - - expect(DefectValidators.validateDefectNotes(notes as AbstractControl)).toBeNull(); - }); - - it('should return null if deficiency category is not dangerous* and prohibition issued is no and value of control is not defined', () => { - const notes = form.get(['parent', 'notes']); - const prohibitionIssued = form.get('prohibitionIssued'); - const defCategory = form.get('deficiencyCategory'); - - prohibitionIssued?.patchValue(false); - defCategory?.patchValue('foo'); - - expect(DefectValidators.validateDefectNotes(notes as AbstractControl)).toBeNull(); - }); - - it('should return null if deficiency category is dangerous* and prohibition issued is no and value of control is defined', () => { - const notes = form.get(['parent', 'notes']); - const prohibitionIssued = form.get('prohibitionIssued'); - const defCategory = form.get('deficiencyCategory'); - const stdForProhibition = form.get('stdForProhibition'); - - notes?.patchValue('foo'); - prohibitionIssued?.patchValue(false); - defCategory?.patchValue(deficiencyCategory.Dangerous); - stdForProhibition?.patchValue(true); - - expect(DefectValidators.validateDefectNotes(notes as AbstractControl)).toBeNull(); - }); + let form: FormGroup; + + beforeEach(() => { + form = new FormGroup({ + parent: new CustomFormGroup( + { name: 'parent', type: FormNodeTypes.GROUP }, + { notes: new CustomFormControl({ name: 'notes', type: FormNodeTypes.CONTROL }) } + ), + prohibitionIssued: new CustomFormControl({ name: 'prohibitionIssued', type: FormNodeTypes.CONTROL }), + deficiencyCategory: new CustomFormControl({ name: 'deficiencyCategory', type: FormNodeTypes.CONTROL }), + stdForProhibition: new CustomFormControl({ name: 'stdForProhibition', type: FormNodeTypes.CONTROL }), + }); + }); + + it('should return null', () => { + expect(DefectValidators.validateDefectNotes(form.controls['foo'])).toBeNull(); + }); + + it('should return error if deficiency category is dangerous* and prohibition issued is no and value of control is not defined', () => { + const notes = form.get(['parent', 'notes']); + const prohibitionIssued = form.get('prohibitionIssued'); + const defCategory = form.get('deficiencyCategory'); + const stdForProhibition = form.get('stdForProhibition'); + + prohibitionIssued?.patchValue(false); + defCategory?.patchValue(deficiencyCategory.Dangerous); + stdForProhibition?.patchValue(true); + + expect(DefectValidators.validateDefectNotes(notes as AbstractControl)).toEqual({ validateDefectNotes: true }); + }); + + it('should return null if deficiency category is dangerous* and prohibition issued is yes and value of control is not defined', () => { + const notes = form.get(['parent', 'notes']); + const prohibitionIssued = form.get('prohibitionIssued'); + const defCategory = form.get('deficiencyCategory'); + const stdForProhibition = form.get('stdForProhibition'); + + prohibitionIssued?.patchValue(true); + defCategory?.patchValue(deficiencyCategory.Dangerous); + stdForProhibition?.patchValue(true); + + expect(DefectValidators.validateDefectNotes(notes as AbstractControl)).toBeNull(); + }); + + it('should return null if deficiency category is not dangerous* and prohibition issued is yes and value of control is not defined', () => { + const notes = form.get(['parent', 'notes']); + const prohibitionIssued = form.get('prohibitionIssued'); + const defCategory = form.get('deficiencyCategory'); + + prohibitionIssued?.patchValue(true); + defCategory?.patchValue('foo'); + + expect(DefectValidators.validateDefectNotes(notes as AbstractControl)).toBeNull(); + }); + + it('should return null if deficiency category is not dangerous* and prohibition issued is no and value of control is not defined', () => { + const notes = form.get(['parent', 'notes']); + const prohibitionIssued = form.get('prohibitionIssued'); + const defCategory = form.get('deficiencyCategory'); + + prohibitionIssued?.patchValue(false); + defCategory?.patchValue('foo'); + + expect(DefectValidators.validateDefectNotes(notes as AbstractControl)).toBeNull(); + }); + + it('should return null if deficiency category is dangerous* and prohibition issued is no and value of control is defined', () => { + const notes = form.get(['parent', 'notes']); + const prohibitionIssued = form.get('prohibitionIssued'); + const defCategory = form.get('deficiencyCategory'); + const stdForProhibition = form.get('stdForProhibition'); + + notes?.patchValue('foo'); + prohibitionIssued?.patchValue(false); + defCategory?.patchValue(deficiencyCategory.Dangerous); + stdForProhibition?.patchValue(true); + + expect(DefectValidators.validateDefectNotes(notes as AbstractControl)).toBeNull(); + }); }); describe('prohibition issued validator', () => { - let form: FormGroup; - - beforeEach(() => { - form = new FormGroup({ - prohibitionIssued: new CustomFormControl({ name: 'prohibitionIssued', type: FormNodeTypes.CONTROL }), - deficiencyCategory: new CustomFormControl({ name: 'deficiencyCategory', type: FormNodeTypes.CONTROL }), - stdForProhibition: new CustomFormControl({ name: 'stdForProhibition', type: FormNodeTypes.CONTROL }), - }); - }); - - it('should return null', () => { - expect(DefectValidators.validateProhibitionIssued(form.controls['prohibitionIssued'])).toBeNull(); - }); - - it('should return error when dangerous no asterisk and prohibition issued is false', () => { - const defCategory = form.get('deficiencyCategory'); - const prohibitionIssued = form.get('prohibitionIssued'); - const stdForProhibition = form.get('stdForProhibition'); - - defCategory?.patchValue(deficiencyCategory.Dangerous); - prohibitionIssued?.patchValue(false); - stdForProhibition?.patchValue(false); - - expect(DefectValidators.validateProhibitionIssued(form.controls['prohibitionIssued'])).toEqual({ validateProhibitionIssued: true }); - }); - - it('should return null when prohibition issued is true', () => { - const defCategory = form.get('deficiencyCategory'); - const prohibitionIssued = form.get('prohibitionIssued'); - const stdForProhibition = form.get('stdForProhibition'); - - defCategory?.patchValue(deficiencyCategory.Dangerous); - prohibitionIssued?.patchValue(true); - stdForProhibition?.patchValue(false); - - expect(DefectValidators.validateProhibitionIssued(form.controls['prohibitionIssued'])).toBeNull(); - }); - - it('should return null when std for prohibition is true', () => { - const defCategory = form.get('deficiencyCategory'); - const prohibitionIssued = form.get('prohibitionIssued'); - const stdForProhibition = form.get('stdForProhibition'); - - defCategory?.patchValue(deficiencyCategory.Dangerous); - prohibitionIssued?.patchValue(false); - stdForProhibition?.patchValue(true); - - expect(DefectValidators.validateProhibitionIssued(form.controls['prohibitionIssued'])).toBeNull(); - }); - - it('should return null when deficiency category is not dangerous', () => { - const defCategory = form.get('deficiencyCategory'); - const prohibitionIssued = form.get('prohibitionIssued'); - const stdForProhibition = form.get('stdForProhibition'); - - defCategory?.patchValue(deficiencyCategory.Minor); - prohibitionIssued?.patchValue(false); - stdForProhibition?.patchValue(false); - - expect(DefectValidators.validateProhibitionIssued(form.controls['prohibitionIssued'])).toBeNull(); - }); + let form: FormGroup; + + beforeEach(() => { + form = new FormGroup({ + prohibitionIssued: new CustomFormControl({ name: 'prohibitionIssued', type: FormNodeTypes.CONTROL }), + deficiencyCategory: new CustomFormControl({ name: 'deficiencyCategory', type: FormNodeTypes.CONTROL }), + stdForProhibition: new CustomFormControl({ name: 'stdForProhibition', type: FormNodeTypes.CONTROL }), + }); + }); + + it('should return null', () => { + expect(DefectValidators.validateProhibitionIssued(form.controls['prohibitionIssued'])).toBeNull(); + }); + + it('should return error when dangerous no asterisk and prohibition issued is false', () => { + const defCategory = form.get('deficiencyCategory'); + const prohibitionIssued = form.get('prohibitionIssued'); + const stdForProhibition = form.get('stdForProhibition'); + + defCategory?.patchValue(deficiencyCategory.Dangerous); + prohibitionIssued?.patchValue(false); + stdForProhibition?.patchValue(false); + + expect(DefectValidators.validateProhibitionIssued(form.controls['prohibitionIssued'])).toEqual({ + validateProhibitionIssued: true, + }); + }); + + it('should return null when prohibition issued is true', () => { + const defCategory = form.get('deficiencyCategory'); + const prohibitionIssued = form.get('prohibitionIssued'); + const stdForProhibition = form.get('stdForProhibition'); + + defCategory?.patchValue(deficiencyCategory.Dangerous); + prohibitionIssued?.patchValue(true); + stdForProhibition?.patchValue(false); + + expect(DefectValidators.validateProhibitionIssued(form.controls['prohibitionIssued'])).toBeNull(); + }); + + it('should return null when std for prohibition is true', () => { + const defCategory = form.get('deficiencyCategory'); + const prohibitionIssued = form.get('prohibitionIssued'); + const stdForProhibition = form.get('stdForProhibition'); + + defCategory?.patchValue(deficiencyCategory.Dangerous); + prohibitionIssued?.patchValue(false); + stdForProhibition?.patchValue(true); + + expect(DefectValidators.validateProhibitionIssued(form.controls['prohibitionIssued'])).toBeNull(); + }); + + it('should return null when deficiency category is not dangerous', () => { + const defCategory = form.get('deficiencyCategory'); + const prohibitionIssued = form.get('prohibitionIssued'); + const stdForProhibition = form.get('stdForProhibition'); + + defCategory?.patchValue(deficiencyCategory.Minor); + prohibitionIssued?.patchValue(false); + stdForProhibition?.patchValue(false); + + expect(DefectValidators.validateProhibitionIssued(form.controls['prohibitionIssued'])).toBeNull(); + }); }); diff --git a/src/app/forms/validators/defects/defect.validators.ts b/src/app/forms/validators/defects/defect.validators.ts index 2d74cbb6d4..e8f8e27c26 100644 --- a/src/app/forms/validators/defects/defect.validators.ts +++ b/src/app/forms/validators/defects/defect.validators.ts @@ -2,44 +2,47 @@ import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; import { deficiencyCategory } from '@models/defects/deficiency-category.enum'; export class DefectValidators { - static validateDefectNotes: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { - if (control?.parent && control.parent.parent) { - const grandParent = control.parent.parent; - const defCategory = grandParent?.get('deficiencyCategory')?.value as deficiencyCategory; - const prohibitionIssued = grandParent.get('prohibitionIssued')?.value as boolean; - const stdForProhibition = grandParent.get('stdForProhibition')?.value as boolean; - - const imNumber: string = grandParent.get('imNumber')?.value ? `${grandParent.get('imNumber')?.value}.` : ''; - const itemNumber: string = grandParent.get('itemNumber')?.value ? `${grandParent.get('itemNumber')?.value}.` : ''; - const deficiencyId: string = grandParent.get('deficiencyId')?.value ? `${grandParent.get('deficiencyId')?.value}.` : ''; - const deficiencySubId: string = grandParent.get('deficiencySubId')?.value ?? ''; - - const defectType = imNumber + itemNumber + deficiencyId + deficiencySubId; - - const optionalDefectNotes = ['43.1.a.ii', '41.1.a.ii', '10.1.iii']; - - if (optionalDefectNotes.includes(defectType)) return null; - - if ( - !control.value - && (defCategory === deficiencyCategory.Advisory || (defCategory === deficiencyCategory.Dangerous && stdForProhibition && !prohibitionIssued)) - ) { - return { validateDefectNotes: true }; - } - } - return null; - }; - - static validateProhibitionIssued: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { - if (control?.parent) { - const defCategory = control.parent.get('deficiencyCategory')?.value as deficiencyCategory; - const stdForProhibition = control.parent.get('stdForProhibition')?.value as boolean; - const prohibitionIssued = control.value as boolean; - - if (defCategory === deficiencyCategory.Dangerous && !stdForProhibition && !prohibitionIssued) { - return { validateProhibitionIssued: true }; - } - } - return null; - }; + static validateDefectNotes: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { + if (control?.parent && control.parent.parent) { + const grandParent = control.parent.parent; + const defCategory = grandParent?.get('deficiencyCategory')?.value as deficiencyCategory; + const prohibitionIssued = grandParent.get('prohibitionIssued')?.value as boolean; + const stdForProhibition = grandParent.get('stdForProhibition')?.value as boolean; + + const imNumber: string = grandParent.get('imNumber')?.value ? `${grandParent.get('imNumber')?.value}.` : ''; + const itemNumber: string = grandParent.get('itemNumber')?.value ? `${grandParent.get('itemNumber')?.value}.` : ''; + const deficiencyId: string = grandParent.get('deficiencyId')?.value + ? `${grandParent.get('deficiencyId')?.value}.` + : ''; + const deficiencySubId: string = grandParent.get('deficiencySubId')?.value ?? ''; + + const defectType = imNumber + itemNumber + deficiencyId + deficiencySubId; + + const optionalDefectNotes = ['43.1.a.ii', '41.1.a.ii', '10.1.iii']; + + if (optionalDefectNotes.includes(defectType)) return null; + + if ( + !control.value && + (defCategory === deficiencyCategory.Advisory || + (defCategory === deficiencyCategory.Dangerous && stdForProhibition && !prohibitionIssued)) + ) { + return { validateDefectNotes: true }; + } + } + return null; + }; + + static validateProhibitionIssued: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { + if (control?.parent) { + const defCategory = control.parent.get('deficiencyCategory')?.value as deficiencyCategory; + const stdForProhibition = control.parent.get('stdForProhibition')?.value as boolean; + const prohibitionIssued = control.value as boolean; + + if (defCategory === deficiencyCategory.Dangerous && !stdForProhibition && !prohibitionIssued) { + return { validateProhibitionIssued: true }; + } + } + return null; + }; } diff --git a/src/app/govuk.d.ts b/src/app/govuk.d.ts index d0201c59fe..da6824e0e0 100644 --- a/src/app/govuk.d.ts +++ b/src/app/govuk.d.ts @@ -1,12 +1,12 @@ declare module 'govuk-frontend/govuk/all' { - export function initAll(): void; + export function initAll(): void; } declare module 'validate-govuk-date' { - export default function validateDate( - day: string | number, - month: string | number, - year: string | number, - fieldName?: string - ): { error: boolean; date?: Date; errors?: [{ error: boolean; reason: string; index: number }] }; + export default function validateDate( + day: string | number, + month: string | number, + year: string | number, + fieldName?: string + ): { error: boolean; date?: Date; errors?: [{ error: boolean; reason: string; index: number }] }; } diff --git a/src/app/guards/cancel-edit-tech/cancel-edit-tech.guard.spec.ts b/src/app/guards/cancel-edit-tech/cancel-edit-tech.guard.spec.ts index 789ff8425d..cc446e3ad6 100644 --- a/src/app/guards/cancel-edit-tech/cancel-edit-tech.guard.spec.ts +++ b/src/app/guards/cancel-edit-tech/cancel-edit-tech.guard.spec.ts @@ -6,25 +6,25 @@ import { provideMockStore } from '@ngrx/store/testing'; import { CancelEditTechGuard } from './cancel-edit-tech.guard'; describe('CancelEditTechGuard', () => { - let guard: CancelEditTechGuard; + let guard: CancelEditTechGuard; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [RouterTestingModule], - providers: [ - CancelEditTechGuard, - provideMockStore({}), - { provide: RouterStateSnapshot, useValue: jest.fn().mockReturnValue({ url: '', toString: jest.fn() }) }, - ], - }); - guard = TestBed.inject(CancelEditTechGuard); - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + providers: [ + CancelEditTechGuard, + provideMockStore({}), + { provide: RouterStateSnapshot, useValue: jest.fn().mockReturnValue({ url: '', toString: jest.fn() }) }, + ], + }); + guard = TestBed.inject(CancelEditTechGuard); + }); - it('should be created', () => { - expect(guard).toBeTruthy(); - }); + it('should be created', () => { + expect(guard).toBeTruthy(); + }); - it('should return true', () => { - expect(guard.canDeactivate()).toBeTruthy(); - }); + it('should return true', () => { + expect(guard.canDeactivate()).toBeTruthy(); + }); }); diff --git a/src/app/guards/cancel-edit-tech/cancel-edit-tech.guard.ts b/src/app/guards/cancel-edit-tech/cancel-edit-tech.guard.ts index a0a5b53f65..7ccc519456 100644 --- a/src/app/guards/cancel-edit-tech/cancel-edit-tech.guard.ts +++ b/src/app/guards/cancel-edit-tech/cancel-edit-tech.guard.ts @@ -6,18 +6,18 @@ import { updateEditingTechRecordCancel } from '@store/technical-records'; import { TechRecordComponent } from 'src/app/features/tech-record/tech-record.component'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class CancelEditTechGuard implements CanDeactivate, CanActivate { - constructor(private store: Store) {} + constructor(private store: Store) {} - canActivate(): boolean { - this.store.dispatch(updateEditingTechRecordCancel()); - return true; - } + canActivate(): boolean { + this.store.dispatch(updateEditingTechRecordCancel()); + return true; + } - canDeactivate(): boolean { - this.store.dispatch(updateEditingTechRecordCancel()); - return true; - } + canDeactivate(): boolean { + this.store.dispatch(updateEditingTechRecordCancel()); + return true; + } } diff --git a/src/app/guards/cancel-edit-test/cancel-edit-test.guard.spec.ts b/src/app/guards/cancel-edit-test/cancel-edit-test.guard.spec.ts index 2a170b7583..14ddd1d729 100644 --- a/src/app/guards/cancel-edit-test/cancel-edit-test.guard.spec.ts +++ b/src/app/guards/cancel-edit-test/cancel-edit-test.guard.spec.ts @@ -5,26 +5,26 @@ import { provideMockStore } from '@ngrx/store/testing'; import { CancelEditTestGuard } from './cancel-edit-test.guard'; describe('NoEditGuard', () => { - let guard: CancelEditTestGuard; + let guard: CancelEditTestGuard; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [RouterTestingModule], - providers: [ - CancelEditTestGuard, - provideMockStore({}), - { provide: RouterStateSnapshot, useValue: jest.fn().mockReturnValue({ url: '', toString: jest.fn() }) }, - ], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + providers: [ + CancelEditTestGuard, + provideMockStore({}), + { provide: RouterStateSnapshot, useValue: jest.fn().mockReturnValue({ url: '', toString: jest.fn() }) }, + ], + }); - guard = TestBed.inject(CancelEditTestGuard); - }); + guard = TestBed.inject(CancelEditTestGuard); + }); - it('should be created', () => { - expect(guard).toBeTruthy(); - }); + it('should be created', () => { + expect(guard).toBeTruthy(); + }); - it('should return true', () => { - expect(guard.canDeactivate()).toBeTruthy(); - }); + it('should return true', () => { + expect(guard.canDeactivate()).toBeTruthy(); + }); }); diff --git a/src/app/guards/cancel-edit-test/cancel-edit-test.guard.ts b/src/app/guards/cancel-edit-test/cancel-edit-test.guard.ts index f11ace2f71..dd5cd72969 100644 --- a/src/app/guards/cancel-edit-test/cancel-edit-test.guard.ts +++ b/src/app/guards/cancel-edit-test/cancel-edit-test.guard.ts @@ -7,13 +7,13 @@ import { cancelEditingTestResult } from '@store/test-records'; import { TestRecordComponent } from 'src/app/features/test-records/amend/views/test-record/test-record.component'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class CancelEditTestGuard implements CanDeactivate { - constructor(private store: Store) {} + constructor(private store: Store) {} - canDeactivate(): boolean { - this.store.dispatch(cancelEditingTestResult()); - return true; - } + canDeactivate(): boolean { + this.store.dispatch(cancelEditingTestResult()); + return true; + } } diff --git a/src/app/guards/feature-toggle-guard/feature-toggle.guard.spec.ts b/src/app/guards/feature-toggle-guard/feature-toggle.guard.spec.ts index 8017d9c8bd..540d94ce3a 100644 --- a/src/app/guards/feature-toggle-guard/feature-toggle.guard.spec.ts +++ b/src/app/guards/feature-toggle-guard/feature-toggle.guard.spec.ts @@ -5,55 +5,51 @@ import { FeatureToggleService } from '@services/feature-toggle-service/feature-t import { FeatureToggleGuard } from './feature-toggle.guard'; describe('feature toggle guard', () => { - let guard: FeatureToggleGuard; + let guard: FeatureToggleGuard; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [RouterTestingModule], - providers: [ - FeatureToggleGuard, - { provide: FeatureToggleService, useValue: { isFeatureEnabled: () => true } }, - ], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + providers: [FeatureToggleGuard, { provide: FeatureToggleService, useValue: { isFeatureEnabled: () => true } }], + }); - guard = TestBed.inject(FeatureToggleGuard); - }); + guard = TestBed.inject(FeatureToggleGuard); + }); - it('should be created', () => { - expect(guard).toBeTruthy(); - }); + it('should be created', () => { + expect(guard).toBeTruthy(); + }); - it('should return true when the feature is enabled', () => { - const next = new ActivatedRouteSnapshot(); - next.data = { featureToggleName: 'testToggle' }; + it('should return true when the feature is enabled', () => { + const next = new ActivatedRouteSnapshot(); + next.data = { featureToggleName: 'testToggle' }; - jest.spyOn(TestBed.inject(FeatureToggleService), 'isFeatureEnabled').mockReturnValue(true); + jest.spyOn(TestBed.inject(FeatureToggleService), 'isFeatureEnabled').mockReturnValue(true); - const guardResponse = guard.canActivate(next); + const guardResponse = guard.canActivate(next); - expect(guardResponse).toBeTruthy(); - }); + expect(guardResponse).toBeTruthy(); + }); - it('should return false when the feature is disabled', () => { - const next = new ActivatedRouteSnapshot(); - next.data = { featureToggleName: 'testToggle' }; + it('should return false when the feature is disabled', () => { + const next = new ActivatedRouteSnapshot(); + next.data = { featureToggleName: 'testToggle' }; - jest.spyOn(TestBed.inject(FeatureToggleService), 'isFeatureEnabled').mockReturnValue(false); + jest.spyOn(TestBed.inject(FeatureToggleService), 'isFeatureEnabled').mockReturnValue(false); - const guardResponse = guard.canActivate(next); + const guardResponse = guard.canActivate(next); - expect(guardResponse).toBeFalsy(); - }); + expect(guardResponse).toBeFalsy(); + }); - it('should return false when no feature is given', () => { - const next = new ActivatedRouteSnapshot(); - next.data = { }; + it('should return false when no feature is given', () => { + const next = new ActivatedRouteSnapshot(); + next.data = {}; - jest.spyOn(TestBed.inject(FeatureToggleService), 'isFeatureEnabled').mockReturnValue(true); + jest.spyOn(TestBed.inject(FeatureToggleService), 'isFeatureEnabled').mockReturnValue(true); - const guardResponse = guard.canActivate(next); - - expect(guardResponse).toBeFalsy(); - }); + const guardResponse = guard.canActivate(next); + expect(guardResponse).toBeFalsy(); + }); }); diff --git a/src/app/guards/feature-toggle-guard/feature-toggle.guard.ts b/src/app/guards/feature-toggle-guard/feature-toggle.guard.ts index 4358d6ecfe..808847be07 100644 --- a/src/app/guards/feature-toggle-guard/feature-toggle.guard.ts +++ b/src/app/guards/feature-toggle-guard/feature-toggle.guard.ts @@ -3,17 +3,17 @@ import { ActivatedRouteSnapshot, CanActivate } from '@angular/router'; import { FeatureToggleService } from '@services/feature-toggle-service/feature-toggle-service'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class FeatureToggleGuard implements CanActivate { - constructor(private featureToggleService: FeatureToggleService) {} + constructor(private featureToggleService: FeatureToggleService) {} - canActivate(next: ActivatedRouteSnapshot): boolean { - const feature = next.data['featureToggleName']; + canActivate(next: ActivatedRouteSnapshot): boolean { + const feature = next.data['featureToggleName']; - if (feature) { - return this.featureToggleService.isFeatureEnabled(feature); - } - return false; - } + if (feature) { + return this.featureToggleService.isFeatureEnabled(feature); + } + return false; + } } diff --git a/src/app/guards/no-edit/no-edit.guard.spec.ts b/src/app/guards/no-edit/no-edit.guard.spec.ts index 2dd8fb9c72..c90468e99b 100644 --- a/src/app/guards/no-edit/no-edit.guard.spec.ts +++ b/src/app/guards/no-edit/no-edit.guard.spec.ts @@ -8,53 +8,53 @@ import { routeEditable } from '@store/router/selectors/router.selectors'; import { NoEditGuard } from './no-edit.guard'; describe('NoEditGuard', () => { - let guard: NoEditGuard; - let store: MockStore; - let mockRouteEditable: MemoizedSelector, boolean, DefaultProjectorFn>; - let route: ActivatedRoute; - let mockRouterStateSnapshot: RouterStateSnapshot; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [RouterTestingModule], - providers: [ - NoEditGuard, - provideMockStore({}), - { provide: RouterStateSnapshot, useValue: jest.fn().mockReturnValue({ url: '', toString: jest.fn() }) }, - ], - }); - - guard = TestBed.inject(NoEditGuard); - store = TestBed.inject(MockStore); - route = TestBed.inject(ActivatedRoute); - mockRouterStateSnapshot = TestBed.inject(RouterStateSnapshot); - mockRouteEditable = store.overrideSelector(routeEditable, false); - }); - - it('should be created', () => { - expect(guard).toBeTruthy(); - }); - - describe('canActivate', () => { - it('should return true when not in edit mode', (done) => { - guard.canActivate(route.snapshot, mockRouterStateSnapshot).subscribe((result) => { - expect(result).toBeTruthy(); - done(); - }); - }); - - it('should reject navigation and return UrlTree without edit query param', (done) => { - mockRouteEditable.setResult(true); - store.refreshState(); - - mockRouterStateSnapshot.url = '/test-result/1/amended/1?edit=true&sanityCheck=bar'; - - guard.canActivate(route.snapshot, mockRouterStateSnapshot).subscribe((tree) => { - expect(tree instanceof UrlTree).toBeTruthy(); - expect((tree as UrlTree).queryParams['edit']).toBeUndefined(); - expect((tree as UrlTree).queryParams['sanityCheck']).toBe('bar'); - done(); - }); - }); - }); + let guard: NoEditGuard; + let store: MockStore; + let mockRouteEditable: MemoizedSelector, boolean, DefaultProjectorFn>; + let route: ActivatedRoute; + let mockRouterStateSnapshot: RouterStateSnapshot; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + providers: [ + NoEditGuard, + provideMockStore({}), + { provide: RouterStateSnapshot, useValue: jest.fn().mockReturnValue({ url: '', toString: jest.fn() }) }, + ], + }); + + guard = TestBed.inject(NoEditGuard); + store = TestBed.inject(MockStore); + route = TestBed.inject(ActivatedRoute); + mockRouterStateSnapshot = TestBed.inject(RouterStateSnapshot); + mockRouteEditable = store.overrideSelector(routeEditable, false); + }); + + it('should be created', () => { + expect(guard).toBeTruthy(); + }); + + describe('canActivate', () => { + it('should return true when not in edit mode', (done) => { + guard.canActivate(route.snapshot, mockRouterStateSnapshot).subscribe((result) => { + expect(result).toBeTruthy(); + done(); + }); + }); + + it('should reject navigation and return UrlTree without edit query param', (done) => { + mockRouteEditable.setResult(true); + store.refreshState(); + + mockRouterStateSnapshot.url = '/test-result/1/amended/1?edit=true&sanityCheck=bar'; + + guard.canActivate(route.snapshot, mockRouterStateSnapshot).subscribe((tree) => { + expect(tree instanceof UrlTree).toBeTruthy(); + expect((tree as UrlTree).queryParams['edit']).toBeUndefined(); + expect((tree as UrlTree).queryParams['sanityCheck']).toBe('bar'); + done(); + }); + }); + }); }); diff --git a/src/app/guards/no-edit/no-edit.guard.ts b/src/app/guards/no-edit/no-edit.guard.ts index 3aeee845c1..1edd1658b0 100644 --- a/src/app/guards/no-edit/no-edit.guard.ts +++ b/src/app/guards/no-edit/no-edit.guard.ts @@ -1,31 +1,32 @@ import { Injectable } from '@angular/core'; -import { - ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree, -} from '@angular/router'; -import { select, Store } from '@ngrx/store'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router'; +import { Store, select } from '@ngrx/store'; import { State } from '@store/.'; import { routeEditable } from '@store/router/selectors/router.selectors'; -import { map, Observable } from 'rxjs'; +import { Observable, map } from 'rxjs'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class NoEditGuard implements CanActivate { - constructor(private store: Store, private router: Router) {} + constructor( + private store: Store, + private router: Router + ) {} - canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { - return this.store.pipe( - select(routeEditable), - map((editable) => { - if (!editable) { - return true; - } + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return this.store.pipe( + select(routeEditable), + map((editable) => { + if (!editable) { + return true; + } - const tree = this.router.parseUrl(state.url); - delete tree.queryParams['edit']; + const tree = this.router.parseUrl(state.url); + delete tree.queryParams['edit']; - return tree; - }), - ); - } + return tree; + }) + ); + } } diff --git a/src/app/guards/no-query-params/no-query-params.guard.spec.ts b/src/app/guards/no-query-params/no-query-params.guard.spec.ts index 736f6604b5..2096327fed 100644 --- a/src/app/guards/no-query-params/no-query-params.guard.spec.ts +++ b/src/app/guards/no-query-params/no-query-params.guard.spec.ts @@ -2,85 +2,87 @@ import { TestBed } from '@angular/core/testing'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { State } from '@store/.'; -import { - Navigation, NavigationExtras, Params, Router, RouterStateSnapshot, UrlTree, -} from '@angular/router'; +import { Navigation, NavigationExtras, Params, Router, RouterStateSnapshot, UrlTree } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { selectQueryParams } from '@store/router/selectors/router.selectors'; import { NoQueryParamsGuard } from './no-query-params.guard'; describe('NoQueryParamsGuard', () => { - let guard: NoQueryParamsGuard; - let store: MockStore; - let router: Router; + let guard: NoQueryParamsGuard; + let store: MockStore; + let router: Router; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [RouterTestingModule], - providers: [NoQueryParamsGuard, provideMockStore({}), { provide: RouterStateSnapshot, useValue: jest.fn().mockReturnValue({ url: '' }) }], - }); - guard = TestBed.inject(NoQueryParamsGuard); - store = TestBed.inject(MockStore); - store.overrideSelector(selectQueryParams, {}); - router = TestBed.inject(Router); - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + providers: [ + NoQueryParamsGuard, + provideMockStore({}), + { provide: RouterStateSnapshot, useValue: jest.fn().mockReturnValue({ url: '' }) }, + ], + }); + guard = TestBed.inject(NoQueryParamsGuard); + store = TestBed.inject(MockStore); + store.overrideSelector(selectQueryParams, {}); + router = TestBed.inject(Router); + }); - it('should be created', () => { - expect(guard).toBeTruthy(); - }); + it('should be created', () => { + expect(guard).toBeTruthy(); + }); - describe('No query params guard', () => { - it('should return true if there are query params', (done) => { - store.overrideSelector(selectQueryParams, { foo: 'bar' } as Params); - guard.canActivate().subscribe((result) => { - expect(result).toBe(true); - done(); - }); - }); + describe('No query params guard', () => { + it('should return true if there are query params', (done) => { + store.overrideSelector(selectQueryParams, { foo: 'bar' } as Params); + guard.canActivate().subscribe((result) => { + expect(result).toBe(true); + done(); + }); + }); - it('should return an empty url when the previous navigation is undefined', (done) => { - const mockNavigation: Navigation = { - id: 1, - initialUrl: '/some/path' as unknown as UrlTree, - extractedUrl: {} as UrlTree, - trigger: 'hashchange', - extras: {} as NavigationExtras, - previousNavigation: {} as Navigation, - }; - router.getCurrentNavigation = jest.fn().mockReturnValue(mockNavigation); - guard.canActivate().subscribe((tree) => { - expect(tree instanceof UrlTree).toBeTruthy(); - expect((tree as UrlTree).toString()).toBe('/'); - done(); - }); - }); + it('should return an empty url when the previous navigation is undefined', (done) => { + const mockNavigation: Navigation = { + id: 1, + initialUrl: '/some/path' as unknown as UrlTree, + extractedUrl: {} as UrlTree, + trigger: 'hashchange', + extras: {} as NavigationExtras, + previousNavigation: {} as Navigation, + }; + router.getCurrentNavigation = jest.fn().mockReturnValue(mockNavigation); + guard.canActivate().subscribe((tree) => { + expect(tree instanceof UrlTree).toBeTruthy(); + expect((tree as UrlTree).toString()).toBe('/'); + done(); + }); + }); - it('should return the previous Url if the previous navigation is defined', (done) => { - const mockNavigation: Navigation = { - id: 1, - initialUrl: '/some/path' as unknown as UrlTree, - extractedUrl: {} as UrlTree, - trigger: 'hashchange', - extras: {} as NavigationExtras, - previousNavigation: {} as Navigation, - }; + it('should return the previous Url if the previous navigation is defined', (done) => { + const mockNavigation: Navigation = { + id: 1, + initialUrl: '/some/path' as unknown as UrlTree, + extractedUrl: {} as UrlTree, + trigger: 'hashchange', + extras: {} as NavigationExtras, + previousNavigation: {} as Navigation, + }; - const tree = router.parseUrl('/path'); + const tree = router.parseUrl('/path'); - const previousNavigation: Navigation = { - ...mockNavigation, - previousNavigation: { - ...mockNavigation, - finalUrl: tree, - }, - }; - router.getCurrentNavigation = jest.fn().mockReturnValue(previousNavigation); - guard.canActivate().subscribe((url_tree) => { - expect(url_tree instanceof UrlTree).toBeTruthy(); - expect(previousNavigation.previousNavigation?.finalUrl?.toString()).toBeTruthy(); - expect(url_tree.toString()).toEqual(previousNavigation.previousNavigation?.finalUrl?.toString()); - done(); - }); - }); - }); + const previousNavigation: Navigation = { + ...mockNavigation, + previousNavigation: { + ...mockNavigation, + finalUrl: tree, + }, + }; + router.getCurrentNavigation = jest.fn().mockReturnValue(previousNavigation); + guard.canActivate().subscribe((url_tree) => { + expect(url_tree instanceof UrlTree).toBeTruthy(); + expect(previousNavigation.previousNavigation?.finalUrl?.toString()).toBeTruthy(); + expect(url_tree.toString()).toEqual(previousNavigation.previousNavigation?.finalUrl?.toString()); + done(); + }); + }); + }); }); diff --git a/src/app/guards/no-query-params/no-query-params.guard.ts b/src/app/guards/no-query-params/no-query-params.guard.ts index 31dbe03c18..084b47472c 100644 --- a/src/app/guards/no-query-params/no-query-params.guard.ts +++ b/src/app/guards/no-query-params/no-query-params.guard.ts @@ -1,24 +1,27 @@ import { Injectable } from '@angular/core'; import { CanActivate, Router, UrlTree } from '@angular/router'; -import { select, Store } from '@ngrx/store'; +import { Store, select } from '@ngrx/store'; import { State } from '@store/.'; import { selectQueryParams } from '@store/router/selectors/router.selectors'; -import { map, Observable } from 'rxjs'; +import { Observable, map } from 'rxjs'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class NoQueryParamsGuard implements CanActivate { - constructor(private store: Store, private router: Router) {} - canActivate(): Observable { - return this.store.pipe( - select(selectQueryParams), - map((queryParams) => { - if (!Object.keys(queryParams).length) { - return this.router.getCurrentNavigation()?.previousNavigation?.finalUrl ?? this.router.parseUrl(''); - } - return true; - }), - ); - } + constructor( + private store: Store, + private router: Router + ) {} + canActivate(): Observable { + return this.store.pipe( + select(selectQueryParams), + map((queryParams) => { + if (!Object.keys(queryParams).length) { + return this.router.getCurrentNavigation()?.previousNavigation?.finalUrl ?? this.router.parseUrl(''); + } + return true; + }) + ); + } } diff --git a/src/app/guards/role-guard/roles.guard.spec.ts b/src/app/guards/role-guard/roles.guard.spec.ts index 06d009a6b3..4aaa0c557d 100644 --- a/src/app/guards/role-guard/roles.guard.spec.ts +++ b/src/app/guards/role-guard/roles.guard.spec.ts @@ -1,57 +1,57 @@ import { TestBed } from '@angular/core/testing'; import { ActivatedRouteSnapshot } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; +import { InteractionStatus } from '@azure/msal-browser'; import { provideMockStore } from '@ngrx/store/testing'; import { UserService } from '@services/user-service/user-service'; import { initialAppState } from '@store/.'; -import { of, lastValueFrom } from 'rxjs'; -import { InteractionStatus } from '@azure/msal-browser'; +import { lastValueFrom, of } from 'rxjs'; import { RoleGuard } from './roles.guard'; describe('RoleGuard', () => { - let guard: RoleGuard; + let guard: RoleGuard; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [RouterTestingModule], - providers: [ - RoleGuard, - provideMockStore({ initialState: initialAppState }), - { provide: UserService, useValue: { roles$: of(['CVSFullAccess']), inProgress$: of(InteractionStatus.None) } }, - ], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + providers: [ + RoleGuard, + provideMockStore({ initialState: initialAppState }), + { provide: UserService, useValue: { roles$: of(['CVSFullAccess']), inProgress$: of(InteractionStatus.None) } }, + ], + }); - guard = TestBed.inject(RoleGuard); - }); + guard = TestBed.inject(RoleGuard); + }); - it('should be created', () => { - expect(guard).toBeTruthy(); - }); + it('should be created', () => { + expect(guard).toBeTruthy(); + }); - it('should return true when I give it the correct role', async () => { - const next = new ActivatedRouteSnapshot(); - next.data = { roles: ['CVSFullAccess'] }; + it('should return true when I give it the correct role', async () => { + const next = new ActivatedRouteSnapshot(); + next.data = { roles: ['CVSFullAccess'] }; - const guardObservable = guard.canActivate(next); + const guardObservable = guard.canActivate(next); - await expect(lastValueFrom(guardObservable)).resolves.toBe(true); - }); + await expect(lastValueFrom(guardObservable)).resolves.toBe(true); + }); - it('should return false when I give it the incorrect role', async () => { - const next = new ActivatedRouteSnapshot(); - next.data = { roles: ['BadRole'] }; + it('should return false when I give it the incorrect role', async () => { + const next = new ActivatedRouteSnapshot(); + next.data = { roles: ['BadRole'] }; - const guardObservable = guard.canActivate(next); + const guardObservable = guard.canActivate(next); - await expect(lastValueFrom(guardObservable)).resolves.toBe(false); - }); + await expect(lastValueFrom(guardObservable)).resolves.toBe(false); + }); - it('should return true when I give it one incorrect role and one correct role', async () => { - const next = new ActivatedRouteSnapshot(); - next.data = { roles: ['CVSFullAccess', 'BadRole'] }; + it('should return true when I give it one incorrect role and one correct role', async () => { + const next = new ActivatedRouteSnapshot(); + next.data = { roles: ['CVSFullAccess', 'BadRole'] }; - const guardObservable = guard.canActivate(next); + const guardObservable = guard.canActivate(next); - await expect(lastValueFrom(guardObservable)).resolves.toBe(true); - }); + await expect(lastValueFrom(guardObservable)).resolves.toBe(true); + }); }); diff --git a/src/app/guards/role-guard/roles.guard.ts b/src/app/guards/role-guard/roles.guard.ts index 4db0963c14..bf3d6777bd 100644 --- a/src/app/guards/role-guard/roles.guard.ts +++ b/src/app/guards/role-guard/roles.guard.ts @@ -2,23 +2,21 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, CanActivate } from '@angular/router'; import { InteractionStatus } from '@azure/msal-browser'; import { UserService } from '@services/user-service/user-service'; -import { - filter, map, Observable, switchMap, -} from 'rxjs'; +import { Observable, filter, map, switchMap } from 'rxjs'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class RoleGuard implements CanActivate { - constructor(private userService: UserService) {} + constructor(private userService: UserService) {} - canActivate(next: ActivatedRouteSnapshot): Observable { - return this.userService.inProgress$.pipe( - filter((status: InteractionStatus) => InteractionStatus.None === status), - switchMap(() => this.userService.roles$), - map((roles) => { - return roles?.some((x) => next.data['roles'].includes(x)) || false; - }), - ); - } + canActivate(next: ActivatedRouteSnapshot): Observable { + return this.userService.inProgress$.pipe( + filter((status: InteractionStatus) => InteractionStatus.None === status), + switchMap(() => this.userService.roles$), + map((roles) => { + return roles?.some((x) => next.data['roles'].includes(x)) || false; + }) + ); + } } diff --git a/src/app/interceptors/delayed-retry/delayed-retry.interceptor.spec.ts b/src/app/interceptors/delayed-retry/delayed-retry.interceptor.spec.ts index b5f95ee123..4e98843a3d 100644 --- a/src/app/interceptors/delayed-retry/delayed-retry.interceptor.spec.ts +++ b/src/app/interceptors/delayed-retry/delayed-retry.interceptor.spec.ts @@ -1,118 +1,114 @@ import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { - TestBed, - fakeAsync, flush, - tick, -} from '@angular/core/testing'; +import { TestBed, fakeAsync, flush, tick } from '@angular/core/testing'; import { provideMockStore } from '@ngrx/store/testing'; import { initialAppState } from '@store/index'; import { DelayedRetryInterceptor, HTTP_RETRY_CONFIG } from './delayed-retry.interceptor'; describe('DelayedRetryInterceptor', () => { - let httpTestingController: HttpTestingController; - let client: HttpClient; - let interceptor: DelayedRetryInterceptor; + let httpTestingController: HttpTestingController; + let client: HttpClient; + let interceptor: DelayedRetryInterceptor; - const DUMMY_ENDPOINT = 'https://www.someapi.com'; + const DUMMY_ENDPOINT = 'https://www.someapi.com'; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - DelayedRetryInterceptor, - { - provide: HTTP_INTERCEPTORS, - useClass: DelayedRetryInterceptor, - multi: true, - }, - provideMockStore({ initialState: initialAppState }), - ], - }); - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + DelayedRetryInterceptor, + { + provide: HTTP_INTERCEPTORS, + useClass: DelayedRetryInterceptor, + multi: true, + }, + provideMockStore({ initialState: initialAppState }), + ], + }); + }); - describe('default config', () => { - it('should be created', () => { - interceptor = TestBed.inject(DelayedRetryInterceptor); - expect(interceptor).toBeTruthy(); - expect(interceptor.config).toEqual({ - count: 3, - delay: 2000, - backoff: false, - whiteList: [], - }); - }); - }); + describe('default config', () => { + it('should be created', () => { + interceptor = TestBed.inject(DelayedRetryInterceptor); + expect(interceptor).toBeTruthy(); + expect(interceptor.config).toEqual({ + count: 3, + delay: 2000, + backoff: false, + whiteList: [], + }); + }); + }); - describe('no backof', () => { - beforeEach(() => { - TestBed.overrideProvider(HTTP_RETRY_CONFIG, { useValue: { delay: 500, count: 3, httpStatusRetry: [504] } }); - client = TestBed.inject(HttpClient); - httpTestingController = TestBed.inject(HttpTestingController); - interceptor = TestBed.inject(DelayedRetryInterceptor); - }); + describe('no backof', () => { + beforeEach(() => { + TestBed.overrideProvider(HTTP_RETRY_CONFIG, { useValue: { delay: 500, count: 3, httpStatusRetry: [504] } }); + client = TestBed.inject(HttpClient); + httpTestingController = TestBed.inject(HttpTestingController); + interceptor = TestBed.inject(DelayedRetryInterceptor); + }); - afterEach(() => { - // After every test, assert that there are no more pending requests. - httpTestingController.verify(); - }); + afterEach(() => { + // After every test, assert that there are no more pending requests. + httpTestingController.verify(); + }); - it('should throw error "Request timed out. Check connectivity and try again." after final retry', fakeAsync(() => { - client.get(DUMMY_ENDPOINT).subscribe({ - error: (e) => { - expect(e).toEqual(new Error('Request timed out. Check connectivity and try again.')); - }, - }); - const retryCount = 3; - for (let i = 0, c = retryCount; i < c; i++) { - tick(500); - const req = httpTestingController.expectOne(DUMMY_ENDPOINT); - req.flush('Deliberate 504 error', { status: 504, statusText: 'Gateway Timeout' }); - } - flush(); - })); + it('should throw error "Request timed out. Check connectivity and try again." after final retry', fakeAsync(() => { + client.get(DUMMY_ENDPOINT).subscribe({ + error: (e) => { + expect(e).toEqual(new Error('Request timed out. Check connectivity and try again.')); + }, + }); + const retryCount = 3; + for (let i = 0, c = retryCount; i < c; i++) { + tick(500); + const req = httpTestingController.expectOne(DUMMY_ENDPOINT); + req.flush('Deliberate 504 error', { status: 504, statusText: 'Gateway Timeout' }); + } + flush(); + })); - it('should cascade errors not in the retry list', (done) => { - client.get(DUMMY_ENDPOINT).subscribe({ - error: (e) => { - const { error, status, statusText } = e; - expect(error).toBe('Deliberate 401 error'); - expect(status).toBe(401); - expect(statusText).toBe('401 Unauthorized'); - done(); - }, - }); - const req = httpTestingController.expectOne(DUMMY_ENDPOINT); - req.flush('Deliberate 401 error', { status: 401, statusText: '401 Unauthorized' }); - }); - }); + it('should cascade errors not in the retry list', (done) => { + client.get(DUMMY_ENDPOINT).subscribe({ + error: (e) => { + const { error, status, statusText } = e; + expect(error).toBe('Deliberate 401 error'); + expect(status).toBe(401); + expect(statusText).toBe('401 Unauthorized'); + done(); + }, + }); + const req = httpTestingController.expectOne(DUMMY_ENDPOINT); + req.flush('Deliberate 401 error', { status: 401, statusText: '401 Unauthorized' }); + }); + }); - describe('backoff', () => { - beforeEach(() => { - TestBed.overrideProvider(HTTP_RETRY_CONFIG, { useValue: { count: 3, delay: 500, backoff: true } }); - client = TestBed.inject(HttpClient); - httpTestingController = TestBed.inject(HttpTestingController); - }); + describe('backoff', () => { + beforeEach(() => { + TestBed.overrideProvider(HTTP_RETRY_CONFIG, { useValue: { count: 3, delay: 500, backoff: true } }); + client = TestBed.inject(HttpClient); + httpTestingController = TestBed.inject(HttpTestingController); + }); - afterEach(() => { - // After every test, assert that there are no more pending requests. - httpTestingController.verify(); - }); + afterEach(() => { + // After every test, assert that there are no more pending requests. + httpTestingController.verify(); + }); - it('should stagger retry requests', fakeAsync(() => { - client.get(DUMMY_ENDPOINT).subscribe({ - error: (e) => { - expect(e).toEqual(new Error('Request timed out. Check connectivity and try again.')); - }, - }); + it('should stagger retry requests', fakeAsync(() => { + client.get(DUMMY_ENDPOINT).subscribe({ + error: (e) => { + expect(e).toEqual(new Error('Request timed out. Check connectivity and try again.')); + }, + }); - const retryCount = 3; - for (let i = 0; i < retryCount; i++) { - tick(500 * (i + 1)); - const req = httpTestingController.expectOne(DUMMY_ENDPOINT); - req.flush('Deliberate 504 error', { status: 504, statusText: 'Gateway Timeout' }); - } - flush(); - })); - }); + const retryCount = 3; + for (let i = 0; i < retryCount; i++) { + tick(500 * (i + 1)); + const req = httpTestingController.expectOne(DUMMY_ENDPOINT); + req.flush('Deliberate 504 error', { status: 504, statusText: 'Gateway Timeout' }); + } + flush(); + })); + }); }); diff --git a/src/app/interceptors/delayed-retry/delayed-retry.interceptor.ts b/src/app/interceptors/delayed-retry/delayed-retry.interceptor.ts index ab0eda8253..3ca28337bf 100644 --- a/src/app/interceptors/delayed-retry/delayed-retry.interceptor.ts +++ b/src/app/interceptors/delayed-retry/delayed-retry.interceptor.ts @@ -1,98 +1,92 @@ -import { - HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, -} from '@angular/common/http'; -import { - Inject, Injectable, InjectionToken, Optional, -} from '@angular/core'; +import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; +import { Inject, Injectable, InjectionToken, Optional } from '@angular/core'; import { Store } from '@ngrx/store'; import { State } from '@store/index'; import { retryInterceptorFailure } from '@store/retry-interceptor/actions/retry-interceptor.actions'; import { setSpinnerState } from '@store/spinner/actions/spinner.actions'; -import { - Observable, - retry, - throwError, - timer, -} from 'rxjs'; +import { Observable, retry, throwError, timer } from 'rxjs'; export const HTTP_RETRY_CONFIG = new InjectionToken('HttpRetryConfig'); export interface HttpRetryConfig { - /** - * The maximum number of times to retry. - */ - count?: number; - /** - * The number of milliseconds to delay before retrying. - */ - delay?: number; - /** - * Array of http status codes to retry. If undefined, all requests are retried. - */ - httpStatusRetry?: Array; - /** - * If true, each retry delay will be multiplied by the current retry count. - */ - backoff?: boolean; + /** + * The maximum number of times to retry. + */ + count?: number; + /** + * The number of milliseconds to delay before retrying. + */ + delay?: number; + /** + * Array of http status codes to retry. If undefined, all requests are retried. + */ + httpStatusRetry?: Array; + /** + * If true, each retry delay will be multiplied by the current retry count. + */ + backoff?: boolean; - whiteList?: string[] + whiteList?: string[]; } -interface InternalConfig extends Required>, Pick { - whiteList: string[] +interface InternalConfig + extends Required>, + Pick { + whiteList: string[]; } @Injectable() export class DelayedRetryInterceptor implements HttpInterceptor { - config: InternalConfig; + config: InternalConfig; - private readonly defaultConfig = { - count: 3, - delay: 2000, - backoff: false, - whiteList: [], - }; + private readonly defaultConfig = { + count: 3, + delay: 2000, + backoff: false, + whiteList: [], + }; - constructor(@Optional() @Inject(HTTP_RETRY_CONFIG) private retryConfig: HttpRetryConfig, private store: Store) { - this.config = { ...this.defaultConfig, ...this.retryConfig }; - } + constructor( + @Optional() @Inject(HTTP_RETRY_CONFIG) private retryConfig: HttpRetryConfig, + private store: Store + ) { + this.config = { ...this.defaultConfig, ...this.retryConfig }; + } - intercept(request: HttpRequest, next: HttpHandler): Observable> { - return next.handle(request).pipe(retry({ - delay: (error, retryCount: number) => { - try { - return this.retryHandler(error, retryCount, this.config, request); - } catch (httpError: unknown) { - return throwError(() => { - this.store.dispatch(setSpinnerState({ showSpinner: false })); - this.store.dispatch(retryInterceptorFailure( - { error }, - )); - return httpError; - }); - } - }, - })); - } + intercept(request: HttpRequest, next: HttpHandler): Observable> { + return next.handle(request).pipe( + retry({ + delay: (error, retryCount: number) => { + try { + return this.retryHandler(error, retryCount, this.config, request); + } catch (httpError: unknown) { + return throwError(() => { + this.store.dispatch(setSpinnerState({ showSpinner: false })); + this.store.dispatch(retryInterceptorFailure({ error })); + return httpError; + }); + } + }, + }) + ); + } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - retryHandler(error: any, retryCount: number, config: InternalConfig, request: HttpRequest) { - const { - delay, count, httpStatusRetry, backoff, whiteList, - } = config; - const { status } = error; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + retryHandler(error: any, retryCount: number, config: InternalConfig, request: HttpRequest) { + const { delay, count, httpStatusRetry, backoff, whiteList } = config; + const { status } = error; - if (retryCount < count && whiteList.some((url) => request.url.includes(url))) { - return timer(backoff ? delay * retryCount : delay); - } + if (retryCount < count && whiteList.some((url) => request.url.includes(url))) { + return timer(backoff ? delay * retryCount : delay); + } - if (httpStatusRetry && !httpStatusRetry.includes(status)) { - throw error; - } + if (httpStatusRetry && !httpStatusRetry.includes(status)) { + throw error; + } - if (retryCount >= count) { - throw new Error('Request timed out. Check connectivity and try again.'); - } - return timer(backoff ? delay * retryCount : delay); - } + if (retryCount >= count) { + throw new Error('Request timed out. Check connectivity and try again.'); + } + return timer(backoff ? delay * retryCount : delay); + } } diff --git a/src/app/interceptors/delayed-retry/delayed-retry.module.ts b/src/app/interceptors/delayed-retry/delayed-retry.module.ts index 7924f4ee4d..30b8321cc4 100644 --- a/src/app/interceptors/delayed-retry/delayed-retry.module.ts +++ b/src/app/interceptors/delayed-retry/delayed-retry.module.ts @@ -1,32 +1,30 @@ import { CommonModule } from '@angular/common'; import { HTTP_INTERCEPTORS } from '@angular/common/http'; -import { - ModuleWithProviders, NgModule, Optional, SkipSelf, -} from '@angular/core'; -import { DelayedRetryInterceptor, HttpRetryConfig, HTTP_RETRY_CONFIG } from './delayed-retry.interceptor'; +import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; +import { DelayedRetryInterceptor, HTTP_RETRY_CONFIG, HttpRetryConfig } from './delayed-retry.interceptor'; @NgModule({ - declarations: [], - imports: [CommonModule], - providers: [ - { - provide: HTTP_INTERCEPTORS, - useClass: DelayedRetryInterceptor, - multi: true, - }, - ], + declarations: [], + imports: [CommonModule], + providers: [ + { + provide: HTTP_INTERCEPTORS, + useClass: DelayedRetryInterceptor, + multi: true, + }, + ], }) export class DelayedRetryModule { - constructor(@Optional() @SkipSelf() parentModule?: DelayedRetryModule) { - if (parentModule) { - throw new Error('DelayedRetryModule is already loaded. Import it in the AppModule only'); - } - } + constructor(@Optional() @SkipSelf() parentModule?: DelayedRetryModule) { + if (parentModule) { + throw new Error('DelayedRetryModule is already loaded. Import it in the AppModule only'); + } + } - static forRoot(config?: HttpRetryConfig): ModuleWithProviders { - return { - ngModule: DelayedRetryModule, - providers: [{ provide: HTTP_RETRY_CONFIG, useValue: config }], - }; - } + static forRoot(config?: HttpRetryConfig): ModuleWithProviders { + return { + ngModule: DelayedRetryModule, + providers: [{ provide: HTTP_RETRY_CONFIG, useValue: config }], + }; + } } diff --git a/src/app/interceptors/error-handling/error-handling.interceptor.spec.ts b/src/app/interceptors/error-handling/error-handling.interceptor.spec.ts index a0a8350397..0177df4752 100644 --- a/src/app/interceptors/error-handling/error-handling.interceptor.spec.ts +++ b/src/app/interceptors/error-handling/error-handling.interceptor.spec.ts @@ -1,89 +1,89 @@ -import { HttpClient, HTTP_INTERCEPTORS } from '@angular/common/http'; +import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { Component } from '@angular/core'; -import { fakeAsync, TestBed, tick } from '@angular/core/testing'; +import { TestBed, fakeAsync, tick } from '@angular/core/testing'; import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { ErrorInterceptor } from './error-handling.interceptor'; @Component({ - selector: 'app-dummy-component', - template: '', + selector: 'app-dummy-component', + template: '', }) class DummyComponent {} describe('ErrorInterceptor', () => { - let router: Router; - let http: HttpClient; - let httpController: HttpTestingController; + let router: Router; + let http: HttpClient; + let httpController: HttpTestingController; - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [DummyComponent], - imports: [ - HttpClientTestingModule, - RouterTestingModule.withRoutes([ - { - path: '', - component: DummyComponent, - }, - { - path: 'error', - component: DummyComponent, - }, - ]), - ], - providers: [ - ErrorInterceptor, - { - provide: HTTP_INTERCEPTORS, - useClass: ErrorInterceptor, - multi: true, - }, - ], - }); - }); + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [DummyComponent], + imports: [ + HttpClientTestingModule, + RouterTestingModule.withRoutes([ + { + path: '', + component: DummyComponent, + }, + { + path: 'error', + component: DummyComponent, + }, + ]), + ], + providers: [ + ErrorInterceptor, + { + provide: HTTP_INTERCEPTORS, + useClass: ErrorInterceptor, + multi: true, + }, + ], + }); + }); - beforeEach(() => { - router = TestBed.inject(Router); - http = TestBed.inject(HttpClient); - httpController = TestBed.inject(HttpTestingController); - jest.clearAllMocks(); - }); + beforeEach(() => { + router = TestBed.inject(Router); + http = TestBed.inject(HttpClient); + httpController = TestBed.inject(HttpTestingController); + jest.clearAllMocks(); + }); - it('should be created', () => { - const interceptor: ErrorInterceptor = TestBed.inject(ErrorInterceptor); + it('should be created', () => { + const interceptor: ErrorInterceptor = TestBed.inject(ErrorInterceptor); - expect(interceptor).toBeTruthy(); - }); + expect(interceptor).toBeTruthy(); + }); - it('should navigate to error page on a 500', fakeAsync(() => { - http.get('http://www.google.com').subscribe({ - next: () => {}, - error: (e) => { - expect(e.status).toBe(500); - }, - }); + it('should navigate to error page on a 500', fakeAsync(() => { + http.get('http://www.google.com').subscribe({ + next: () => {}, + error: (e) => { + expect(e.status).toBe(500); + }, + }); - const req = httpController.expectOne('http://www.google.com'); - req.flush('string', { status: 500, statusText: 'Internal Server Error' }); + const req = httpController.expectOne('http://www.google.com'); + req.flush('string', { status: 500, statusText: 'Internal Server Error' }); - tick(); + tick(); - expect(router.url).toBe('/error'); - })); + expect(router.url).toBe('/error'); + })); - it('should not navigate to error page on a success', fakeAsync(() => { - http.get('http://www.google.com').subscribe({ - next: (response) => { - expect(response).toBe('string'); - }, - error: () => {}, - }); + it('should not navigate to error page on a success', fakeAsync(() => { + http.get('http://www.google.com').subscribe({ + next: (response) => { + expect(response).toBe('string'); + }, + error: () => {}, + }); - const req = httpController.expectOne('http://www.google.com'); - req.flush('string'); - tick(); - expect(router.url).toBe('/'); - })); + const req = httpController.expectOne('http://www.google.com'); + req.flush('string'); + tick(); + expect(router.url).toBe('/'); + })); }); diff --git a/src/app/interceptors/error-handling/error-handling.interceptor.ts b/src/app/interceptors/error-handling/error-handling.interceptor.ts index 5aef1090f5..228eaa28f1 100644 --- a/src/app/interceptors/error-handling/error-handling.interceptor.ts +++ b/src/app/interceptors/error-handling/error-handling.interceptor.ts @@ -1,46 +1,45 @@ -import { - HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, -} from '@angular/common/http'; -import { - Inject, Injectable, InjectionToken, Optional, -} from '@angular/core'; +import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; +import { Inject, Injectable, InjectionToken, Optional } from '@angular/core'; import { Router } from '@angular/router'; import { Observable, catchError, throwError } from 'rxjs'; export const HTTP_RESPONSE_REDIRECT = new InjectionToken('HttpResponseRedirectConfig'); export interface HttpResponseRedirectConfig { - /** - * The status codes to check for. - */ - httpStatusRedirect?: Array; - /** - * The route to redirect to - */ - redirectTo?: string; + /** + * The status codes to check for. + */ + httpStatusRedirect?: Array; + /** + * The route to redirect to + */ + redirectTo?: string; } type InternalConfig = Required>; @Injectable() export class ErrorInterceptor implements HttpInterceptor { - config: InternalConfig; + config: InternalConfig; - private readonly defaultConfig = { httpStatusRedirect: [500], redirectTo: 'error' }; + private readonly defaultConfig = { httpStatusRedirect: [500], redirectTo: 'error' }; - constructor(private router: Router, @Optional() @Inject(HTTP_RESPONSE_REDIRECT) private redirectConfig: HttpResponseRedirectConfig) { - this.config = { ...this.defaultConfig, ...this.redirectConfig }; - } + constructor( + private router: Router, + @Optional() @Inject(HTTP_RESPONSE_REDIRECT) private redirectConfig: HttpResponseRedirectConfig + ) { + this.config = { ...this.defaultConfig, ...this.redirectConfig }; + } - intercept(request: HttpRequest, next: HttpHandler): Observable> { - return next.handle(request).pipe( - catchError((error) => { - if (error instanceof HttpErrorResponse) { - if (this.config.httpStatusRedirect.includes(error.status)) { - void this.router.navigateByUrl(this.config.redirectTo); - } - } - return throwError(() => error); - }), - ); - } + intercept(request: HttpRequest, next: HttpHandler): Observable> { + return next.handle(request).pipe( + catchError((error) => { + if (error instanceof HttpErrorResponse) { + if (this.config.httpStatusRedirect.includes(error.status)) { + void this.router.navigateByUrl(this.config.redirectTo); + } + } + return throwError(() => error); + }) + ); + } } diff --git a/src/app/interceptors/error-handling/error-handling.module.ts b/src/app/interceptors/error-handling/error-handling.module.ts index 4ef9ebbb37..1e1d27ebdb 100644 --- a/src/app/interceptors/error-handling/error-handling.module.ts +++ b/src/app/interceptors/error-handling/error-handling.module.ts @@ -1,32 +1,30 @@ import { CommonModule } from '@angular/common'; import { HTTP_INTERCEPTORS } from '@angular/common/http'; -import { - ModuleWithProviders, NgModule, Optional, SkipSelf, -} from '@angular/core'; -import { ErrorInterceptor, HttpResponseRedirectConfig, HTTP_RESPONSE_REDIRECT } from './error-handling.interceptor'; +import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; +import { ErrorInterceptor, HTTP_RESPONSE_REDIRECT, HttpResponseRedirectConfig } from './error-handling.interceptor'; @NgModule({ - declarations: [], - imports: [CommonModule], - providers: [ - { - provide: HTTP_INTERCEPTORS, - useClass: ErrorInterceptor, - multi: true, - }, - ], + declarations: [], + imports: [CommonModule], + providers: [ + { + provide: HTTP_INTERCEPTORS, + useClass: ErrorInterceptor, + multi: true, + }, + ], }) export class ErrorInterceptorModule { - constructor(@Optional() @SkipSelf() parentModule?: ErrorInterceptorModule) { - if (parentModule) { - throw new Error('ErrorInterceptorModule is already loaded. Import it in the AppModule only'); - } - } + constructor(@Optional() @SkipSelf() parentModule?: ErrorInterceptorModule) { + if (parentModule) { + throw new Error('ErrorInterceptorModule is already loaded. Import it in the AppModule only'); + } + } - static forRoot(config?: HttpResponseRedirectConfig): ModuleWithProviders { - return { - ngModule: ErrorInterceptorModule, - providers: [{ provide: HTTP_RESPONSE_REDIRECT, useValue: config }], - }; - } + static forRoot(config?: HttpResponseRedirectConfig): ModuleWithProviders { + return { + ngModule: ErrorInterceptorModule, + providers: [{ provide: HTTP_RESPONSE_REDIRECT, useValue: config }], + }; + } } diff --git a/src/app/interceptors/interceptor.module.ts b/src/app/interceptors/interceptor.module.ts index b48d89a2ef..09261685de 100644 --- a/src/app/interceptors/interceptor.module.ts +++ b/src/app/interceptors/interceptor.module.ts @@ -4,13 +4,17 @@ import { DelayedRetryModule } from './delayed-retry/delayed-retry.module'; import { ErrorInterceptorModule } from './error-handling/error-handling.module'; @NgModule({ - declarations: [], - imports: [ - CommonModule, - DelayedRetryModule.forRoot({ - count: 3, delay: 2000, httpStatusRetry: [504], backoff: true, whiteList: ['document-retrieval'], - }), - ErrorInterceptorModule.forRoot({ httpStatusRedirect: [500], redirectTo: 'error' }), - ], + declarations: [], + imports: [ + CommonModule, + DelayedRetryModule.forRoot({ + count: 3, + delay: 2000, + httpStatusRetry: [504], + backoff: true, + whiteList: ['document-retrieval'], + }), + ErrorInterceptorModule.forRoot({ httpStatusRedirect: [500], redirectTo: 'error' }), + ], }) export class InterceptorModule {} diff --git a/src/app/models/adr.enum.ts b/src/app/models/adr.enum.ts index 39dd3551fd..bb6e8ca48c 100644 --- a/src/app/models/adr.enum.ts +++ b/src/app/models/adr.enum.ts @@ -1,9 +1,9 @@ export enum TC2Types { - INITIAL = 'initial', + INITIAL = 'initial', } export enum TC3Types { - INTERMEDIATE = 'intermediate', - PERIODIC = 'periodic', - EXCEPTIONAL = 'exceptional', + INTERMEDIATE = 'intermediate', + PERIODIC = 'periodic', + EXCEPTIONAL = 'exceptional', } diff --git a/src/app/models/body-type-enum.ts b/src/app/models/body-type-enum.ts index 9c60d54732..a575d58949 100644 --- a/src/app/models/body-type-enum.ts +++ b/src/app/models/body-type-enum.ts @@ -1,112 +1,112 @@ // The types and codes need to be lowercase for the API. export enum BodyTypeDescription { - ARTIC = 'artic', - ARTICULATED = 'articulated', - BOX = 'box', - CAR_TRANSPORTER = 'car transporter', - CONCRETE_MIXER = 'concrete mixer', - CURTAINSIDER = 'curtainsider', - DOUBLE_DECKER = 'double decker', - FLAT = 'flat', - LIVESTOCK_CARRIER = 'livestock carrier', - LOW_LOADER = 'low loader', - MINI_BUS = 'mini bus', - OTHER = 'other', - OTHER_TANKER = 'other tanker', - PETROL_OR_OIL_TANKER = 'petrol/oil tanker', - REFUSE = 'refuse', - REFRIGERATED = 'refrigerated', - SINGLE_DECKER = 'single decker', - SKELETAL = 'skeletal', - SKIP_LOADER = 'skip loader', - TIPPER = 'tipper', - TRACTOR = 'tractor', + ARTIC = 'artic', + ARTICULATED = 'articulated', + BOX = 'box', + CAR_TRANSPORTER = 'car transporter', + CONCRETE_MIXER = 'concrete mixer', + CURTAINSIDER = 'curtainsider', + DOUBLE_DECKER = 'double decker', + FLAT = 'flat', + LIVESTOCK_CARRIER = 'livestock carrier', + LOW_LOADER = 'low loader', + MINI_BUS = 'mini bus', + OTHER = 'other', + OTHER_TANKER = 'other tanker', + PETROL_OR_OIL_TANKER = 'petrol/oil tanker', + REFUSE = 'refuse', + REFRIGERATED = 'refrigerated', + SINGLE_DECKER = 'single decker', + SKELETAL = 'skeletal', + SKIP_LOADER = 'skip loader', + TIPPER = 'tipper', + TRACTOR = 'tractor', } export enum BodyTypeCode { - A = 'a', - B = 'b', - C = 'c', - D = 'd', - E = 'e', - F = 'f', - I = 'i', - K = 'k', - L = 'l', - M = 'm', - O = 'o', - P = 'p', - R = 'r', - S = 's', - T = 't', - U = 'u', - X = 'x', - Y = 'y', + A = 'a', + B = 'b', + C = 'c', + D = 'd', + E = 'e', + F = 'f', + I = 'i', + K = 'k', + L = 'l', + M = 'm', + O = 'o', + P = 'p', + R = 'r', + S = 's', + T = 't', + U = 'u', + X = 'x', + Y = 'y', } const commonBodyTypeCodeMap = new Map([ - [BodyTypeCode.B, BodyTypeDescription.BOX], - [BodyTypeCode.C, BodyTypeDescription.REFRIGERATED], - [BodyTypeCode.D, BodyTypeDescription.DOUBLE_DECKER], - [BodyTypeCode.E, BodyTypeDescription.CURTAINSIDER], - [BodyTypeCode.F, BodyTypeDescription.FLAT], - [BodyTypeCode.I, BodyTypeDescription.LIVESTOCK_CARRIER], - [BodyTypeCode.K, BodyTypeDescription.SKELETAL], - [BodyTypeCode.O, BodyTypeDescription.OTHER_TANKER], - [BodyTypeCode.P, BodyTypeDescription.PETROL_OR_OIL_TANKER], - [BodyTypeCode.S, BodyTypeDescription.SKIP_LOADER], - [BodyTypeCode.T, BodyTypeDescription.TIPPER], - [BodyTypeCode.X, BodyTypeDescription.OTHER], - [BodyTypeCode.Y, BodyTypeDescription.CAR_TRANSPORTER], + [BodyTypeCode.B, BodyTypeDescription.BOX], + [BodyTypeCode.C, BodyTypeDescription.REFRIGERATED], + [BodyTypeCode.D, BodyTypeDescription.DOUBLE_DECKER], + [BodyTypeCode.E, BodyTypeDescription.CURTAINSIDER], + [BodyTypeCode.F, BodyTypeDescription.FLAT], + [BodyTypeCode.I, BodyTypeDescription.LIVESTOCK_CARRIER], + [BodyTypeCode.K, BodyTypeDescription.SKELETAL], + [BodyTypeCode.O, BodyTypeDescription.OTHER_TANKER], + [BodyTypeCode.P, BodyTypeDescription.PETROL_OR_OIL_TANKER], + [BodyTypeCode.S, BodyTypeDescription.SKIP_LOADER], + [BodyTypeCode.T, BodyTypeDescription.TIPPER], + [BodyTypeCode.X, BodyTypeDescription.OTHER], + [BodyTypeCode.Y, BodyTypeDescription.CAR_TRANSPORTER], ]); const psvBodyTypeCodeMap = new Map([ - [BodyTypeCode.A, BodyTypeDescription.ARTICULATED], - [BodyTypeCode.D, BodyTypeDescription.DOUBLE_DECKER], - [BodyTypeCode.M, BodyTypeDescription.MINI_BUS], - [BodyTypeCode.S, BodyTypeDescription.SINGLE_DECKER], - [BodyTypeCode.O, BodyTypeDescription.OTHER], + [BodyTypeCode.A, BodyTypeDescription.ARTICULATED], + [BodyTypeCode.D, BodyTypeDescription.DOUBLE_DECKER], + [BodyTypeCode.M, BodyTypeDescription.MINI_BUS], + [BodyTypeCode.S, BodyTypeDescription.SINGLE_DECKER], + [BodyTypeCode.O, BodyTypeDescription.OTHER], ]); const hgvBodyTypeCodeMap = new Map([ - [BodyTypeCode.B, BodyTypeDescription.BOX], - [BodyTypeCode.C, BodyTypeDescription.REFRIGERATED], - [BodyTypeCode.E, BodyTypeDescription.CURTAINSIDER], - [BodyTypeCode.F, BodyTypeDescription.FLAT], - [BodyTypeCode.I, BodyTypeDescription.LIVESTOCK_CARRIER], - [BodyTypeCode.K, BodyTypeDescription.SKELETAL], - [BodyTypeCode.O, BodyTypeDescription.OTHER_TANKER], - [BodyTypeCode.P, BodyTypeDescription.PETROL_OR_OIL_TANKER], - [BodyTypeCode.S, BodyTypeDescription.SKIP_LOADER], - [BodyTypeCode.T, BodyTypeDescription.TIPPER], - [BodyTypeCode.X, BodyTypeDescription.OTHER], - [BodyTypeCode.Y, BodyTypeDescription.CAR_TRANSPORTER], - [BodyTypeCode.A, BodyTypeDescription.TRACTOR], - [BodyTypeCode.L, BodyTypeDescription.LOW_LOADER], - [BodyTypeCode.M, BodyTypeDescription.CONCRETE_MIXER], - [BodyTypeCode.R, BodyTypeDescription.REFUSE], + [BodyTypeCode.B, BodyTypeDescription.BOX], + [BodyTypeCode.C, BodyTypeDescription.REFRIGERATED], + [BodyTypeCode.E, BodyTypeDescription.CURTAINSIDER], + [BodyTypeCode.F, BodyTypeDescription.FLAT], + [BodyTypeCode.I, BodyTypeDescription.LIVESTOCK_CARRIER], + [BodyTypeCode.K, BodyTypeDescription.SKELETAL], + [BodyTypeCode.O, BodyTypeDescription.OTHER_TANKER], + [BodyTypeCode.P, BodyTypeDescription.PETROL_OR_OIL_TANKER], + [BodyTypeCode.S, BodyTypeDescription.SKIP_LOADER], + [BodyTypeCode.T, BodyTypeDescription.TIPPER], + [BodyTypeCode.X, BodyTypeDescription.OTHER], + [BodyTypeCode.Y, BodyTypeDescription.CAR_TRANSPORTER], + [BodyTypeCode.A, BodyTypeDescription.TRACTOR], + [BodyTypeCode.L, BodyTypeDescription.LOW_LOADER], + [BodyTypeCode.M, BodyTypeDescription.CONCRETE_MIXER], + [BodyTypeCode.R, BodyTypeDescription.REFUSE], ]); const trlBodyTypeCodeMap = new Map([ - ...commonBodyTypeCodeMap.entries(), - [BodyTypeCode.L, BodyTypeDescription.LOW_LOADER], + ...commonBodyTypeCodeMap.entries(), + [BodyTypeCode.L, BodyTypeDescription.LOW_LOADER], ]); const articulatedHgvBodyTypeCodeMap = new Map([ - [BodyTypeCode.A, BodyTypeDescription.ARTICULATED], + [BodyTypeCode.A, BodyTypeDescription.ARTICULATED], ]); export const vehicleBodyTypeCodeMap = new Map>([ - ['psv', psvBodyTypeCodeMap], - ['rigidHgv', hgvBodyTypeCodeMap], - ['trl', trlBodyTypeCodeMap], - ['articulatedHgv', articulatedHgvBodyTypeCodeMap], + ['psv', psvBodyTypeCodeMap], + ['rigidHgv', hgvBodyTypeCodeMap], + ['trl', trlBodyTypeCodeMap], + ['articulatedHgv', articulatedHgvBodyTypeCodeMap], ]); export const vehicleBodyTypeDescriptionMap = new Map>([ - ['psv', new Map([...psvBodyTypeCodeMap.entries()].map(([k, v]) => [v, k]))], - ['trl', new Map([...trlBodyTypeCodeMap.entries()].map(([k, v]) => [v, k]))], - ['rigidHgv', new Map([...hgvBodyTypeCodeMap.entries()].map(([k, v]) => [v, k]))], - ['articulatedHgv', new Map([...articulatedHgvBodyTypeCodeMap.entries()].map(([k, v]) => [v, k]))], + ['psv', new Map([...psvBodyTypeCodeMap.entries()].map(([k, v]) => [v, k]))], + ['trl', new Map([...trlBodyTypeCodeMap.entries()].map(([k, v]) => [v, k]))], + ['rigidHgv', new Map([...hgvBodyTypeCodeMap.entries()].map(([k, v]) => [v, k]))], + ['articulatedHgv', new Map([...articulatedHgvBodyTypeCodeMap.entries()].map(([k, v]) => [v, k]))], ]); diff --git a/src/app/models/coupling-type-enum.ts b/src/app/models/coupling-type-enum.ts index 7b2c15488e..22d0a4c1e4 100644 --- a/src/app/models/coupling-type-enum.ts +++ b/src/app/models/coupling-type-enum.ts @@ -1,19 +1,19 @@ import { MultiOptions } from '@forms/models/options.model'; export enum CouplingTypeCodeEnum { - F = 'F', - B = 'B', - O = 'O', - A = 'A', - D = 'D', - S = 'S', + F = 'F', + B = 'B', + O = 'O', + A = 'A', + D = 'D', + S = 'S', } export const CouplingTypeOptions: MultiOptions = [ - { label: 'Fifth wheel', value: CouplingTypeCodeEnum.F }, - { label: 'Drawbar', value: CouplingTypeCodeEnum.B }, - { label: 'Other', value: CouplingTypeCodeEnum.O }, - { label: 'Automatic', value: CouplingTypeCodeEnum.A }, - { label: 'Dolly', value: CouplingTypeCodeEnum.D }, - { label: 'Semi', value: CouplingTypeCodeEnum.S }, + { label: 'Fifth wheel', value: CouplingTypeCodeEnum.F }, + { label: 'Drawbar', value: CouplingTypeCodeEnum.B }, + { label: 'Other', value: CouplingTypeCodeEnum.O }, + { label: 'Automatic', value: CouplingTypeCodeEnum.A }, + { label: 'Dolly', value: CouplingTypeCodeEnum.D }, + { label: 'Semi', value: CouplingTypeCodeEnum.S }, ]; diff --git a/src/app/models/defects/additional-information.model.ts b/src/app/models/defects/additional-information.model.ts index 7c97bed775..243eff99ec 100644 --- a/src/app/models/defects/additional-information.model.ts +++ b/src/app/models/defects/additional-information.model.ts @@ -1,12 +1,12 @@ import { Location } from './location.model'; export interface AdditionalInformation { - hgv?: AdditionalInfoSection; - psv?: AdditionalInfoSection; - trl?: AdditionalInfoSection; + hgv?: AdditionalInfoSection; + psv?: AdditionalInfoSection; + trl?: AdditionalInfoSection; } export interface AdditionalInfoSection { - location: Location; - notes: boolean; + location: Location; + notes: boolean; } diff --git a/src/app/models/defects/defect.model.ts b/src/app/models/defects/defect.model.ts index 2723869e44..a47912fc10 100644 --- a/src/app/models/defects/defect.model.ts +++ b/src/app/models/defects/defect.model.ts @@ -3,9 +3,9 @@ import { AdditionalInformation } from './additional-information.model'; import { Item } from './item.model'; export interface Defect { - additionalInfo: AdditionalInformation; - forVehicleType: VehicleTypes[]; - imDescription: string; - imNumber: number; - items: Item[]; + additionalInfo: AdditionalInformation; + forVehicleType: VehicleTypes[]; + imDescription: string; + imNumber: number; + items: Item[]; } diff --git a/src/app/models/defects/deficiency-category.enum.ts b/src/app/models/defects/deficiency-category.enum.ts index a4bbbb6693..f2e83fee80 100644 --- a/src/app/models/defects/deficiency-category.enum.ts +++ b/src/app/models/defects/deficiency-category.enum.ts @@ -1,6 +1,6 @@ export enum deficiencyCategory { - Advisory = 'advisory', - Dangerous = 'dangerous', - Major = 'major', - Minor = 'minor', + Advisory = 'advisory', + Dangerous = 'dangerous', + Major = 'major', + Minor = 'minor', } diff --git a/src/app/models/defects/deficiency.model.ts b/src/app/models/defects/deficiency.model.ts index ddb251c26e..eba54a991b 100644 --- a/src/app/models/defects/deficiency.model.ts +++ b/src/app/models/defects/deficiency.model.ts @@ -2,11 +2,11 @@ import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { deficiencyCategory } from './deficiency-category.enum'; export interface Deficiency { - deficiencyCategory: deficiencyCategory; - deficiencyId: string; - deficiencySubId: string; - deficiencyText: string; - forVehicleType: VehicleTypes[]; - ref: string; - stdForProhibition: boolean; + deficiencyCategory: deficiencyCategory; + deficiencyId: string; + deficiencySubId: string; + deficiencyText: string; + forVehicleType: VehicleTypes[]; + ref: string; + stdForProhibition: boolean; } diff --git a/src/app/models/defects/item.model.ts b/src/app/models/defects/item.model.ts index 69f1bfe8fd..69b877a1cd 100644 --- a/src/app/models/defects/item.model.ts +++ b/src/app/models/defects/item.model.ts @@ -2,8 +2,8 @@ import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { Deficiency } from './deficiency.model'; export interface Item { - deficiencies: Deficiency[]; - forVehicleType: VehicleTypes[]; - itemDescription: string; - itemNumber: number; + deficiencies: Deficiency[]; + forVehicleType: VehicleTypes[]; + itemDescription: string; + itemNumber: number; } diff --git a/src/app/models/defects/location.model.ts b/src/app/models/defects/location.model.ts index 1bcc2c7253..511101c2ec 100644 --- a/src/app/models/defects/location.model.ts +++ b/src/app/models/defects/location.model.ts @@ -1,34 +1,34 @@ export interface Location { - axleNumber?: number[]; - horizontal?: Horizontal[]; - lateral?: Lateral[]; - longitudinal?: Longitudinal[]; - rowNumber?: number[]; - seatNumber?: number[]; - vertical?: Vertical[]; + axleNumber?: number[]; + horizontal?: Horizontal[]; + lateral?: Lateral[]; + longitudinal?: Longitudinal[]; + rowNumber?: number[]; + seatNumber?: number[]; + vertical?: Vertical[]; } export type Vertical = 'upper' | 'lower'; export const VerticalEnum = { - Upper: 'upper' as Vertical, - Lower: 'lower' as Vertical, + Upper: 'upper' as Vertical, + Lower: 'lower' as Vertical, }; export type Horizontal = 'inner' | 'outer'; export const HorizontalEnum = { - Inner: 'inner' as Horizontal, - Outer: 'outer' as Horizontal, + Inner: 'inner' as Horizontal, + Outer: 'outer' as Horizontal, }; export type Lateral = 'nearside' | 'centre' | 'offside'; export const LateralEnum = { - Nearside: 'nearside' as Lateral, - Centre: 'centre' as Lateral, - Offside: 'offside' as Lateral, + Nearside: 'nearside' as Lateral, + Centre: 'centre' as Lateral, + Offside: 'offside' as Lateral, }; export type Longitudinal = 'front' | 'rear'; export const LongitudinalEnum = { - Front: 'front' as Longitudinal, - Rear: 'rear' as Longitudinal, + Front: 'front' as Longitudinal, + Rear: 'rear' as Longitudinal, }; diff --git a/src/app/models/reference-data.model.ts b/src/app/models/reference-data.model.ts index 891fd5071d..429c670e8b 100644 --- a/src/app/models/reference-data.model.ts +++ b/src/app/models/reference-data.model.ts @@ -1,91 +1,91 @@ export enum ReferenceDataResourceType { - Brakes = 'BRAKES', - CountryOfRegistration = 'COUNTRY_OF_REGISTRATION', - HgvMake = 'HGV_MAKE', - PsvMake = 'PSV_MAKE', - ReasonsForAbandoningHgv = 'REASONS_FOR_ABANDONING_HGV', - ReasonsForAbandoningTrl = 'REASONS_FOR_ABANDONING_TRL', - ReasonsForAbandoningPsv = 'REASONS_FOR_ABANDONING_PSV', - ReferenceDataAdminType = 'REFERENCE_DATA_ADMIN_TYPE', - SpecialistReasonsForAbandoning = 'SPECIALIST_REASONS_FOR_ABANDONING', - TirReasonsForAbandoning = 'TIR_REASONS_FOR_ABANDONING', - TrlMake = 'TRL_MAKE', - Tyres = 'TYRES', - User = 'USER', - TyreLoadIndex = 'TYRE_LOAD_INDEX', + Brakes = 'BRAKES', + CountryOfRegistration = 'COUNTRY_OF_REGISTRATION', + HgvMake = 'HGV_MAKE', + PsvMake = 'PSV_MAKE', + ReasonsForAbandoningHgv = 'REASONS_FOR_ABANDONING_HGV', + ReasonsForAbandoningTrl = 'REASONS_FOR_ABANDONING_TRL', + ReasonsForAbandoningPsv = 'REASONS_FOR_ABANDONING_PSV', + ReferenceDataAdminType = 'REFERENCE_DATA_ADMIN_TYPE', + SpecialistReasonsForAbandoning = 'SPECIALIST_REASONS_FOR_ABANDONING', + TirReasonsForAbandoning = 'TIR_REASONS_FOR_ABANDONING', + TrlMake = 'TRL_MAKE', + Tyres = 'TYRES', + User = 'USER', + TyreLoadIndex = 'TYRE_LOAD_INDEX', } type AuditTypes = `${keyof Record}#AUDIT`; export type ReferenceDataResourceTypeAudit = `${keyof Record}` | AuditTypes; export interface ReferenceDataAdminColumn { - name: string; - heading: string; - order: number; + name: string; + heading: string; + order: number; } export interface ReferenceDataModelBase { - resourceType: ReferenceDataResourceType; - resourceKey: string | number; - description?: string; - createdAt?: string; - createdName?: string; - createdId?: string; - reason?: string; - label?: string; + resourceType: ReferenceDataResourceType; + resourceKey: string | number; + description?: string; + createdAt?: string; + createdName?: string; + createdId?: string; + reason?: string; + label?: string; } export interface PsvMake extends ReferenceDataModelBase { - dtpNumber: string; - psvChassisMake: string; - psvChassisModel: string; - psvBodyMake: string; - psvBodyType: string; + dtpNumber: string; + psvChassisMake: string; + psvChassisModel: string; + psvBodyMake: string; + psvBodyType: string; } export interface BodyModel extends ReferenceDataModelBase { - bodyMake: string; + bodyMake: string; } export interface Brake extends ReferenceDataModelBase { - service: string; - secondary: string; - parking: string; + service: string; + secondary: string; + parking: string; } export interface ReferenceDataTyre extends ReferenceDataModelBase { - code: string; - loadIndexSingleLoad?: string; - tyreSize: string; - dateTimeStamp: string; - userId: string; - loadIndexTwinLoad?: string; - plyRating: string; - axleLoadSingle?: string; - axleLoadDouble?: string; + code: string; + loadIndexSingleLoad?: string; + tyreSize: string; + dateTimeStamp: string; + userId: string; + loadIndexTwinLoad?: string; + plyRating: string; + axleLoadSingle?: string; + axleLoadDouble?: string; } export interface ReferenceDataTyreLoadIndex extends ReferenceDataModelBase { - loadIndex: string; + loadIndex: string; } export interface User extends ReferenceDataModelBase { - name: string; - email: string; + name: string; + email: string; } export interface ReferenceDataAdminType extends ReferenceDataModelBase { - code?: string; - dtpNumber?: string; - loadIndexSingleLoad?: string; - loadIndexTwinLoad?: string; - parking?: string; - plyRating?: string; - psvBodyMake?: string; - psvBodyType?: string; - psvChassisMake?: string; - psvChassisModel?: string; - secondary?: string; - service?: string; - tyreSize?: string; + code?: string; + dtpNumber?: string; + loadIndexSingleLoad?: string; + loadIndexTwinLoad?: string; + parking?: string; + plyRating?: string; + psvBodyMake?: string; + psvBodyType?: string; + psvChassisMake?: string; + psvChassisModel?: string; + secondary?: string; + service?: string; + tyreSize?: string; } diff --git a/src/app/models/roles.enum.ts b/src/app/models/roles.enum.ts index df3fff91a6..4477fa9aa7 100644 --- a/src/app/models/roles.enum.ts +++ b/src/app/models/roles.enum.ts @@ -1,14 +1,14 @@ export enum Roles { - Admin = 'CVSFullAccess', - TechRecordView = 'CVSFullAccess,TechRecord.View', - TechRecordCreate = 'CVSFullAccess,TechRecord.Create', - TechRecordAmend = 'CVSFullAccess,TechRecord.Amend', - TechRecordArchive = 'CVSFullAccess,TechRecord.Archive', - TechRecordUnarchive = 'CVSFullAccess,TechRecord.Unarchive', - TestResultView = 'CVSFullAccess,TestResult.View', - TestResultAmend = 'CVSFullAccess,TestResult.Amend', - TestResultCreateContingency = 'CVSFullAccess,TestResult.CreateContingency', - TestResultCreateDeskAssessment = 'CVSFullAccess,TestResult.CreateDeskBased', - ReferenceDataView = 'CVSFullAccess,ReferenceData.View', - ReferenceDataAmend = 'CVSFullAccess,ReferenceData.Amend', + Admin = 'CVSFullAccess', + TechRecordView = 'CVSFullAccess,TechRecord.View', + TechRecordCreate = 'CVSFullAccess,TechRecord.Create', + TechRecordAmend = 'CVSFullAccess,TechRecord.Amend', + TechRecordArchive = 'CVSFullAccess,TechRecord.Archive', + TechRecordUnarchive = 'CVSFullAccess,TechRecord.Unarchive', + TestResultView = 'CVSFullAccess,TestResult.View', + TestResultAmend = 'CVSFullAccess,TestResult.Amend', + TestResultCreateContingency = 'CVSFullAccess,TestResult.CreateContingency', + TestResultCreateDeskAssessment = 'CVSFullAccess,TestResult.CreateDeskBased', + ReferenceDataView = 'CVSFullAccess,ReferenceData.View', + ReferenceDataAmend = 'CVSFullAccess,ReferenceData.Amend', } diff --git a/src/app/models/routes.enum.ts b/src/app/models/routes.enum.ts index 1df9e718a1..b059970a72 100644 --- a/src/app/models/routes.enum.ts +++ b/src/app/models/routes.enum.ts @@ -1,85 +1,85 @@ export enum RootRoutes { - ROOT = '', - SEARCH_TECHNICAL_RECORD = 'search', - CREATE_TECHNICAL_RECORD = 'create', - BATCH_CREATE_TECHNICAL_RECORD = 'create-batch', - CURRENT_TEST_RESULT = 'test-records/:systemNumber/test-result/:testResultId/:testNumber', - CURRENT_TECH_RECORD = 'tech-records/:systemNumber/:createdTimestamp', - REFERENCE_DATA = 'reference-data', - FEATURE_TOGGLE = 'feature-toggle', - ERROR = 'error', - WILDCARD = '**', + ROOT = '', + SEARCH_TECHNICAL_RECORD = 'search', + CREATE_TECHNICAL_RECORD = 'create', + BATCH_CREATE_TECHNICAL_RECORD = 'create-batch', + CURRENT_TEST_RESULT = 'test-records/:systemNumber/test-result/:testResultId/:testNumber', + CURRENT_TECH_RECORD = 'tech-records/:systemNumber/:createdTimestamp', + REFERENCE_DATA = 'reference-data', + FEATURE_TOGGLE = 'feature-toggle', + ERROR = 'error', + WILDCARD = '**', } export enum SearchRoutes { - SEARCH_RESULT = 'results', + SEARCH_RESULT = 'results', } export enum TechRecordRoutes { - CORRECT_ERROR = 'correcting-an-error', - NOTIFIABLE_ALTERATION_NEEDED = 'notifiable-alteration-needed', - CHANGE_VIN = 'change-vin', - CHANGE_VRM = 'change-vrm', - REASON_TO_CHANGE_VRM = 'change-vrm/:reason', - GENERATE_PLATE = 'generate-plate', - GENERATE_LETTER = 'generate-letter', - AMEND_REASON = 'amend-reason', - CHANGE_STATUS = 'change-status', - UNARCHIVE_RECORD = 'unarchive-record', - CHANGE_VEHICLE_TYPE = 'change-vehicle-type', - CHANGE_VTA_VISIBILITY = 'change-vta-visibility', - CORRECT_ERROR_TYRE_SEARCH = 'correcting-an-error/tyre-search/:axleNumber', - CORRECT_ERROR_CHANGE_SUMMARY = 'correcting-an-error/change-summary', - CORRECT_ERROR_EDIT_ADDITIONAL_EXAMINER_NOTE = 'correcting-an-error/edit-additional-examiner-note/:examinerNoteIndex', - NOTIFIABLE_ALTERATION_NEEDED_CHANGE_SUMMARY = 'notifiable-alteration-needed/change-summary', - NOTIFIABLE_ALTERATION_NEEDED_TYRE_SEARCH = 'notifiable-alteration-needed/tyre-search/:axleNumber', - NOTIFIABLE_ALTERNATION_NEEDED_EDIT_ADDITIONAL_EXAMINER_NOTE = 'notifiable-alteration-needed/edit-additional-examiner-note/:examinerNoteIndex', - TEST_RECORDS = 'test-records/test-result/:testResultId/:testNumber', - CREATE_TEST = 'test-records/create-test', - ADR_CERTIFICATE = 'adr-certificate', + CORRECT_ERROR = 'correcting-an-error', + NOTIFIABLE_ALTERATION_NEEDED = 'notifiable-alteration-needed', + CHANGE_VIN = 'change-vin', + CHANGE_VRM = 'change-vrm', + REASON_TO_CHANGE_VRM = 'change-vrm/:reason', + GENERATE_PLATE = 'generate-plate', + GENERATE_LETTER = 'generate-letter', + AMEND_REASON = 'amend-reason', + CHANGE_STATUS = 'change-status', + UNARCHIVE_RECORD = 'unarchive-record', + CHANGE_VEHICLE_TYPE = 'change-vehicle-type', + CHANGE_VTA_VISIBILITY = 'change-vta-visibility', + CORRECT_ERROR_TYRE_SEARCH = 'correcting-an-error/tyre-search/:axleNumber', + CORRECT_ERROR_CHANGE_SUMMARY = 'correcting-an-error/change-summary', + CORRECT_ERROR_EDIT_ADDITIONAL_EXAMINER_NOTE = 'correcting-an-error/edit-additional-examiner-note/:examinerNoteIndex', + NOTIFIABLE_ALTERATION_NEEDED_CHANGE_SUMMARY = 'notifiable-alteration-needed/change-summary', + NOTIFIABLE_ALTERATION_NEEDED_TYRE_SEARCH = 'notifiable-alteration-needed/tyre-search/:axleNumber', + NOTIFIABLE_ALTERNATION_NEEDED_EDIT_ADDITIONAL_EXAMINER_NOTE = 'notifiable-alteration-needed/edit-additional-examiner-note/:examinerNoteIndex', + TEST_RECORDS = 'test-records/test-result/:testResultId/:testNumber', + CREATE_TEST = 'test-records/create-test', + ADR_CERTIFICATE = 'adr-certificate', } export enum TechRecordCreateRoutes { - NEW_RECORD_DETAILS = 'new-record-details', - TYRE_SEARCH = 'tyre-search/:axleNumber', + NEW_RECORD_DETAILS = 'new-record-details', + TYRE_SEARCH = 'tyre-search/:axleNumber', } export enum TechRecordCreateBatchRoutes { - RECORD = ':vehicleType', - DETAILS = 'details', - BATCH_RESULT = 'batch-results', - TYRE_SEARCH = 'tyre-search/:axleNumber', + RECORD = ':vehicleType', + DETAILS = 'details', + BATCH_RESULT = 'batch-results', + TYRE_SEARCH = 'tyre-search/:axleNumber', } export enum ReferenceDataRoutes { - TYPE = ':type', - CREATE = 'create', - DELETED_ITEMS = 'deleted-items', - KEY = ':key', - DELETE = ':key/delete', + TYPE = ':type', + CREATE = 'create', + DELETED_ITEMS = 'deleted-items', + KEY = ':key', + DELETE = ':key/delete', } export enum TestRecordAmendRoutes { - AMEND_TEST = 'amend-test', - INCORRECT_TEST_TYPE = 'incorrect-test-type', - TEST_DETAILS = 'amend-test-details', - DEFECT = 'defect/:defectIndex', - SELECT_DEFECT = 'selectDefect', - SELECT_DEFECT_REFERENCE = ':ref', - AMENDED_TEST = 'amended/:createdAt', - CANCEL_TEST = 'cancel-test', - REQUIRED_STANDARD = 'requiredStandard/:requiredStandardIndex', - SELECT_REQUIRED_STANDARD = 'selectRequiredStandard', - REQUIRED_STANDARD_REF = ':inspectionType/:ref', + AMEND_TEST = 'amend-test', + INCORRECT_TEST_TYPE = 'incorrect-test-type', + TEST_DETAILS = 'amend-test-details', + DEFECT = 'defect/:defectIndex', + SELECT_DEFECT = 'selectDefect', + SELECT_DEFECT_REFERENCE = ':ref', + AMENDED_TEST = 'amended/:createdAt', + CANCEL_TEST = 'cancel-test', + REQUIRED_STANDARD = 'requiredStandard/:requiredStandardIndex', + SELECT_REQUIRED_STANDARD = 'selectRequiredStandard', + REQUIRED_STANDARD_REF = ':inspectionType/:ref', } export enum TestRecordCreateRoutes { - TYPE = 'type', - TEST_DETAILS = 'test-details', - DEFECT = 'defect/:defectIndex', - SELECT_DEFECT = 'selectDefect', - SELECT_DEFECT_REF = ':ref', - REQUIRED_STANDARD = 'requiredStandard/:requiredStandardIndex', - SELECT_REQUIRED_STANDARD = 'selectRequiredStandard', - REQUIRED_STANDARD_REF = ':inspectionType/:ref', + TYPE = 'type', + TEST_DETAILS = 'test-details', + DEFECT = 'defect/:defectIndex', + SELECT_DEFECT = 'selectDefect', + SELECT_DEFECT_REF = ':ref', + REQUIRED_STANDARD = 'requiredStandard/:requiredStandardIndex', + SELECT_REQUIRED_STANDARD = 'selectRequiredStandard', + REQUIRED_STANDARD_REF = ':inspectionType/:ref', } diff --git a/src/app/models/search-types-enum.ts b/src/app/models/search-types-enum.ts index e4168ec8e8..056c4857b4 100644 --- a/src/app/models/search-types-enum.ts +++ b/src/app/models/search-types-enum.ts @@ -1,8 +1,8 @@ export enum SEARCH_TYPES { - VIN = 'vin', - PARTIAL_VIN = 'partialVin', - VRM = 'primaryVrm', - TRAILER_ID = 'trailerId', - SYSTEM_NUMBER = 'systemNumber', - ALL = 'all', + VIN = 'vin', + PARTIAL_VIN = 'partialVin', + VRM = 'primaryVrm', + TRAILER_ID = 'trailerId', + SYSTEM_NUMBER = 'systemNumber', + ALL = 'all', } diff --git a/src/app/models/tech-record/tech-record-actions.enum.ts b/src/app/models/tech-record/tech-record-actions.enum.ts index f101c7e5da..22e89b8330 100644 --- a/src/app/models/tech-record/tech-record-actions.enum.ts +++ b/src/app/models/tech-record/tech-record-actions.enum.ts @@ -1,6 +1,6 @@ export enum TechRecordActions { - CURRENT = 'archive', - PROVISIONAL = 'promote,archive', - ARCHIVED = 'unarchive', - NONE = '', + CURRENT = 'archive', + PROVISIONAL = 'promote,archive', + ARCHIVED = 'unarchive', + NONE = '', } diff --git a/src/app/models/test-results/defectAdditionalInformation.ts b/src/app/models/test-results/defectAdditionalInformation.ts index 73eb9ac08c..b2343b98c9 100644 --- a/src/app/models/test-results/defectAdditionalInformation.ts +++ b/src/app/models/test-results/defectAdditionalInformation.ts @@ -12,6 +12,6 @@ import { DefectAdditionalInformationLocation } from './defectAdditionalInformationLocation'; export interface DefectAdditionalInformation { - location?: DefectAdditionalInformationLocation; - notes?: string; + location?: DefectAdditionalInformationLocation; + notes?: string; } diff --git a/src/app/models/test-results/defectAdditionalInformationLocation.ts b/src/app/models/test-results/defectAdditionalInformationLocation.ts index 67898aa66a..771cdd7857 100644 --- a/src/app/models/test-results/defectAdditionalInformationLocation.ts +++ b/src/app/models/test-results/defectAdditionalInformationLocation.ts @@ -11,33 +11,33 @@ */ export interface DefectAdditionalInformationLocation { - vertical?: VerticalEnum; - horizontal?: HorizontalEnum; - lateral?: LateralEnum; - longitudinal?: LongitudinalEnum; - rowNumber?: number; - seatNumber?: number; - axleNumber?: number; + vertical?: VerticalEnum; + horizontal?: HorizontalEnum; + lateral?: LateralEnum; + longitudinal?: LongitudinalEnum; + rowNumber?: number; + seatNumber?: number; + axleNumber?: number; } export type VerticalEnum = 'upper' | 'lower'; export const VerticalTypeEnum = { - Upper: 'upper' as VerticalEnum, - Lower: 'lower' as VerticalEnum, + Upper: 'upper' as VerticalEnum, + Lower: 'lower' as VerticalEnum, }; export type HorizontalEnum = 'inner' | 'outer'; export const HorizontalTypeEnum = { - Inner: 'inner' as HorizontalEnum, - Outer: 'outer' as HorizontalEnum, + Inner: 'inner' as HorizontalEnum, + Outer: 'outer' as HorizontalEnum, }; export type LateralEnum = 'nearside' | 'centre' | 'offside'; export const LateralTypeEnum = { - Nearside: 'nearside' as LateralEnum, - Centre: 'centre' as LateralEnum, - Offside: 'offside' as LateralEnum, + Nearside: 'nearside' as LateralEnum, + Centre: 'centre' as LateralEnum, + Offside: 'offside' as LateralEnum, }; export type LongitudinalEnum = 'front' | 'rear'; export const LongitudinalTypeEnum = { - Front: 'front' as LongitudinalEnum, - Rear: 'rear' as LongitudinalEnum, + Front: 'front' as LongitudinalEnum, + Rear: 'rear' as LongitudinalEnum, }; diff --git a/src/app/models/test-results/test-result-defect.model.ts b/src/app/models/test-results/test-result-defect.model.ts index a3ea0798d3..4b3dd6552d 100644 --- a/src/app/models/test-results/test-result-defect.model.ts +++ b/src/app/models/test-results/test-result-defect.model.ts @@ -1,25 +1,25 @@ import { DefectAdditionalInformation } from './defectAdditionalInformation'; export interface TestResultDefect { - imNumber?: number; - imDescription?: string; - additionalInformation?: DefectAdditionalInformation; - itemNumber?: number; - itemDescription?: string; - deficiencyRef?: string; - deficiencyId?: string; - deficiencySubId?: string; - deficiencyCategory: DeficiencyCategoryStringEnum; - deficiencyText?: string; - stdForProhibition?: boolean; - prs?: boolean; - prohibitionIssued?: boolean; + imNumber?: number; + imDescription?: string; + additionalInformation?: DefectAdditionalInformation; + itemNumber?: number; + itemDescription?: string; + deficiencyRef?: string; + deficiencyId?: string; + deficiencySubId?: string; + deficiencyCategory: DeficiencyCategoryStringEnum; + deficiencyText?: string; + stdForProhibition?: boolean; + prs?: boolean; + prohibitionIssued?: boolean; } export type DeficiencyCategoryStringEnum = 'advisory' | 'dangerous' | 'major' | 'minor'; export const DeficiencyCategoryEnum = { - Advisory: 'advisory' as DeficiencyCategoryStringEnum, - Dangerous: 'dangerous' as DeficiencyCategoryStringEnum, - Major: 'major' as DeficiencyCategoryStringEnum, - Minor: 'minor' as DeficiencyCategoryStringEnum, + Advisory: 'advisory' as DeficiencyCategoryStringEnum, + Dangerous: 'dangerous' as DeficiencyCategoryStringEnum, + Major: 'major' as DeficiencyCategoryStringEnum, + Minor: 'minor' as DeficiencyCategoryStringEnum, }; diff --git a/src/app/models/test-results/test-result-required-standard.model.ts b/src/app/models/test-results/test-result-required-standard.model.ts index f854e956d7..5b83b71e46 100644 --- a/src/app/models/test-results/test-result-required-standard.model.ts +++ b/src/app/models/test-results/test-result-required-standard.model.ts @@ -1,18 +1,18 @@ import { InspectionType } from '@dvsa/cvs-type-definitions/types/required-standards/defects/get'; export interface TestResultRequiredStandard { - sectionNumber: string; - sectionDescription: string; - rsNumber: number; - requiredStandard: string; - refCalculation: string; - additionalInfo: boolean; - inspectionTypes: InspectionType[]; - prs?: boolean; - additionalNotes?: string; + sectionNumber: string; + sectionDescription: string; + rsNumber: number; + requiredStandard: string; + refCalculation: string; + additionalInfo: boolean; + inspectionTypes: InspectionType[]; + prs?: boolean; + additionalNotes?: string; } export enum INSPECTION_TYPE { - NORMAL = 'normal', - BASIC = 'basic', + NORMAL = 'normal', + BASIC = 'basic', } diff --git a/src/app/models/test-results/test-result-status.enum.ts b/src/app/models/test-results/test-result-status.enum.ts index ef320dfc89..09706aa539 100644 --- a/src/app/models/test-results/test-result-status.enum.ts +++ b/src/app/models/test-results/test-result-status.enum.ts @@ -1,4 +1,4 @@ export enum TestResultStatus { - SUBMITTED = 'submitted', - CANCELLED = 'cancelled', + SUBMITTED = 'submitted', + CANCELLED = 'cancelled', } diff --git a/src/app/models/test-results/test-result-view.enum.ts b/src/app/models/test-results/test-result-view.enum.ts index 7a9d993101..87f5f8dc26 100644 --- a/src/app/models/test-results/test-result-view.enum.ts +++ b/src/app/models/test-results/test-result-view.enum.ts @@ -1,6 +1,6 @@ export const TestModeEnum = { - Edit: 'edit', - View: 'view', - Abandon: 'abandon', - Cancel: 'cancel', + Edit: 'edit', + View: 'view', + Abandon: 'abandon', + Cancel: 'cancel', }; diff --git a/src/app/models/test-results/test-result.model.ts b/src/app/models/test-results/test-result.model.ts index 8d35d689cb..d07851f747 100644 --- a/src/app/models/test-results/test-result.model.ts +++ b/src/app/models/test-results/test-result.model.ts @@ -12,65 +12,65 @@ import { TestCodes } from './testCodes.enum'; import { TypeOfTest } from './typeOfTest.enum'; export interface TestResultModel { - testResultId: string; + testResultId: string; - systemNumber: string; - vin: string; - vrm?: string; // Mandatory for PSV and HGV, not applicable to TRL + systemNumber: string; + vin: string; + vrm?: string; // Mandatory for PSV and HGV, not applicable to TRL - createdAt?: string; - testStartTimestamp: string | Date; - testEndTimestamp: string | Date; + createdAt?: string; + testStartTimestamp: string | Date; + testEndTimestamp: string | Date; - testTypes: TestType[]; + testTypes: TestType[]; - trailerId: string; - countryOfRegistration: string; - euVehicleCategory: EUVehicleCategory | null; - odometerReading: number; - odometerReadingUnits: OdometerReadingUnits; - preparerName: string; - preparerId: string; + trailerId: string; + countryOfRegistration: string; + euVehicleCategory: EUVehicleCategory | null; + odometerReading: number; + odometerReadingUnits: OdometerReadingUnits; + preparerName: string; + preparerId: string; - testStationName: string; - testStationPNumber: string; - testStationType: TestStationType; - testerName: string; - testerEmailAddress: string; - testerStaffId: string; + testStationName: string; + testStationPNumber: string; + testStationType: TestStationType; + testerName: string; + testerEmailAddress: string; + testerStaffId: string; - reasonForCreation?: string; - reasonForCancellation?: string; - vehicleType: VehicleTypes; - testHistory?: TestResultModel[]; - testStatus?: TestResultStatus; + reasonForCreation?: string; + reasonForCancellation?: string; + vehicleType: VehicleTypes; + testHistory?: TestResultModel[]; + testStatus?: TestResultStatus; - make?: string; - model?: string | null; - bodyType?: TechRecordBodyType; + make?: string; + model?: string | null; + bodyType?: TechRecordBodyType; - /** - * Applicable only when updating/creating a test from VTM - */ - createdByName?: string; - createdById?: string; - lastUpdatedByName?: string; - typeOfTest?: TypeOfTest; - contingencyTestNumber?: string; - source?: string; - lastUpdatedById?: string; - testVersion?: string | null; - testCode?: TestCodes; + /** + * Applicable only when updating/creating a test from VTM + */ + createdByName?: string; + createdById?: string; + lastUpdatedByName?: string; + typeOfTest?: TypeOfTest; + contingencyTestNumber?: string; + source?: string; + lastUpdatedById?: string; + testVersion?: string | null; + testCode?: TestCodes; - vehicleSize?: VehicleSize; - vehicleConfiguration?: VehicleConfiguration | null; - noOfAxles?: number; - vehicleClass?: VehicleClass; - vehicleSubclass?: Array; - numberOfWheelsDriven?: number; - statusCode?: StatusCodes; - /** - * Used only for TRL - */ - firstUseDate?: string; + vehicleSize?: VehicleSize; + vehicleConfiguration?: VehicleConfiguration | null; + noOfAxles?: number; + vehicleClass?: VehicleClass; + vehicleSubclass?: Array; + numberOfWheelsDriven?: number; + statusCode?: StatusCodes; + /** + * Used only for TRL + */ + firstUseDate?: string; } diff --git a/src/app/models/test-results/testCodes.enum.ts b/src/app/models/test-results/testCodes.enum.ts index df33ea6c66..d7306fb571 100644 --- a/src/app/models/test-results/testCodes.enum.ts +++ b/src/app/models/test-results/testCodes.enum.ts @@ -1,58 +1,58 @@ export enum TestCodes { - AAL = 'aal', - AAS = 'aas', - ADL = 'adl', - WDL = 'wdl', - WDS = 'wds', - WBL = 'wbl', - WBS = 'wbs', - RHL = 'rhl', - RPL = 'rpl', - RPS = 'rps', - WHL = 'whl', - WHS = 'whs', - RGL = 'rgl', - RSL = 'rsl', - RSS = 'rss', - PHL = 'phl', - PHS = 'phs', - P1L = 'p1l', - P1S = 'p1s', - P8L = 'p8l', - P8S = 'p8s', - PML = 'pml', - PMS = 'pms', - P6L = 'p6l', - P6S = 'p6s', - P2L = 'p2l', - P2S = 'p2s', - P3L = 'p3l', - PGL = 'pgl', - PGS = 'pgs', - PRL = 'prl', - PRS = 'prs', - WIS = 'wis', - WIL = 'wil', - WFL = 'wfl', - WFS = 'wfs', - WEL = 'wel', - WES = 'wes', - QAL = 'qal', - QAS = 'qas', - QGL = 'qgl', - QGS = 'qgs', - QDL = 'qdl', - QDS = 'qds', - QCL = 'qcl', - QCS = 'qcs', - QBL = 'qbl', - QBS = 'qbs', - BIF = 'bif', - TEL = 'tel', - TES = 'tes', - NFL = 'nfl', - NFS = 'nfs', - LCP = 'lcp', - LBP = 'lbp', - LNP = 'lnp', + AAL = 'aal', + AAS = 'aas', + ADL = 'adl', + WDL = 'wdl', + WDS = 'wds', + WBL = 'wbl', + WBS = 'wbs', + RHL = 'rhl', + RPL = 'rpl', + RPS = 'rps', + WHL = 'whl', + WHS = 'whs', + RGL = 'rgl', + RSL = 'rsl', + RSS = 'rss', + PHL = 'phl', + PHS = 'phs', + P1L = 'p1l', + P1S = 'p1s', + P8L = 'p8l', + P8S = 'p8s', + PML = 'pml', + PMS = 'pms', + P6L = 'p6l', + P6S = 'p6s', + P2L = 'p2l', + P2S = 'p2s', + P3L = 'p3l', + PGL = 'pgl', + PGS = 'pgs', + PRL = 'prl', + PRS = 'prs', + WIS = 'wis', + WIL = 'wil', + WFL = 'wfl', + WFS = 'wfs', + WEL = 'wel', + WES = 'wes', + QAL = 'qal', + QAS = 'qas', + QGL = 'qgl', + QGS = 'qgs', + QDL = 'qdl', + QDS = 'qds', + QCL = 'qcl', + QCS = 'qcs', + QBL = 'qbl', + QBS = 'qbs', + BIF = 'bif', + TEL = 'tel', + TES = 'tes', + NFL = 'nfl', + NFS = 'nfs', + LCP = 'lcp', + LBP = 'lbp', + LNP = 'lnp', } diff --git a/src/app/models/test-results/typeOfTest.enum.ts b/src/app/models/test-results/typeOfTest.enum.ts index 61b4dc2ce2..9385a349f1 100644 --- a/src/app/models/test-results/typeOfTest.enum.ts +++ b/src/app/models/test-results/typeOfTest.enum.ts @@ -1,4 +1,4 @@ export enum TypeOfTest { - CONTINGENCY = 'contingency', - DESK_BASED = 'desk-based', + CONTINGENCY = 'contingency', + DESK_BASED = 'desk-based', } diff --git a/src/app/models/test-stations/test-station-type.enum.ts b/src/app/models/test-stations/test-station-type.enum.ts index 33b5b3d4bc..658eb2c740 100644 --- a/src/app/models/test-stations/test-station-type.enum.ts +++ b/src/app/models/test-stations/test-station-type.enum.ts @@ -1,6 +1,6 @@ export enum TestStationType { - ATF = 'atf', - GVTS = 'gvts', - HQ = 'hq', - POTF = 'potf', + ATF = 'atf', + GVTS = 'gvts', + HQ = 'hq', + POTF = 'potf', } diff --git a/src/app/models/test-stations/test-station.model.ts b/src/app/models/test-stations/test-station.model.ts index b3dc11a837..eb045d9dba 100644 --- a/src/app/models/test-stations/test-station.model.ts +++ b/src/app/models/test-stations/test-station.model.ts @@ -1,24 +1,24 @@ import { TestStationType } from './test-station-type.enum'; export interface TestStation { - testStationId: string; - testStationAccessNotes?: string; - testStationAddress: string; - testStationContactNumber: number; - testStationEmails: string[]; - testStationGeneralNotes: string; - testStationLatitude?: number; - testStationLongitude?: number; - testStationName: string; - testStationPNumber: string; - testStationPostcode: string; - testStationStatus: TestStationStatuses; - testStationTown: string; - testStationType: TestStationType; + testStationId: string; + testStationAccessNotes?: string; + testStationAddress: string; + testStationContactNumber: number; + testStationEmails: string[]; + testStationGeneralNotes: string; + testStationLatitude?: number; + testStationLongitude?: number; + testStationName: string; + testStationPNumber: string; + testStationPostcode: string; + testStationStatus: TestStationStatuses; + testStationTown: string; + testStationType: TestStationType; } export enum TestStationStatuses { - active = 'active', - inactive = 'inactive', - pending = 'pending', + active = 'active', + inactive = 'inactive', + pending = 'pending', } diff --git a/src/app/models/test-types/emissions.enum.ts b/src/app/models/test-types/emissions.enum.ts index fab454e6db..817457fb24 100644 --- a/src/app/models/test-types/emissions.enum.ts +++ b/src/app/models/test-types/emissions.enum.ts @@ -1,37 +1,37 @@ export enum FuelType { - Diesel = 'diesel', - GasCng = 'gas-cng', - GasLng = 'gas-lng', - GasLpg = 'gas-lpg', - FuelCell = 'fuel cell', - Petrol = 'petrol', - FullElectric = 'full electric', + Diesel = 'diesel', + GasCng = 'gas-cng', + GasLng = 'gas-lng', + GasLpg = 'gas-lpg', + FuelCell = 'fuel cell', + Petrol = 'petrol', + FullElectric = 'full electric', } export enum EmissionStandard { - EuroIVPM = '0.03 g/kWh Euro IV PM', - Euro3 = 'Euro 3', - Euro4 = 'Euro 4', - Euro5 = 'Euro 5', - Euro6 = 'Euro 6', - EuroV = 'Euro V', - EuroVI = 'Euro VI', - FullElectric = 'Full Electric', + EuroIVPM = '0.03 g/kWh Euro IV PM', + Euro3 = 'Euro 3', + Euro4 = 'Euro 4', + Euro5 = 'Euro 5', + Euro6 = 'Euro 6', + EuroV = 'Euro V', + EuroVI = 'Euro VI', + FullElectric = 'Full Electric', } export enum ModTypeCode { - p = 'p', - m = 'm', - g = 'g', + p = 'p', + m = 'm', + g = 'g', } export enum ModeTypeDescription { - ParticulateTrap = 'particulate trap', - Engine = 'modification or change of engine', - GasEngine = 'gas engine', + ParticulateTrap = 'particulate trap', + Engine = 'modification or change of engine', + GasEngine = 'gas engine', } export interface ModType { - code: ModTypeCode; - description: ModeTypeDescription; + code: ModTypeCode; + description: ModeTypeDescription; } diff --git a/src/app/models/test-types/eu-vehicle-category.enum.ts b/src/app/models/test-types/eu-vehicle-category.enum.ts index 6925551322..637d652be9 100644 --- a/src/app/models/test-types/eu-vehicle-category.enum.ts +++ b/src/app/models/test-types/eu-vehicle-category.enum.ts @@ -1,20 +1,20 @@ export enum EuVehicleCategory { - M1 = 'm1', - M2 = 'm2', - M3 = 'm3', - N1 = 'n1', - N2 = 'n2', - N3 = 'n3', - O1 = 'o1', - O2 = 'o2', - O3 = 'o3', - O4 = 'o4', - L1E_A = 'l1e-a', - L1E = 'l1e', - L2E = 'l2e', - L3E = 'l3e', - L4E = 'l4e', - L5E = 'l5e', - L6E = 'l6e', - L7E = 'l7e', + M1 = 'm1', + M2 = 'm2', + M3 = 'm3', + N1 = 'n1', + N2 = 'n2', + N3 = 'n3', + O1 = 'o1', + O2 = 'o2', + O3 = 'o3', + O4 = 'o4', + L1E_A = 'l1e-a', + L1E = 'l1e', + L2E = 'l2e', + L3E = 'l3e', + L4E = 'l4e', + L5E = 'l5e', + L6E = 'l6e', + L7E = 'l7e', } diff --git a/src/app/models/test-types/odometer-unit.enum.ts b/src/app/models/test-types/odometer-unit.enum.ts index d24f614178..94f47dca6a 100644 --- a/src/app/models/test-types/odometer-unit.enum.ts +++ b/src/app/models/test-types/odometer-unit.enum.ts @@ -1,4 +1,4 @@ export enum OdometerReadingUnits { - KILOMETRES = 'kilometres', - MILES = 'miles', + KILOMETRES = 'kilometres', + MILES = 'miles', } diff --git a/src/app/models/test-types/test-type.model.ts b/src/app/models/test-types/test-type.model.ts index e058699035..f98f5fd0dc 100644 --- a/src/app/models/test-types/test-type.model.ts +++ b/src/app/models/test-types/test-type.model.ts @@ -3,62 +3,62 @@ import { TestResultRequiredStandard } from '@models/test-results/test-result-req import * as Emissions from './emissions.enum'; export interface TestType { - testTypeId: string; - testNumber: string; - name: string; - testCode: string; - testTypeName: string; + testTypeId: string; + testNumber: string; + name: string; + testCode: string; + testTypeName: string; - testTypeStartTimestamp: string | Date; - testTypeEndTimestamp: string | Date; - testExpiryDate: string | Date; + testTypeStartTimestamp: string | Date; + testTypeEndTimestamp: string | Date; + testExpiryDate: string | Date; - certificateNumber: string; - reasonForAbandoning: string | null; - additionalCommentsForAbandon?: string | null; - testAnniversaryDate: string | Date; - prohibitionIssued: boolean | null; + certificateNumber: string; + reasonForAbandoning: string | null; + additionalCommentsForAbandon?: string | null; + testAnniversaryDate: string | Date; + prohibitionIssued: boolean | null; - testResult: resultOfTestEnum; + testResult: resultOfTestEnum; - seatbeltInstallationCheckDate: boolean; - numberOfSeatbeltsFitted: number; - lastSeatbeltInstallationCheckDate: string | Date | null; - emissionStandard: Emissions.EmissionStandard; - smokeTestKLimitApplied: string; - fuelType: Emissions.FuelType; - modType: Emissions.ModType; - modificationTypeUsed: string; - particulateTrapFitted: string; - particulateTrapSerialNumber: string; - defects?: TestResultDefects; - requiredStandards?: TestResultRequiredStandard[]; - customDefects: CustomDefects[]; + seatbeltInstallationCheckDate: boolean; + numberOfSeatbeltsFitted: number; + lastSeatbeltInstallationCheckDate: string | Date | null; + emissionStandard: Emissions.EmissionStandard; + smokeTestKLimitApplied: string; + fuelType: Emissions.FuelType; + modType: Emissions.ModType; + modificationTypeUsed: string; + particulateTrapFitted: string; + particulateTrapSerialNumber: string; + defects?: TestResultDefects; + requiredStandards?: TestResultRequiredStandard[]; + customDefects: CustomDefects[]; - additionalNotesRecorded: string; - certificateLink?: string | null; - deletionFlag?: boolean; - secondaryCertificateNumber?: string | null; - reapplicationDate?: string; + additionalNotesRecorded: string; + certificateLink?: string | null; + deletionFlag?: boolean; + secondaryCertificateNumber?: string | null; + reapplicationDate?: string; - centralDocs?: CentralDocs; + centralDocs?: CentralDocs; } export interface CentralDocs { - issueRequired: boolean; - notes?: string; - reasonsForIssue?: string[]; + issueRequired: boolean; + notes?: string; + reasonsForIssue?: string[]; } export interface CustomDefects { - referenceNumber?: string; - defectName: string; - defectNotes: string; + referenceNumber?: string; + defectName: string; + defectNotes: string; } export enum resultOfTestEnum { - fail = 'fail', - prs = 'prs', - pass = 'pass', - abandoned = 'abandoned', + fail = 'fail', + prs = 'prs', + pass = 'pass', + abandoned = 'abandoned', } diff --git a/src/app/models/vehicle-class.model.ts b/src/app/models/vehicle-class.model.ts index b444d14e03..34ddeb1073 100644 --- a/src/app/models/vehicle-class.model.ts +++ b/src/app/models/vehicle-class.model.ts @@ -1,44 +1,44 @@ export interface VehicleClass { - code?: CodesEnum; - description?: DescriptionsEnum; + code?: CodesEnum; + description?: DescriptionsEnum; } export type CodesEnum = '2' | 'n' | 's' | '1' | 't' | 'l' | '3' | 'v' | '4' | '7' | '5'; export const CodeEnum = { - _2: '2' as CodesEnum, - N: 'n' as CodesEnum, - S: 's' as CodesEnum, - _1: '1' as CodesEnum, - T: 't' as CodesEnum, - L: 'l' as CodesEnum, - _3: '3' as CodesEnum, - V: 'v' as CodesEnum, - _4: '4' as CodesEnum, - _7: '7' as CodesEnum, - _5: '5' as CodesEnum, + _2: '2' as CodesEnum, + N: 'n' as CodesEnum, + S: 's' as CodesEnum, + _1: '1' as CodesEnum, + T: 't' as CodesEnum, + L: 'l' as CodesEnum, + _3: '3' as CodesEnum, + V: 'v' as CodesEnum, + _4: '4' as CodesEnum, + _7: '7' as CodesEnum, + _5: '5' as CodesEnum, }; export type DescriptionsEnum = - | 'motorbikes over 200cc or with a sidecar' - | 'not applicable' - | 'small psv (ie: less than or equal to 22 seats)' - | 'motorbikes up to 200cc' - | 'trailer' - | 'large psv(ie: greater than 23 seats)' - | '3 wheelers' - | 'heavy goods vehicle' - | 'MOT class 4' - | 'MOT class 7' - | 'MOT class 5'; + | 'motorbikes over 200cc or with a sidecar' + | 'not applicable' + | 'small psv (ie: less than or equal to 22 seats)' + | 'motorbikes up to 200cc' + | 'trailer' + | 'large psv(ie: greater than 23 seats)' + | '3 wheelers' + | 'heavy goods vehicle' + | 'MOT class 4' + | 'MOT class 7' + | 'MOT class 5'; export const DescriptionEnum = { - MotorbikesOver200ccOrWithASidecar: 'motorbikes over 200cc or with a sidecar' as DescriptionsEnum, - NotApplicable: 'not applicable' as DescriptionsEnum, - SmallPsvIeLessThanOrEqualTo22Seats: 'small psv (ie: less than or equal to 22 seats)' as DescriptionsEnum, - MotorbikesUpTo200cc: 'motorbikes up to 200cc' as DescriptionsEnum, - Trailer: 'trailer' as DescriptionsEnum, - LargePsvIeGreaterThan23Seats: 'large psv(ie: greater than 23 seats)' as DescriptionsEnum, - _3Wheelers: '3 wheelers' as DescriptionsEnum, - HeavyGoodsVehicle: 'heavy goods vehicle' as DescriptionsEnum, - MOTClass4: 'MOT class 4' as DescriptionsEnum, - MOTClass7: 'MOT class 7' as DescriptionsEnum, - MOTClass5: 'MOT class 5' as DescriptionsEnum, + MotorbikesOver200ccOrWithASidecar: 'motorbikes over 200cc or with a sidecar' as DescriptionsEnum, + NotApplicable: 'not applicable' as DescriptionsEnum, + SmallPsvIeLessThanOrEqualTo22Seats: 'small psv (ie: less than or equal to 22 seats)' as DescriptionsEnum, + MotorbikesUpTo200cc: 'motorbikes up to 200cc' as DescriptionsEnum, + Trailer: 'trailer' as DescriptionsEnum, + LargePsvIeGreaterThan23Seats: 'large psv(ie: greater than 23 seats)' as DescriptionsEnum, + _3Wheelers: '3 wheelers' as DescriptionsEnum, + HeavyGoodsVehicle: 'heavy goods vehicle' as DescriptionsEnum, + MOTClass4: 'MOT class 4' as DescriptionsEnum, + MOTClass7: 'MOT class 7' as DescriptionsEnum, + MOTClass5: 'MOT class 5' as DescriptionsEnum, }; diff --git a/src/app/models/vehicle-configuration.enum.ts b/src/app/models/vehicle-configuration.enum.ts index 0ebc2bb204..78230f7742 100644 --- a/src/app/models/vehicle-configuration.enum.ts +++ b/src/app/models/vehicle-configuration.enum.ts @@ -1,32 +1,32 @@ export enum VehicleConfiguration { - RIGID = 'rigid', - ARTICULATED = 'articulated', - CENTRE_AXLE_DRAWBAR = 'centre axle drawbar', - SEMI_CAR_TRANSPORTER = 'semi-car transporter', - SEMI_TRAILER = 'semi-trailer', - LOW_LOADER = 'low loader', - OTHER = 'other', - DRAWBAR = 'drawbar', - FOUR_IN_LINE = 'four-in-line', - DOLLY = 'dolly', - FULL_DRAWBAR = 'full drawbar', - LONG_SEMI_TRAILER = 'long semi-trailer', + RIGID = 'rigid', + ARTICULATED = 'articulated', + CENTRE_AXLE_DRAWBAR = 'centre axle drawbar', + SEMI_CAR_TRANSPORTER = 'semi-car transporter', + SEMI_TRAILER = 'semi-trailer', + LOW_LOADER = 'low loader', + OTHER = 'other', + DRAWBAR = 'drawbar', + FOUR_IN_LINE = 'four-in-line', + DOLLY = 'dolly', + FULL_DRAWBAR = 'full drawbar', + LONG_SEMI_TRAILER = 'long semi-trailer', } export enum HgvPsvVehicleConfiguration { - RIGID = 'rigid', - ARTICULATED = 'articulated', + RIGID = 'rigid', + ARTICULATED = 'articulated', } export enum TrlVehicleConfiguration { - CENTRE_AXLE_DRAWBAR = 'centre axle drawbar', - SEMI_CAR_TRANSPORTER = 'semi-car transporter', - SEMI_TRAILER = 'semi-trailer', - LOW_LOADER = 'low loader', - OTHER = 'other', - DRAWBAR = 'drawbar', - FOUR_IN_LINE = 'four-in-line', - DOLLY = 'dolly', - FULL_DRAWBAR = 'full drawbar', - LONG_SEMI_TRAILER = 'long semi-trailer', + CENTRE_AXLE_DRAWBAR = 'centre axle drawbar', + SEMI_CAR_TRANSPORTER = 'semi-car transporter', + SEMI_TRAILER = 'semi-trailer', + LOW_LOADER = 'low loader', + OTHER = 'other', + DRAWBAR = 'drawbar', + FOUR_IN_LINE = 'four-in-line', + DOLLY = 'dolly', + FULL_DRAWBAR = 'full drawbar', + LONG_SEMI_TRAILER = 'long semi-trailer', } diff --git a/src/app/models/vehicle-size.enum.ts b/src/app/models/vehicle-size.enum.ts index ae5a8ddb91..c3c8e50c80 100644 --- a/src/app/models/vehicle-size.enum.ts +++ b/src/app/models/vehicle-size.enum.ts @@ -1,4 +1,4 @@ export enum VehicleSize { - SMALL = 'small', - LARGE = 'large', + SMALL = 'small', + LARGE = 'large', } diff --git a/src/app/models/vehicle-tech-record.model.ts b/src/app/models/vehicle-tech-record.model.ts index 19b6f9e22a..93841e4008 100644 --- a/src/app/models/vehicle-tech-record.model.ts +++ b/src/app/models/vehicle-tech-record.model.ts @@ -7,11 +7,11 @@ import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/ import { BodyTypeCode, BodyTypeDescription } from './body-type-enum'; export interface VehicleTechRecordModel { - vrms: Vrm[]; - vin: string; - trailerId?: string; - systemNumber: string; - techRecord: TechRecordModel[]; + vrms: Vrm[]; + vin: string; + trailerId?: string; + systemNumber: string; + techRecord: TechRecordModel[]; } export type V3TechRecordModel = TechRecordType<'get'> | TechRecordType<'put'>; @@ -20,488 +20,490 @@ export type Empty = { [key in keyof T]: T[key] | null }; export type VehiclesOtherThan = TechRecordTypeByVehicle>; -export type Axles = NonNullable['techRecord_axles']>; +export type Axles = NonNullable< + TechRecordTypeByVehicle['techRecord_axles'] +>; export type Axle = Axles[0]; export type BatchUpdateVehicleModel = TechRecordType<'put'> & { - createdTimestamp: string; - systemNumber?: string; + createdTimestamp: string; + systemNumber?: string; }; export interface PostNewVehicleModel extends Omit { - primaryVrm?: string; - secondaryVrms?: string[]; + primaryVrm?: string; + secondaryVrms?: string[]; } export interface Vrm { - vrm: string; - isPrimary: boolean; + vrm: string; + isPrimary: boolean; } export enum ReasonForEditing { - CORRECTING_AN_ERROR = 'correcting-an-error', - NOTIFIABLE_ALTERATION_NEEDED = 'notifiable-alteration-needed', + CORRECTING_AN_ERROR = 'correcting-an-error', + NOTIFIABLE_ALTERATION_NEEDED = 'notifiable-alteration-needed', } export enum StatusCodes { - ARCHIVED = 'archived', - CURRENT = 'current', - PROVISIONAL = 'provisional', + ARCHIVED = 'archived', + CURRENT = 'current', + PROVISIONAL = 'provisional', } export enum VehicleTypes { - PSV = 'psv', - HGV = 'hgv', - TRL = 'trl', - LGV = 'lgv', - CAR = 'car', - SMALL_TRL = 'small trl', - MOTORCYCLE = 'motorcycle', + PSV = 'psv', + HGV = 'hgv', + TRL = 'trl', + LGV = 'lgv', + CAR = 'car', + SMALL_TRL = 'small trl', + MOTORCYCLE = 'motorcycle', } export enum TrailerFormType { - TES1 = 'tes1', - TES2 = 'tes2', + TES1 = 'tes1', + TES2 = 'tes2', } export enum FuelTypes { - DIESELPETROL = 'DieselPetrol', - DIESEL = 'Diesel', - PETROL = 'Petrol', - HYBRID = 'Hybrid', - ELECTRIC = 'Electric', - CNG = 'CNG', - FUELCELL = 'Fuel cell', - LNG = 'LNG', - OTHER = 'Other', + DIESELPETROL = 'DieselPetrol', + DIESEL = 'Diesel', + PETROL = 'Petrol', + HYBRID = 'Hybrid', + ELECTRIC = 'Electric', + CNG = 'CNG', + FUELCELL = 'Fuel cell', + LNG = 'LNG', + OTHER = 'Other', } export enum VehicleConfigurations { - RIGID = 'rigid', - ARTICULATED = 'articulated', - CENTRE_AXLE_DRAWBAR = 'centre axle drawbar', - SEMI_CAR_TRANSPORTER = 'semi-car transporter', - SEMI_TRAILER = 'semi-trailer', - LOW_LOADER = 'low loader', - OTHER = 'other', - DRAWBAR = 'drawbar', - FOUR_IN_LINE = 'four-in-line', - DOLLY = 'dolly', - FULL_DRAWBAR = 'full drawbar', - LONG_SEMI_TRAILER = 'long semi-trailer', + RIGID = 'rigid', + ARTICULATED = 'articulated', + CENTRE_AXLE_DRAWBAR = 'centre axle drawbar', + SEMI_CAR_TRANSPORTER = 'semi-car transporter', + SEMI_TRAILER = 'semi-trailer', + LOW_LOADER = 'low loader', + OTHER = 'other', + DRAWBAR = 'drawbar', + FOUR_IN_LINE = 'four-in-line', + DOLLY = 'dolly', + FULL_DRAWBAR = 'full drawbar', + LONG_SEMI_TRAILER = 'long semi-trailer', } export enum FrameDescriptions { - CHANNEL_SECTION = 'Channel section', - SPACE_FRAME = 'Space frame', - I_SECTION = 'I section', - TUBULAR = 'Tubular', - FRAME_SECTION = 'Frame section', - OTHER = 'Other', - INTEGRAL = 'integral', - BOX_SECTION = 'Box section', - U_SECTION = 'U section', + CHANNEL_SECTION = 'Channel section', + SPACE_FRAME = 'Space frame', + I_SECTION = 'I section', + TUBULAR = 'Tubular', + FRAME_SECTION = 'Frame section', + OTHER = 'Other', + INTEGRAL = 'integral', + BOX_SECTION = 'Box section', + U_SECTION = 'U section', } export enum VehicleSizes { - SMALL = 'small', - LARGE = 'large', + SMALL = 'small', + LARGE = 'large', } export enum VehicleSubclass { - N = 'n', - P = 'p', - A = 'a', - S = 's', - C = 'c', - L = 'l', - T = 't', - E = 'e', - M = 'm', - R = 'r', - W = 'w', + N = 'n', + P = 'p', + A = 'a', + S = 's', + C = 'c', + L = 'l', + T = 't', + E = 'e', + M = 'm', + R = 'r', + W = 'w', } export interface LettersOfAuth { - letterType: string; - paragraphId: ParagraphIds; - letterIssuer: string; - letterDateRequested: string; - letterContents: string; + letterType: string; + paragraphId: ParagraphIds; + letterIssuer: string; + letterDateRequested: string; + letterContents: string; } export enum LettersIntoAuthApprovalType { - GB_WVTA = 'GB WVTA', - UKNI_WVTA = 'UKNI WVTA', - EU_WVTA_PRE_23 = 'EU WVTA Pre 23', - EU_WVTA_23_ON = 'EU WVTA 23 on', - QNIG = 'QNIG', - PROV_GB_WVTA = 'Prov.GB WVTA', - SMALL_SERIES_NKSXX = 'Small series NKSXX', - SMALL_SERIES_NKS = 'Small series NKS', - IVA_VCA = 'IVA - VCA', - IVA_DVSA_NI = 'IVA - DVSA/NI', + GB_WVTA = 'GB WVTA', + UKNI_WVTA = 'UKNI WVTA', + EU_WVTA_PRE_23 = 'EU WVTA Pre 23', + EU_WVTA_23_ON = 'EU WVTA 23 on', + QNIG = 'QNIG', + PROV_GB_WVTA = 'Prov.GB WVTA', + SMALL_SERIES_NKSXX = 'Small series NKSXX', + SMALL_SERIES_NKS = 'Small series NKS', + IVA_VCA = 'IVA - VCA', + IVA_DVSA_NI = 'IVA - DVSA/NI', } export enum ParagraphId { - PARAGRAPH_3 = 3, - PARAGRAPH_4 = 4, - PARAGRAPH_5 = 5, - PARAGRAPH_6 = 6, - PARAGRAPH_7 = 7, + PARAGRAPH_3 = 3, + PARAGRAPH_4 = 4, + PARAGRAPH_5 = 5, + PARAGRAPH_6 = 6, + PARAGRAPH_7 = 7, } export enum SpeedCategorySymbol { - A7 = 'a7', - A8 = 'a8', - B = 'b', - C = 'c', - D = 'd', - E = 'e', - F = 'f', - G = 'g', - J = 'j', - K = 'k', - L = 'l', - M = 'm', - N = 'n', - P = 'p', - Q = 'q', + A7 = 'a7', + A8 = 'a8', + B = 'b', + C = 'c', + D = 'd', + E = 'e', + F = 'f', + G = 'g', + J = 'j', + K = 'k', + L = 'l', + M = 'm', + N = 'n', + P = 'p', + Q = 'q', } export enum FitmentCode { - SINGLE = 'single', - DOUBLE = 'double', + SINGLE = 'single', + DOUBLE = 'double', } export interface Tyres { - tyreCode?: number | null; - tyreSize?: string | null; - plyRating?: string | null; - fitmentCode?: FitmentCode | null; - speedCategorySymbol?: SpeedCategorySymbol | null; - dataTrAxles?: number | null; + tyreCode?: number | null; + tyreSize?: string | null; + plyRating?: string | null; + fitmentCode?: FitmentCode | null; + speedCategorySymbol?: SpeedCategorySymbol | null; + dataTrAxles?: number | null; } export class Tyre implements Tyres { - tyreSize!: string | null; - speedCategorySymbol!: SpeedCategorySymbol | null; - fitmentCode!: FitmentCode | null; - dataTrAxles!: number | null; - plyRating!: string | null; - tyreCode!: number | null; + tyreSize!: string | null; + speedCategorySymbol!: SpeedCategorySymbol | null; + fitmentCode!: FitmentCode | null; + dataTrAxles!: number | null; + plyRating!: string | null; + tyreCode!: number | null; - constructor(tyre: Tyres) { - Object.assign(this, tyre); - } + constructor(tyre: Tyres) { + Object.assign(this, tyre); + } } export interface AxleWeights { - kerbWeight?: number | null; - ladenWeight?: number | null; - gbWeight?: number | null; - eecWeight?: number | null; - designWeight?: number | null; + kerbWeight?: number | null; + ladenWeight?: number | null; + gbWeight?: number | null; + eecWeight?: number | null; + designWeight?: number | null; } export interface Purchaser { - name?: string; - address1?: string; - address2?: string; - postTown?: string; - address3?: string | null; - postCode?: string | null; - telephoneNumber?: string | null; - emailAddress?: string | null; - faxNumber?: string | null; - purchaserNotes?: string | null; + name?: string; + address1?: string; + address2?: string; + postTown?: string; + address3?: string | null; + postCode?: string | null; + telephoneNumber?: string | null; + emailAddress?: string | null; + faxNumber?: string | null; + purchaserNotes?: string | null; } export interface BodyType { - description?: BodyTypeDescription; - code?: BodyTypeCode; + description?: BodyTypeDescription; + code?: BodyTypeCode; } export interface TechRecordModel { - historicVin?: string; - historicPrimaryVrm?: string; - historicSecondaryVrms?: string[]; - createdAt: Date; - createdByName?: string; - statusCode?: StatusCodes; - vehicleType: VehicleTypes; - regnDate?: string; - firstUseDate?: string; - manufactureYear?: number; - noOfAxles?: number; - axles?: Axle[]; - suspensionType?: string; - speedRestriction?: number; - speedLimiterMrk?: boolean; - tachoExemptMrk?: boolean; - euroStandard?: string; - roadFriendly?: boolean; - fuelPropulsionSystem?: FuelTypes; - drawbarCouplingFitted?: boolean; - vehicleClass?: { - description: string; - code: string; - }; - vehicleConfiguration?: VehicleConfigurations | null; - couplingType?: string; - maxLoadOnCoupling?: number; - frameDescription?: FrameDescriptions; - offRoad?: boolean; - numberOfWheelsDriven?: number; - euVehicleCategory?: EUVehicleCategory; - emissionsLimit?: number; - seatsLowerDeck?: number; - seatsUpperDeck?: number; - standingCapacity?: number; - vehicleSize?: VehicleSizes; - numberOfSeatbelts?: string; - seatbeltInstallationApprovalDate?: string; - departmentalVehicleMarker?: boolean; - approvalType?: ApprovalType; - approvalTypeNumber?: string; - ntaNumber?: string; - coifSerialNumber?: string; - coifCertifierName?: string; - coifDate?: string | Date; - variantNumber?: string; - variantVersionNumber?: string; - brakes?: Brakes; - applicantDetails?: ApplicantDetails; - microfilm?: Microfilm; - remarks?: string; - reasonForCreation?: string; - modelLiteral?: string; - make?: string; - model?: string; - chassisMake?: string; - chassisModel?: string; - bodyMake?: string; - bodyModel?: string; - bodyType?: BodyType; - functionCode?: string; - conversionRefNo?: string; - purchaserDetails?: Purchaser; - authIntoService?: AuthIntoService; - notes?: string; - vehicleSubclass?: Array; - - // Gross vehicle weights - grossKerbWeight?: number; - grossLadenWeight?: number; - grossGbWeight?: number; - grossEecWeight?: number; - grossDesignWeight?: number; - unladenWeight?: number; - - // Train weights - trainDesignWeight?: number; - trainEecWeight?: number; - trainGbWeight?: number; - - // Max Train Weights - maxTrainGbWeight?: number; - maxTrainDesignWeight?: number; - maxTrainEecWeight?: number; - - // Dimensions - dimensions?: Dimensions; - frontAxleToRearAxle?: number; - rearAxleToRearTrl?: number; - - // Front of vehicle to 5th wheel coupling - frontVehicleTo5thWheelCouplingMin?: number; - frontVehicleTo5thWheelCouplingMax?: number; - - // Front axle to 5th wheel - frontAxleTo5thWheelMin?: number; - frontAxleTo5thWheelMax?: number; - - // Coupling center to rear axle - couplingCenterToRearAxleMin?: number; - couplingCenterToRearAxleMax?: number; - - // Coupling center to rear trailer - couplingCenterToRearTrlMin?: number; - couplingCenterToRearTrlMax?: number; - plates?: Plates[]; - letterOfAuth?: LettersOfAuth; - dda?: DDA; - updateType?: string; - - recordCompleteness?: string; - hiddenInVta?: boolean; + historicVin?: string; + historicPrimaryVrm?: string; + historicSecondaryVrms?: string[]; + createdAt: Date; + createdByName?: string; + statusCode?: StatusCodes; + vehicleType: VehicleTypes; + regnDate?: string; + firstUseDate?: string; + manufactureYear?: number; + noOfAxles?: number; + axles?: Axle[]; + suspensionType?: string; + speedRestriction?: number; + speedLimiterMrk?: boolean; + tachoExemptMrk?: boolean; + euroStandard?: string; + roadFriendly?: boolean; + fuelPropulsionSystem?: FuelTypes; + drawbarCouplingFitted?: boolean; + vehicleClass?: { + description: string; + code: string; + }; + vehicleConfiguration?: VehicleConfigurations | null; + couplingType?: string; + maxLoadOnCoupling?: number; + frameDescription?: FrameDescriptions; + offRoad?: boolean; + numberOfWheelsDriven?: number; + euVehicleCategory?: EUVehicleCategory; + emissionsLimit?: number; + seatsLowerDeck?: number; + seatsUpperDeck?: number; + standingCapacity?: number; + vehicleSize?: VehicleSizes; + numberOfSeatbelts?: string; + seatbeltInstallationApprovalDate?: string; + departmentalVehicleMarker?: boolean; + approvalType?: ApprovalType; + approvalTypeNumber?: string; + ntaNumber?: string; + coifSerialNumber?: string; + coifCertifierName?: string; + coifDate?: string | Date; + variantNumber?: string; + variantVersionNumber?: string; + brakes?: Brakes; + applicantDetails?: ApplicantDetails; + microfilm?: Microfilm; + remarks?: string; + reasonForCreation?: string; + modelLiteral?: string; + make?: string; + model?: string; + chassisMake?: string; + chassisModel?: string; + bodyMake?: string; + bodyModel?: string; + bodyType?: BodyType; + functionCode?: string; + conversionRefNo?: string; + purchaserDetails?: Purchaser; + authIntoService?: AuthIntoService; + notes?: string; + vehicleSubclass?: Array; + + // Gross vehicle weights + grossKerbWeight?: number; + grossLadenWeight?: number; + grossGbWeight?: number; + grossEecWeight?: number; + grossDesignWeight?: number; + unladenWeight?: number; + + // Train weights + trainDesignWeight?: number; + trainEecWeight?: number; + trainGbWeight?: number; + + // Max Train Weights + maxTrainGbWeight?: number; + maxTrainDesignWeight?: number; + maxTrainEecWeight?: number; + + // Dimensions + dimensions?: Dimensions; + frontAxleToRearAxle?: number; + rearAxleToRearTrl?: number; + + // Front of vehicle to 5th wheel coupling + frontVehicleTo5thWheelCouplingMin?: number; + frontVehicleTo5thWheelCouplingMax?: number; + + // Front axle to 5th wheel + frontAxleTo5thWheelMin?: number; + frontAxleTo5thWheelMax?: number; + + // Coupling center to rear axle + couplingCenterToRearAxleMin?: number; + couplingCenterToRearAxleMax?: number; + + // Coupling center to rear trailer + couplingCenterToRearTrlMin?: number; + couplingCenterToRearTrlMax?: number; + plates?: Plates[]; + letterOfAuth?: LettersOfAuth; + dda?: DDA; + updateType?: string; + + recordCompleteness?: string; + hiddenInVta?: boolean; } export interface AuthIntoService { - cocIssueDate?: string | null; - dateReceived?: string | null; - datePending?: string | null; - dateAuthorised?: string | null; - dateRejected?: string | null; + cocIssueDate?: string | null; + dateReceived?: string | null; + datePending?: string | null; + dateAuthorised?: string | null; + dateRejected?: string | null; } export interface DDA { - certificateIssued?: boolean; - wheelchairCapacity?: number; - wheelchairFittings?: string; - wheelchairLiftPresent?: boolean; - wheelchairLiftInformation?: string; - wheelchairRampPresent?: boolean; - wheelchairRampInformation?: string; - minEmergencyExits?: number; - outswing?: string; - ddaSchedules?: string; - seatbeltsFitted?: number; - ddaNotes?: string; + certificateIssued?: boolean; + wheelchairCapacity?: number; + wheelchairFittings?: string; + wheelchairLiftPresent?: boolean; + wheelchairLiftInformation?: string; + wheelchairRampPresent?: boolean; + wheelchairRampInformation?: string; + minEmergencyExits?: number; + outswing?: string; + ddaSchedules?: string; + seatbeltsFitted?: number; + ddaNotes?: string; } export interface Plates { - plateSerialNumber?: string; - plateIssueDate?: Date; - plateReasonForIssue?: PlateReasonForIssue; - plateIssuer?: string; + plateSerialNumber?: string; + plateIssueDate?: Date; + plateReasonForIssue?: PlateReasonForIssue; + plateIssuer?: string; } export enum PlateReasonForIssue { - FREE_REPLACEMENT = 'Free replacement', - REPLACEMENT = 'Replacement', - DESTROYED = 'Destroyed', - PROVISIONAL = 'Provisional', - ORIGINAL = 'Original', - MANUAL = 'Manual', + FREE_REPLACEMENT = 'Free replacement', + REPLACEMENT = 'Replacement', + DESTROYED = 'Destroyed', + PROVISIONAL = 'Provisional', + ORIGINAL = 'Original', + MANUAL = 'Manual', } export interface ApplicantDetails { - name?: string; - address1?: string; - address2?: string; - postTown?: string; - address3?: string; - postCode?: string; - telephoneNumber?: string; - emailAddress?: string; + name?: string; + address1?: string; + address2?: string; + postTown?: string; + address3?: string; + postCode?: string; + telephoneNumber?: string; + emailAddress?: string; } export interface Dimensions { - height?: number; - length?: number; - width?: number; - axleSpacing?: AxleSpacing[]; + height?: number; + length?: number; + width?: number; + axleSpacing?: AxleSpacing[]; } export interface AxleSpacing { - axles?: string; - value?: number | null; + axles?: string; + value?: number | null; } export interface Brakes { - dtpNumber?: string; - loadSensingValve?: string; // TODO: Check from here if these types are correct - antilockBrakingSystem?: string; - axleNumber?: string; - axleBrakeProperties?: AxleBrakeProperties; // Check to here and including object - brakeCode?: string; - brakeCodeOriginal?: string; - dataTrBrakeOne?: string; - dataTrBrakeTwo?: string; - dataTrBrakeThree?: string; - retarderBrakeOne?: Retarders; - retarderBrakeTwo?: Retarders; - brakeForceWheelsNotLocked?: BrakeForceWheelsNotLocked; - brakeForceWheelsUpToHalfLocked?: BrakeForceWheelsUpToHalfLocked; + dtpNumber?: string; + loadSensingValve?: string; // TODO: Check from here if these types are correct + antilockBrakingSystem?: string; + axleNumber?: string; + axleBrakeProperties?: AxleBrakeProperties; // Check to here and including object + brakeCode?: string; + brakeCodeOriginal?: string; + dataTrBrakeOne?: string; + dataTrBrakeTwo?: string; + dataTrBrakeThree?: string; + retarderBrakeOne?: Retarders; + retarderBrakeTwo?: Retarders; + brakeForceWheelsNotLocked?: BrakeForceWheelsNotLocked; + brakeForceWheelsUpToHalfLocked?: BrakeForceWheelsUpToHalfLocked; } export interface BrakeForceWheelsNotLocked { - parkingBrakeForceA?: number; - secondaryBrakeForceA?: number; - serviceBrakeForceA?: number; + parkingBrakeForceA?: number; + secondaryBrakeForceA?: number; + serviceBrakeForceA?: number; } export interface BrakeForceWheelsUpToHalfLocked { - parkingBrakeForceB?: number; - secondaryBrakeForceB?: number; - serviceBrakeForceB?: number; + parkingBrakeForceB?: number; + secondaryBrakeForceB?: number; + serviceBrakeForceB?: number; } export enum Retarders { - ELECTRIC = 'electric', - EXHAUST = 'exhaust', - FRICTION = 'friction', - HYDRAULIC = 'hydraulic', - OTHER = 'other', - NONE = 'none', + ELECTRIC = 'electric', + EXHAUST = 'exhaust', + FRICTION = 'friction', + HYDRAULIC = 'hydraulic', + OTHER = 'other', + NONE = 'none', } export interface AxleBrakeProperties { - brakeActuator?: string; - leverLength?: string; - springBrakeParking?: boolean; + brakeActuator?: string; + leverLength?: string; + springBrakeParking?: boolean; } export interface Microfilm { - microfilmDocumentType?: MicrofilmDocumentType; - microfilmRollNumber?: string; - microfilmSerialNumber?: string; + microfilmDocumentType?: MicrofilmDocumentType; + microfilmRollNumber?: string; + microfilmSerialNumber?: string; } export enum MicrofilmDocumentType { - PSVMisc = 'PSV Miscellaneous', - AAT = 'AAT - Trailer Annual Test', - AIV = 'AIV - HGV International App', - COIFMod = 'COIF Modification', - Trailer = 'Trailer COC + Int Plate', - RCT = 'RCT - Trailer Test Cert paid', - HGV = 'HGV COC + Int Plate', - PSVCarry = 'PSV Carry/Auth', - OMORep = 'OMO Report', - AIT = 'AIT - Trailer International App', - IPV = 'IPV - HGV EEC Plate/Cert', - XCV = 'XCV - HGV Test Cert free', - AAV = 'AAV - HGV Annual Test', - COIFMaster = 'COIF Master', - Tempo100 = 'Tempo 100 Sp Ord', - Deleted = 'Deleted', - PSVNalt = 'PSV N/ALT', - XPT = 'XPT - Tr Plating Cert paid', - FFV = 'FFV - HGV First Test', - Repl = 'Repl Vitesse 100', - TCV = 'TCV - HGV Test Cert', - ZZZ = 'ZZZ - Miscellaneous', - Test = 'Test Certificate', - XCT = 'XCT - Trailer Test Cert free', - C52 = 'C52 - COC and VTG52A', - Tempo100Rep = 'Tempo 100 Report', - Main = 'Main File Amendment', - PSVDoc = 'PSV Doc', - PSVCOC = 'PSV COC', - PSVReplCOC = 'PSV Repl COC', - TAV = 'TAV - COC', - NPT = 'NPT - Trailer Alteration', - OMO = 'OMO Certificate', - PSVReplCOIF = 'PSV Repl COIF', - PSVReplCOF = 'PSV Repl COF', - COIFApp = 'COIF Application', - XPV = 'XPV - HGV Plating Cert Free', - TCT = 'TCT - Trailer Test Cert', - Tempo100App = 'Tempo 100 App', - PSV = 'PSV Decision on N/ALT', - Special = 'Special Order PSV', - NPV = 'NPV - HGV Alteration', - No = 'No Description Found', - Vitesse = 'Vitesse 100 Sp Ord', - Brake = 'Brake Test Details', - COIF = 'COIF Productional', - RDT = 'RDT - Test Disc Paid', - RCV = 'RCV - HGV Test Cert', - FFT = 'FFT - Trailer First Test', - IPT = 'IPT - Trailer EEC Plate/Cert', - XDT = 'XDT - Test Disc Free', - PRV = 'PRV - HGV Plating Cert paid', - COF = 'COF Cert', - PRT = 'PRT - Tr Plating Cert paid', - Tempo = 'Tempo 100 Permit', + PSVMisc = 'PSV Miscellaneous', + AAT = 'AAT - Trailer Annual Test', + AIV = 'AIV - HGV International App', + COIFMod = 'COIF Modification', + Trailer = 'Trailer COC + Int Plate', + RCT = 'RCT - Trailer Test Cert paid', + HGV = 'HGV COC + Int Plate', + PSVCarry = 'PSV Carry/Auth', + OMORep = 'OMO Report', + AIT = 'AIT - Trailer International App', + IPV = 'IPV - HGV EEC Plate/Cert', + XCV = 'XCV - HGV Test Cert free', + AAV = 'AAV - HGV Annual Test', + COIFMaster = 'COIF Master', + Tempo100 = 'Tempo 100 Sp Ord', + Deleted = 'Deleted', + PSVNalt = 'PSV N/ALT', + XPT = 'XPT - Tr Plating Cert paid', + FFV = 'FFV - HGV First Test', + Repl = 'Repl Vitesse 100', + TCV = 'TCV - HGV Test Cert', + ZZZ = 'ZZZ - Miscellaneous', + Test = 'Test Certificate', + XCT = 'XCT - Trailer Test Cert free', + C52 = 'C52 - COC and VTG52A', + Tempo100Rep = 'Tempo 100 Report', + Main = 'Main File Amendment', + PSVDoc = 'PSV Doc', + PSVCOC = 'PSV COC', + PSVReplCOC = 'PSV Repl COC', + TAV = 'TAV - COC', + NPT = 'NPT - Trailer Alteration', + OMO = 'OMO Certificate', + PSVReplCOIF = 'PSV Repl COIF', + PSVReplCOF = 'PSV Repl COF', + COIFApp = 'COIF Application', + XPV = 'XPV - HGV Plating Cert Free', + TCT = 'TCT - Trailer Test Cert', + Tempo100App = 'Tempo 100 App', + PSV = 'PSV Decision on N/ALT', + Special = 'Special Order PSV', + NPV = 'NPV - HGV Alteration', + No = 'No Description Found', + Vitesse = 'Vitesse 100 Sp Ord', + Brake = 'Brake Test Details', + COIF = 'COIF Productional', + RDT = 'RDT - Test Disc Paid', + RCV = 'RCV - HGV Test Cert', + FFT = 'FFT - Trailer First Test', + IPT = 'IPT - Trailer EEC Plate/Cert', + XDT = 'XDT - Test Disc Free', + PRV = 'PRV - HGV Plating Cert paid', + COF = 'COF Cert', + PRT = 'PRT - Tr Plating Cert paid', + Tempo = 'Tempo 100 Permit', } diff --git a/src/app/resolvers/contingency-test/contingency-test.resolver.spec.ts b/src/app/resolvers/contingency-test/contingency-test.resolver.spec.ts index f6863ed1bf..d87b399e84 100644 --- a/src/app/resolvers/contingency-test/contingency-test.resolver.spec.ts +++ b/src/app/resolvers/contingency-test/contingency-test.resolver.spec.ts @@ -12,203 +12,194 @@ import { TechnicalRecordService } from '@services/technical-record/technical-rec import { UserService } from '@services/user-service/user-service'; import { State, initialAppState } from '@store/.'; import { initialContingencyTest } from '@store/test-records'; -import { - Observable, - ReplaySubject, - firstValueFrom, - of, - throwError, -} from 'rxjs'; -import { - contingencyTestResolver, - getBodyMake, - getBodyModel, - getBodyType, -} from './contingency-test.resolver'; +import { Observable, ReplaySubject, firstValueFrom, of, throwError } from 'rxjs'; +import { contingencyTestResolver, getBodyMake, getBodyModel, getBodyType } from './contingency-test.resolver'; describe('ContingencyTestResolver', () => { - let resolver: ResolveFn; - const actions$ = new ReplaySubject(); - let store: MockStore; - let techRecordService: TechnicalRecordService; - - const MockUserService = { - getUserName$: jest.fn().mockReturnValue(new Observable()), - get user$() { - return of('foo'); - }, - }; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - provideMockActions(() => actions$), - TechnicalRecordService, - { provide: UserService, useValue: MockUserService }, - ], - }); - resolver = (...resolverParameters) => - TestBed.runInInjectionContext(() => contingencyTestResolver(...resolverParameters)); - store = TestBed.inject(MockStore); - techRecordService = TestBed.inject(TechnicalRecordService); - }); - - it('should be created', () => { - expect(resolver).toBeTruthy(); - }); - - it('should return true and dispatch the initial contingency test action', async () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue(of(mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>)); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - const resolveResult = await firstValueFrom(result); - - expect(resolveResult).toBe(true); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(expect.objectContaining({ type: initialContingencyTest.type, testResult: expect.anything() })); - }); - - it('should return false if there is an error', async () => { - jest.spyOn(techRecordService, 'techRecord$', 'get').mockReturnValue(of(mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>)); - jest.spyOn(MockUserService, 'user$', 'get').mockImplementationOnce(() => throwError(() => new Error('foo'))); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - const resolveResult = await firstValueFrom(result); - expect(resolveResult).toBe(false); - }); - - describe('getBodyMake', () => { - it('should return vehicle make if vehicle is psv', () => { - const techRecord = { - techRecord_vehicleType: 'psv', - techRecord_bodyMake: 'test make 1', - } as V3TechRecordModel; - - const make = getBodyMake(techRecord); - expect(make).toBe('test make 1'); - }); - - it('should return vehicle make if vehicle is hgv', () => { - const techRecord = { - techRecord_vehicleType: 'hgv', - techRecord_make: 'test make 2', - } as V3TechRecordModel; - - const make = getBodyMake(techRecord); - expect(make).toBe('test make 2'); - }); - - it('should return vehicle make if vehicle is trl', () => { - const techRecord = { - techRecord_vehicleType: 'trl', - techRecord_make: 'test make 3', - } as V3TechRecordModel; - - const make = getBodyMake(techRecord); - expect(make).toBe('test make 3'); - }); - - it('should not return vehicle make if vehicle is not hgv, psv or trl', () => { - const techRecord = { - techRecord_vehicleType: 'car', - } as V3TechRecordModel; - - const make = getBodyMake(techRecord); - expect(make).toBeNull(); - }); - }); - - describe('getBodyModel', () => { - it('should return vehicle model if vehicle is psv', () => { - const techRecord = { - techRecord_vehicleType: 'psv', - techRecord_bodyModel: 'test model 1', - } as V3TechRecordModel; - - const model = getBodyModel(techRecord); - expect(model).toBe('test model 1'); - }); - - it('should return vehicle model if vehicle is hgv', () => { - const techRecord = { - techRecord_vehicleType: 'hgv', - techRecord_model: 'test model 2', - } as V3TechRecordModel; - - const model = getBodyModel(techRecord); - expect(model).toBe('test model 2'); - }); - - it('should return vehicle model if vehicle is trl', () => { - const techRecord = { - techRecord_vehicleType: 'trl', - techRecord_model: 'test model 3', - } as V3TechRecordModel; - - const model = getBodyModel(techRecord); - expect(model).toBe('test model 3'); - }); - - it('should not return vehicle model if vehicle is not hgv, psv or trl', () => { - const techRecord = { - techRecord_vehicleType: 'car', - } as V3TechRecordModel; - - const model = getBodyModel(techRecord); - expect(model).toBeNull(); - }); - }); - - describe('getBodyType', () => { - it('should return vehicle body type if vehicle is psv', () => { - const techRecord = { - techRecord_vehicleType: 'psv', - techRecord_bodyType_code: 'test code 1', - techRecord_bodyType_description: 'flat', - - } as V3TechRecordModel; - - const bodyType = getBodyType(techRecord); - expect(bodyType).toStrictEqual({ code: 'test code 1', description: 'flat' }); - }); - - it('should return vehicle body type if vehicle is hgv', () => { - const techRecord = { - techRecord_vehicleType: 'hgv', - techRecord_bodyType_code: 'test code 2', - techRecord_bodyType_description: 'flat', - - } as V3TechRecordModel; - - const bodyType = getBodyType(techRecord); - expect(bodyType).toStrictEqual({ code: 'test code 2', description: 'flat' }); - }); - - it('should return vehicle body type if vehicle is trl', () => { - const techRecord = { - techRecord_vehicleType: 'trl', - techRecord_bodyType_code: 'test code 3', - techRecord_bodyType_description: 'flat', - - } as V3TechRecordModel; - - const bodyType = getBodyType(techRecord); - expect(bodyType).toStrictEqual({ code: 'test code 3', description: 'flat' }); - }); - - it('should not return vehicle body type if vehicle is not hgv, psv or trl', () => { - const techRecord = { - techRecord_vehicleType: 'car', - } as V3TechRecordModel; - - const bodyType = getBodyType(techRecord); - expect(bodyType).toBeNull(); - }); - }); - + let resolver: ResolveFn; + const actions$ = new ReplaySubject(); + let store: MockStore; + let techRecordService: TechnicalRecordService; + + const MockUserService = { + getUserName$: jest.fn().mockReturnValue(new Observable()), + get user$() { + return of('foo'); + }, + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule, RouterTestingModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + provideMockActions(() => actions$), + TechnicalRecordService, + { provide: UserService, useValue: MockUserService }, + ], + }); + resolver = (...resolverParameters) => + TestBed.runInInjectionContext(() => contingencyTestResolver(...resolverParameters)); + store = TestBed.inject(MockStore); + techRecordService = TestBed.inject(TechnicalRecordService); + }); + + it('should be created', () => { + expect(resolver).toBeTruthy(); + }); + + it('should return true and dispatch the initial contingency test action', async () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + jest + .spyOn(techRecordService, 'techRecord$', 'get') + .mockReturnValue(of(mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>)); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + const resolveResult = await firstValueFrom(result); + + expect(resolveResult).toBe(true); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith( + expect.objectContaining({ type: initialContingencyTest.type, testResult: expect.anything() }) + ); + }); + + it('should return false if there is an error', async () => { + jest + .spyOn(techRecordService, 'techRecord$', 'get') + .mockReturnValue(of(mockVehicleTechnicalRecord('psv') as TechRecordType<'psv'>)); + jest.spyOn(MockUserService, 'user$', 'get').mockImplementationOnce(() => throwError(() => new Error('foo'))); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + const resolveResult = await firstValueFrom(result); + expect(resolveResult).toBe(false); + }); + + describe('getBodyMake', () => { + it('should return vehicle make if vehicle is psv', () => { + const techRecord = { + techRecord_vehicleType: 'psv', + techRecord_bodyMake: 'test make 1', + } as V3TechRecordModel; + + const make = getBodyMake(techRecord); + expect(make).toBe('test make 1'); + }); + + it('should return vehicle make if vehicle is hgv', () => { + const techRecord = { + techRecord_vehicleType: 'hgv', + techRecord_make: 'test make 2', + } as V3TechRecordModel; + + const make = getBodyMake(techRecord); + expect(make).toBe('test make 2'); + }); + + it('should return vehicle make if vehicle is trl', () => { + const techRecord = { + techRecord_vehicleType: 'trl', + techRecord_make: 'test make 3', + } as V3TechRecordModel; + + const make = getBodyMake(techRecord); + expect(make).toBe('test make 3'); + }); + + it('should not return vehicle make if vehicle is not hgv, psv or trl', () => { + const techRecord = { + techRecord_vehicleType: 'car', + } as V3TechRecordModel; + + const make = getBodyMake(techRecord); + expect(make).toBeNull(); + }); + }); + + describe('getBodyModel', () => { + it('should return vehicle model if vehicle is psv', () => { + const techRecord = { + techRecord_vehicleType: 'psv', + techRecord_bodyModel: 'test model 1', + } as V3TechRecordModel; + + const model = getBodyModel(techRecord); + expect(model).toBe('test model 1'); + }); + + it('should return vehicle model if vehicle is hgv', () => { + const techRecord = { + techRecord_vehicleType: 'hgv', + techRecord_model: 'test model 2', + } as V3TechRecordModel; + + const model = getBodyModel(techRecord); + expect(model).toBe('test model 2'); + }); + + it('should return vehicle model if vehicle is trl', () => { + const techRecord = { + techRecord_vehicleType: 'trl', + techRecord_model: 'test model 3', + } as V3TechRecordModel; + + const model = getBodyModel(techRecord); + expect(model).toBe('test model 3'); + }); + + it('should not return vehicle model if vehicle is not hgv, psv or trl', () => { + const techRecord = { + techRecord_vehicleType: 'car', + } as V3TechRecordModel; + + const model = getBodyModel(techRecord); + expect(model).toBeNull(); + }); + }); + + describe('getBodyType', () => { + it('should return vehicle body type if vehicle is psv', () => { + const techRecord = { + techRecord_vehicleType: 'psv', + techRecord_bodyType_code: 'test code 1', + techRecord_bodyType_description: 'flat', + } as V3TechRecordModel; + + const bodyType = getBodyType(techRecord); + expect(bodyType).toStrictEqual({ code: 'test code 1', description: 'flat' }); + }); + + it('should return vehicle body type if vehicle is hgv', () => { + const techRecord = { + techRecord_vehicleType: 'hgv', + techRecord_bodyType_code: 'test code 2', + techRecord_bodyType_description: 'flat', + } as V3TechRecordModel; + + const bodyType = getBodyType(techRecord); + expect(bodyType).toStrictEqual({ code: 'test code 2', description: 'flat' }); + }); + + it('should return vehicle body type if vehicle is trl', () => { + const techRecord = { + techRecord_vehicleType: 'trl', + techRecord_bodyType_code: 'test code 3', + techRecord_bodyType_description: 'flat', + } as V3TechRecordModel; + + const bodyType = getBodyType(techRecord); + expect(bodyType).toStrictEqual({ code: 'test code 3', description: 'flat' }); + }); + + it('should not return vehicle body type if vehicle is not hgv, psv or trl', () => { + const techRecord = { + techRecord_vehicleType: 'car', + } as V3TechRecordModel; + + const bodyType = getBodyType(techRecord); + expect(bodyType).toBeNull(); + }); + }); }); diff --git a/src/app/resolvers/contingency-test/contingency-test.resolver.ts b/src/app/resolvers/contingency-test/contingency-test.resolver.ts index 57587d0de6..da721920ae 100644 --- a/src/app/resolvers/contingency-test/contingency-test.resolver.ts +++ b/src/app/resolvers/contingency-test/contingency-test.resolver.ts @@ -12,126 +12,131 @@ import { UserService } from '@services/user-service/user-service'; import { State } from '@store/.'; import { selectTechRecord } from '@store/technical-records'; import { initialContingencyTest } from '@store/test-records'; -import { - catchError, map, of, switchMap, take, tap, withLatestFrom, -} from 'rxjs'; +import { catchError, map, of, switchMap, take, tap, withLatestFrom } from 'rxjs'; import { v4 as uuidv4 } from 'uuid'; export const contingencyTestResolver: ResolveFn = () => { - const store: Store = inject(Store); - const techRecordService: TechnicalRecordService = inject(TechnicalRecordService); - const userService: UserService = inject(UserService); - return techRecordService.techRecord$.pipe( - switchMap((techRecord) => { - const { vin, systemNumber } = techRecord as TechRecordType<'get'>; - const vrm = techRecord?.techRecord_vehicleType !== 'trl' ? techRecord?.primaryVrm : undefined; - const trailerId = techRecord?.techRecord_vehicleType === 'trl' ? techRecord.trailerId : undefined; - return store.select(selectTechRecord).pipe( - withLatestFrom(userService.user$), - map(([viewableTechRecord, user]) => { - const now = new Date(); - return { - vin, - vrm, - trailerId, - systemNumber, - vehicleType: viewableTechRecord?.techRecord_vehicleType, - statusCode: viewableTechRecord?.techRecord_statusCode, - testResultId: uuidv4(), - euVehicleCategory: (viewableTechRecord as TechRecordType<'get'>)?.techRecord_euVehicleCategory ?? null, - vehicleSize: viewableTechRecord?.techRecord_vehicleType === 'psv' ? viewableTechRecord?.techRecord_vehicleSize : undefined, - vehicleConfiguration: (viewableTechRecord as TechRecordType<'get'>)?.techRecord_vehicleConfiguration ?? null, - vehicleClass: - (viewableTechRecord?.techRecord_vehicleType === 'psv' - || viewableTechRecord?.techRecord_vehicleType === 'trl' - || viewableTechRecord?.techRecord_vehicleType === 'hgv' - || viewableTechRecord?.techRecord_vehicleType === 'motorcycle') - && 'techRecord_vehicleClass_code' in viewableTechRecord - ? { - code: viewableTechRecord?.techRecord_vehicleClass_code, - description: viewableTechRecord?.techRecord_vehicleClass_description, - } - : null, - vehicleSubclass: - viewableTechRecord && 'techRecord_vehicleSubclass' in viewableTechRecord ? viewableTechRecord.techRecord_vehicleSubclass : null, - noOfAxles: viewableTechRecord?.techRecord_noOfAxles ?? 0, - numberOfWheelsDriven: - viewableTechRecord && 'techRecord_numberOfWheelsDriven' in viewableTechRecord - ? viewableTechRecord.techRecord_numberOfWheelsDriven - : null, - testStatus: 'submitted', - regnDate: viewableTechRecord?.techRecord_regnDate, - numberOfSeats: - ((viewableTechRecord as VehicleType<'psv'>)?.techRecord_seatsLowerDeck ?? 0) - + ((viewableTechRecord as VehicleType<'psv'>)?.techRecord_seatsUpperDeck ?? 0), - reasonForCancellation: '', - createdAt: now.toISOString(), - lastUpdatedAt: now.toISOString(), - firstUseDate: viewableTechRecord?.techRecord_vehicleType === 'trl' ? viewableTechRecord?.techRecord_firstUseDate : null, - createdByName: user.name, - createdById: user.oid, - lastUpdatedByName: user.name, - lastUpdatedById: user.oid, - typeOfTest: TypeOfTest.CONTINGENCY, - source: 'vtm', - make: getBodyMake(viewableTechRecord), - model: getBodyModel(viewableTechRecord), - bodyType: getBodyType(viewableTechRecord), - testTypes: [ - { - testResult: 'pass', - prohibitionIssued: null, - additionalCommentsForAbandon: null, - } as TestType, - ], - } as Partial; - }), - ); - }), - tap((testResult) => { - store.dispatch(initialContingencyTest({ testResult })); - }), - take(1), - map(() => { - return true; - }), - catchError(() => { - return of(false); - }), - ); + const store: Store = inject(Store); + const techRecordService: TechnicalRecordService = inject(TechnicalRecordService); + const userService: UserService = inject(UserService); + return techRecordService.techRecord$.pipe( + switchMap((techRecord) => { + const { vin, systemNumber } = techRecord as TechRecordType<'get'>; + const vrm = techRecord?.techRecord_vehicleType !== 'trl' ? techRecord?.primaryVrm : undefined; + const trailerId = techRecord?.techRecord_vehicleType === 'trl' ? techRecord.trailerId : undefined; + return store.select(selectTechRecord).pipe( + withLatestFrom(userService.user$), + map(([viewableTechRecord, user]) => { + const now = new Date(); + return { + vin, + vrm, + trailerId, + systemNumber, + vehicleType: viewableTechRecord?.techRecord_vehicleType, + statusCode: viewableTechRecord?.techRecord_statusCode, + testResultId: uuidv4(), + euVehicleCategory: (viewableTechRecord as TechRecordType<'get'>)?.techRecord_euVehicleCategory ?? null, + vehicleSize: + viewableTechRecord?.techRecord_vehicleType === 'psv' + ? viewableTechRecord?.techRecord_vehicleSize + : undefined, + vehicleConfiguration: + (viewableTechRecord as TechRecordType<'get'>)?.techRecord_vehicleConfiguration ?? null, + vehicleClass: + (viewableTechRecord?.techRecord_vehicleType === 'psv' || + viewableTechRecord?.techRecord_vehicleType === 'trl' || + viewableTechRecord?.techRecord_vehicleType === 'hgv' || + viewableTechRecord?.techRecord_vehicleType === 'motorcycle') && + 'techRecord_vehicleClass_code' in viewableTechRecord + ? { + code: viewableTechRecord?.techRecord_vehicleClass_code, + description: viewableTechRecord?.techRecord_vehicleClass_description, + } + : null, + vehicleSubclass: + viewableTechRecord && 'techRecord_vehicleSubclass' in viewableTechRecord + ? viewableTechRecord.techRecord_vehicleSubclass + : null, + noOfAxles: viewableTechRecord?.techRecord_noOfAxles ?? 0, + numberOfWheelsDriven: + viewableTechRecord && 'techRecord_numberOfWheelsDriven' in viewableTechRecord + ? viewableTechRecord.techRecord_numberOfWheelsDriven + : null, + testStatus: 'submitted', + regnDate: viewableTechRecord?.techRecord_regnDate, + numberOfSeats: + ((viewableTechRecord as VehicleType<'psv'>)?.techRecord_seatsLowerDeck ?? 0) + + ((viewableTechRecord as VehicleType<'psv'>)?.techRecord_seatsUpperDeck ?? 0), + reasonForCancellation: '', + createdAt: now.toISOString(), + lastUpdatedAt: now.toISOString(), + firstUseDate: + viewableTechRecord?.techRecord_vehicleType === 'trl' ? viewableTechRecord?.techRecord_firstUseDate : null, + createdByName: user.name, + createdById: user.oid, + lastUpdatedByName: user.name, + lastUpdatedById: user.oid, + typeOfTest: TypeOfTest.CONTINGENCY, + source: 'vtm', + make: getBodyMake(viewableTechRecord), + model: getBodyModel(viewableTechRecord), + bodyType: getBodyType(viewableTechRecord), + testTypes: [ + { + testResult: 'pass', + prohibitionIssued: null, + additionalCommentsForAbandon: null, + } as TestType, + ], + } as Partial; + }) + ); + }), + tap((testResult) => { + store.dispatch(initialContingencyTest({ testResult })); + }), + take(1), + map(() => { + return true; + }), + catchError(() => { + return of(false); + }) + ); }; export function getBodyMake(techRecord: V3TechRecordModel | undefined) { - if (techRecord?.techRecord_vehicleType === 'psv') { - return techRecord.techRecord_bodyMake; - } + if (techRecord?.techRecord_vehicleType === 'psv') { + return techRecord.techRecord_bodyMake; + } - if (techRecord?.techRecord_vehicleType === 'hgv' || techRecord?.techRecord_vehicleType === 'trl') { - return techRecord.techRecord_make; - } + if (techRecord?.techRecord_vehicleType === 'hgv' || techRecord?.techRecord_vehicleType === 'trl') { + return techRecord.techRecord_make; + } - return null; + return null; } export function getBodyModel(techRecord: V3TechRecordModel | undefined) { - if (techRecord?.techRecord_vehicleType === 'psv') { - return techRecord.techRecord_bodyModel ? techRecord.techRecord_bodyModel : null; - } + if (techRecord?.techRecord_vehicleType === 'psv') { + return techRecord.techRecord_bodyModel ? techRecord.techRecord_bodyModel : null; + } - if (techRecord?.techRecord_vehicleType === 'hgv' || techRecord?.techRecord_vehicleType === 'trl') { - return techRecord.techRecord_model; - } + if (techRecord?.techRecord_vehicleType === 'hgv' || techRecord?.techRecord_vehicleType === 'trl') { + return techRecord.techRecord_model; + } - return null; + return null; } export function getBodyType(techRecord: V3TechRecordModel | undefined) { - const vehicleType = techRecord?.techRecord_vehicleType; + const vehicleType = techRecord?.techRecord_vehicleType; - if (!vehicleType || (vehicleType !== 'hgv' && vehicleType !== 'psv' && vehicleType !== 'trl')) return null; + if (!vehicleType || (vehicleType !== 'hgv' && vehicleType !== 'psv' && vehicleType !== 'trl')) return null; - return { - code: techRecord.techRecord_bodyType_code, - description: techRecord.techRecord_bodyType_description, - }; + return { + code: techRecord.techRecord_bodyType_code, + description: techRecord.techRecord_bodyType_description, + }; } diff --git a/src/app/resolvers/defects-taxonomy/defects-taxonomy.resolver.spec.ts b/src/app/resolvers/defects-taxonomy/defects-taxonomy.resolver.spec.ts index 82efbdcb20..62156ad95a 100644 --- a/src/app/resolvers/defects-taxonomy/defects-taxonomy.resolver.spec.ts +++ b/src/app/resolvers/defects-taxonomy/defects-taxonomy.resolver.spec.ts @@ -1,68 +1,68 @@ import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot } from '@angular/router'; import { provideMockActions } from '@ngrx/effects/testing'; import { Action } from '@ngrx/store'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; -import { initialAppState, State } from '@store/.'; +import { State, initialAppState } from '@store/.'; import { fetchDefects, fetchDefectsFailed, fetchDefectsSuccess } from '@store/defects'; import { Observable } from 'rxjs'; import { TestScheduler } from 'rxjs/testing'; -import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot } from '@angular/router'; import { defectsTaxonomyResolver } from './defects-taxonomy.resolver'; describe('DefectsTaxonomyResolver', () => { - let resolver: ResolveFn; - let actions$ = new Observable(); - let testScheduler: TestScheduler; - let store: MockStore; + let resolver: ResolveFn; + let actions$ = new Observable(); + let testScheduler: TestScheduler; + let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideMockStore({ initialState: initialAppState }), provideMockActions(() => actions$)], - }); - resolver = (...resolverParameters) => - TestBed.runInInjectionContext(() => defectsTaxonomyResolver(...resolverParameters)); - store = TestBed.inject(MockStore); - }); + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore({ initialState: initialAppState }), provideMockActions(() => actions$)], + }); + resolver = (...resolverParameters) => + TestBed.runInInjectionContext(() => defectsTaxonomyResolver(...resolverParameters)); + store = TestBed.inject(MockStore); + }); - beforeEach(() => { - testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - }); + beforeEach(() => { + testScheduler = new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); + }); + }); - it('should be created', () => { - expect(resolver).toBeTruthy(); - }); + it('should be created', () => { + expect(resolver).toBeTruthy(); + }); - describe('fetch test types', () => { - it('should resolve to true when all actions are success type', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - testScheduler.run(({ hot, expectObservable }) => { - actions$ = hot('-a', { a: fetchDefectsSuccess }); - expectObservable(result).toBe('-(b|)', { - b: true, - }); - }); + describe('fetch test types', () => { + it('should resolve to true when all actions are success type', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + testScheduler.run(({ hot, expectObservable }) => { + actions$ = hot('-a', { a: fetchDefectsSuccess }); + expectObservable(result).toBe('-(b|)', { + b: true, + }); + }); - expect(dispatchSpy).toHaveBeenCalledWith(fetchDefects()); - }); + expect(dispatchSpy).toHaveBeenCalledWith(fetchDefects()); + }); - it('should resolve to false when one or more actions are of failure type', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - testScheduler.run(({ hot, expectObservable }) => { - actions$ = hot('-a', { a: fetchDefectsFailed }); - expectObservable(result).toBe('-(b|)', { - b: false, - }); - }); + it('should resolve to false when one or more actions are of failure type', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + testScheduler.run(({ hot, expectObservable }) => { + actions$ = hot('-a', { a: fetchDefectsFailed }); + expectObservable(result).toBe('-(b|)', { + b: false, + }); + }); - expect(dispatchSpy).toHaveBeenCalledWith(fetchDefects()); - }); - }); + expect(dispatchSpy).toHaveBeenCalledWith(fetchDefects()); + }); + }); }); diff --git a/src/app/resolvers/defects-taxonomy/defects-taxonomy.resolver.ts b/src/app/resolvers/defects-taxonomy/defects-taxonomy.resolver.ts index 54583e71be..b774614d82 100644 --- a/src/app/resolvers/defects-taxonomy/defects-taxonomy.resolver.ts +++ b/src/app/resolvers/defects-taxonomy/defects-taxonomy.resolver.ts @@ -2,22 +2,17 @@ import { inject } from '@angular/core'; import { ResolveFn } from '@angular/router'; import { Actions, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; -import { - DefectsState, - fetchDefects, - fetchDefectsFailed, - fetchDefectsSuccess, -} from '@store/defects'; +import { DefectsState, fetchDefects, fetchDefectsFailed, fetchDefectsSuccess } from '@store/defects'; import { map, take } from 'rxjs'; export const defectsTaxonomyResolver: ResolveFn = () => { - const store: Store = inject(Store); - const action$: Actions = inject(Actions); - store.dispatch(fetchDefects()); + const store: Store = inject(Store); + const action$: Actions = inject(Actions); + store.dispatch(fetchDefects()); - return action$.pipe( - ofType(fetchDefectsSuccess, fetchDefectsFailed), - take(1), - map((action) => action.type === fetchDefectsSuccess.type), - ); + return action$.pipe( + ofType(fetchDefectsSuccess, fetchDefectsFailed), + take(1), + map((action) => action.type === fetchDefectsSuccess.type) + ); }; diff --git a/src/app/resolvers/required-standards/required-standards.resolver.spec.ts b/src/app/resolvers/required-standards/required-standards.resolver.spec.ts index 105f0117bf..4f807c3f08 100644 --- a/src/app/resolvers/required-standards/required-standards.resolver.spec.ts +++ b/src/app/resolvers/required-standards/required-standards.resolver.spec.ts @@ -6,9 +6,9 @@ import { Action } from '@ngrx/store'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { State, initialAppState } from '@store/index'; import { - getRequiredStandards, - getRequiredStandardsFailure, - getRequiredStandardsSuccess, + getRequiredStandards, + getRequiredStandardsFailure, + getRequiredStandardsSuccess, } from '@store/required-standards/actions/required-standards.actions'; import { testResultInEdit } from '@store/test-records/selectors/test-records.selectors'; import { Observable } from 'rxjs'; @@ -16,61 +16,61 @@ import { TestScheduler } from 'rxjs/testing'; import { requiredStandardsResolver } from './required-standards.resolver'; describe('RequiredStandardsResolver', () => { - let resolver: ResolveFn; - let actions$ = new Observable(); - let testScheduler: TestScheduler; - let store: MockStore; + let resolver: ResolveFn; + let actions$ = new Observable(); + let testScheduler: TestScheduler; + let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideMockStore({ initialState: initialAppState }), provideMockActions(() => actions$)], - }); - resolver = (...resolverParameters) => - TestBed.runInInjectionContext(() => requiredStandardsResolver(...resolverParameters)); - store = TestBed.inject(MockStore); - }); + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore({ initialState: initialAppState }), provideMockActions(() => actions$)], + }); + resolver = (...resolverParameters) => + TestBed.runInInjectionContext(() => requiredStandardsResolver(...resolverParameters)); + store = TestBed.inject(MockStore); + }); - beforeEach(() => { - testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - }); + beforeEach(() => { + testScheduler = new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); + }); + }); - it('should be created', () => { - expect(resolver).toBeTruthy(); - }); + it('should be created', () => { + expect(resolver).toBeTruthy(); + }); - describe('get required standards', () => { - it('should resolve to true when all actions are success type', () => { - store.overrideSelector(testResultInEdit, { euVehicleCategory: 'm1' } as unknown as TestResultModel); - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - testScheduler.run(({ hot, expectObservable }) => { - actions$ = hot('-a', { a: getRequiredStandardsSuccess }); - expectObservable(result).toBe('-(b|)', { - b: true, - }); - }); + describe('get required standards', () => { + it('should resolve to true when all actions are success type', () => { + store.overrideSelector(testResultInEdit, { euVehicleCategory: 'm1' } as unknown as TestResultModel); + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + testScheduler.run(({ hot, expectObservable }) => { + actions$ = hot('-a', { a: getRequiredStandardsSuccess }); + expectObservable(result).toBe('-(b|)', { + b: true, + }); + }); - expect(dispatchSpy).toHaveBeenCalledWith(getRequiredStandards({ euVehicleCategory: 'm1' })); - }); + expect(dispatchSpy).toHaveBeenCalledWith(getRequiredStandards({ euVehicleCategory: 'm1' })); + }); - it('should resolve to false when one or more actions are of failure type', () => { - store.overrideSelector(testResultInEdit, { euVehicleCategory: 'm1' } as unknown as TestResultModel); - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - testScheduler.run(({ hot, expectObservable }) => { - actions$ = hot('-a', { a: getRequiredStandardsFailure }); - expectObservable(result).toBe('-(b|)', { - b: false, - }); - }); + it('should resolve to false when one or more actions are of failure type', () => { + store.overrideSelector(testResultInEdit, { euVehicleCategory: 'm1' } as unknown as TestResultModel); + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + testScheduler.run(({ hot, expectObservable }) => { + actions$ = hot('-a', { a: getRequiredStandardsFailure }); + expectObservable(result).toBe('-(b|)', { + b: false, + }); + }); - expect(dispatchSpy).toHaveBeenCalledWith(getRequiredStandards({ euVehicleCategory: 'm1' })); - }); - }); + expect(dispatchSpy).toHaveBeenCalledWith(getRequiredStandards({ euVehicleCategory: 'm1' })); + }); + }); }); diff --git a/src/app/resolvers/required-standards/required-standards.resolver.ts b/src/app/resolvers/required-standards/required-standards.resolver.ts index 393316a573..8ea0d5a753 100644 --- a/src/app/resolvers/required-standards/required-standards.resolver.ts +++ b/src/app/resolvers/required-standards/required-standards.resolver.ts @@ -3,24 +3,24 @@ import { ResolveFn } from '@angular/router'; import { Actions, ofType } from '@ngrx/effects'; import { Store, select } from '@ngrx/store'; import { - getRequiredStandards, - getRequiredStandardsFailure, - getRequiredStandardsSuccess, + getRequiredStandards, + getRequiredStandardsFailure, + getRequiredStandardsSuccess, } from '@store/required-standards/actions/required-standards.actions'; import { RequiredStandardState } from '@store/required-standards/reducers/required-standards.reducer'; import { testResultInEdit } from '@store/test-records/selectors/test-records.selectors'; import { map, take } from 'rxjs'; export const requiredStandardsResolver: ResolveFn = () => { - const store: Store = inject(Store); - const action$: Actions = inject(Actions); - store.pipe(select(testResultInEdit), take(1)).subscribe((editingTestResult) => { - store.dispatch(getRequiredStandards({ euVehicleCategory: editingTestResult?.euVehicleCategory ?? '' })); - }); + const store: Store = inject(Store); + const action$: Actions = inject(Actions); + store.pipe(select(testResultInEdit), take(1)).subscribe((editingTestResult) => { + store.dispatch(getRequiredStandards({ euVehicleCategory: editingTestResult?.euVehicleCategory ?? '' })); + }); - return action$.pipe( - ofType(getRequiredStandardsSuccess, getRequiredStandardsFailure), - take(1), - map((action) => action.type === getRequiredStandardsSuccess.type), - ); + return action$.pipe( + ofType(getRequiredStandardsSuccess, getRequiredStandardsFailure), + take(1), + map((action) => action.type === getRequiredStandardsSuccess.type) + ); }; diff --git a/src/app/resolvers/tech-record-clean/tech-record-clean.resolver.spec.ts b/src/app/resolvers/tech-record-clean/tech-record-clean.resolver.spec.ts index 6a8a02e543..a7d11b552e 100644 --- a/src/app/resolvers/tech-record-clean/tech-record-clean.resolver.spec.ts +++ b/src/app/resolvers/tech-record-clean/tech-record-clean.resolver.spec.ts @@ -10,99 +10,111 @@ import { Observable, firstValueFrom, of } from 'rxjs'; import { techRecordCleanResolver } from './tech-record-clean.resolver'; describe('techRecordCleanResolver', () => { - const executeResolver: ResolveFn> = (...resolverParameters) => - TestBed.runInInjectionContext(() => techRecordCleanResolver(...resolverParameters)); + const executeResolver: ResolveFn> = (...resolverParameters) => + TestBed.runInInjectionContext(() => techRecordCleanResolver(...resolverParameters)); - const actions$ = new Observable(); - const mockActivatedRouteSnapshot = jest.fn; - let store: MockStore; - let activatedRouteSnapshot: ActivatedRouteSnapshot; + const actions$ = new Observable(); + const mockActivatedRouteSnapshot = jest.fn; + let store: MockStore; + let activatedRouteSnapshot: ActivatedRouteSnapshot; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [RouterTestingModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - provideMockActions(() => actions$), - { provide: ActivatedRouteSnapshot, useValue: mockActivatedRouteSnapshot }, - ], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + provideMockActions(() => actions$), + { provide: ActivatedRouteSnapshot, useValue: mockActivatedRouteSnapshot }, + ], + }); - store = TestBed.inject(MockStore); - activatedRouteSnapshot = TestBed.inject(ActivatedRouteSnapshot); - activatedRouteSnapshot.data = { - isEditing: true, - }; - }); + store = TestBed.inject(MockStore); + activatedRouteSnapshot = TestBed.inject(ActivatedRouteSnapshot); + activatedRouteSnapshot.data = { + isEditing: true, + }; + }); - it('should be created', () => { - expect(executeResolver).toBeTruthy(); - }); + it('should be created', () => { + expect(executeResolver).toBeTruthy(); + }); - describe('fetch tech record', () => { - it('should update the editing tech record when approval type = Small series and approval number is in NKS format', async () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - jest.spyOn(store, 'select').mockReturnValue(of({ - techRecord_vehicleType: 'hgv', - techRecord_approvalType: 'Small series' as ApprovalType, - techRecord_approvalTypeNumber: '811*NKS*666666', - })); - const result = executeResolver(activatedRouteSnapshot, {} as RouterStateSnapshot) as Observable; - const resolveResult = await firstValueFrom(result); + describe('fetch tech record', () => { + it('should update the editing tech record when approval type = Small series and approval number is in NKS format', async () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + jest.spyOn(store, 'select').mockReturnValue( + of({ + techRecord_vehicleType: 'hgv', + techRecord_approvalType: 'Small series' as ApprovalType, + techRecord_approvalTypeNumber: '811*NKS*666666', + }) + ); + const result = executeResolver(activatedRouteSnapshot, {} as RouterStateSnapshot) as Observable; + const resolveResult = await firstValueFrom(result); - expect(resolveResult).toBe(true); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(expect.objectContaining({ - vehicleTechRecord: { - techRecord_approvalType: ApprovalType.SMALL_SERIES_NKS, - techRecord_approvalTypeNumber: '811*NKS*666666', - techRecord_vehicleType: 'hgv', - }, - })); - }); + expect(resolveResult).toBe(true); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith( + expect.objectContaining({ + vehicleTechRecord: { + techRecord_approvalType: ApprovalType.SMALL_SERIES_NKS, + techRecord_approvalTypeNumber: '811*NKS*666666', + techRecord_vehicleType: 'hgv', + }, + }) + ); + }); - it('should update the editing tech record when approval type = Small series and approval number is in NKSXX format', async () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - jest.spyOn(store, 'select').mockReturnValue(of({ - techRecord_vehicleType: 'hgv', - techRecord_approvalType: 'Small series' as ApprovalType, - techRecord_approvalTypeNumber: '811*NKSXX/1234*666666', - })); - const result = executeResolver(activatedRouteSnapshot, {} as RouterStateSnapshot) as Observable; - const resolveResult = await firstValueFrom(result); + it('should update the editing tech record when approval type = Small series and approval number is in NKSXX format', async () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + jest.spyOn(store, 'select').mockReturnValue( + of({ + techRecord_vehicleType: 'hgv', + techRecord_approvalType: 'Small series' as ApprovalType, + techRecord_approvalTypeNumber: '811*NKSXX/1234*666666', + }) + ); + const result = executeResolver(activatedRouteSnapshot, {} as RouterStateSnapshot) as Observable; + const resolveResult = await firstValueFrom(result); - expect(resolveResult).toBe(true); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(expect.objectContaining({ - vehicleTechRecord: { - techRecord_approvalType: ApprovalType.SMALL_SERIES_NKSXX, - techRecord_approvalTypeNumber: '811*NKSXX/1234*666666', - techRecord_vehicleType: 'hgv', - }, - })); - }); + expect(resolveResult).toBe(true); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith( + expect.objectContaining({ + vehicleTechRecord: { + techRecord_approvalType: ApprovalType.SMALL_SERIES_NKSXX, + techRecord_approvalTypeNumber: '811*NKSXX/1234*666666', + techRecord_vehicleType: 'hgv', + }, + }) + ); + }); - it('should not update the editing tech record when the approval type is Small series, but the approval number is invalid', async () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - jest.spyOn(store, 'select').mockReturnValue(of({ - techRecord_vehicleType: 'hgv', - techRecord_approvalType: 'Small series' as ApprovalType, - techRecord_approvalTypeNumber: 'INVALID NUMBER', - })); - const result = executeResolver(activatedRouteSnapshot, {} as RouterStateSnapshot) as Observable; - const resolveResult = await firstValueFrom(result); + it('should not update the editing tech record when the approval type is Small series, but the approval number is invalid', async () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + jest.spyOn(store, 'select').mockReturnValue( + of({ + techRecord_vehicleType: 'hgv', + techRecord_approvalType: 'Small series' as ApprovalType, + techRecord_approvalTypeNumber: 'INVALID NUMBER', + }) + ); + const result = executeResolver(activatedRouteSnapshot, {} as RouterStateSnapshot) as Observable; + const resolveResult = await firstValueFrom(result); - expect(resolveResult).toBe(true); - expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(resolveResult).toBe(true); + expect(dispatchSpy).toHaveBeenCalledTimes(1); - // This bad data gets nulled by the tech-record-validate resolver - expect(dispatchSpy).toHaveBeenCalledWith(expect.objectContaining({ - vehicleTechRecord: { - techRecord_approvalType: 'Small series' as ApprovalType, - techRecord_approvalTypeNumber: 'INVALID NUMBER', - techRecord_vehicleType: 'hgv', - }, - })); - }); - }); + // This bad data gets nulled by the tech-record-validate resolver + expect(dispatchSpy).toHaveBeenCalledWith( + expect.objectContaining({ + vehicleTechRecord: { + techRecord_approvalType: 'Small series' as ApprovalType, + techRecord_approvalTypeNumber: 'INVALID NUMBER', + techRecord_vehicleType: 'hgv', + }, + }) + ); + }); + }); }); diff --git a/src/app/resolvers/tech-record-clean/tech-record-clean.resolver.ts b/src/app/resolvers/tech-record-clean/tech-record-clean.resolver.ts index a733a0cf2f..6232501f60 100644 --- a/src/app/resolvers/tech-record-clean/tech-record-clean.resolver.ts +++ b/src/app/resolvers/tech-record-clean/tech-record-clean.resolver.ts @@ -6,43 +6,41 @@ import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { Store } from '@ngrx/store'; import { State } from '@store/index'; import { selectTechRecord, updateEditingTechRecord } from '@store/technical-records'; -import { - Observable, map, take, tap, -} from 'rxjs'; +import { Observable, map, take, tap } from 'rxjs'; export const techRecordCleanResolver: ResolveFn> = (route) => { - const store = inject(Store); + const store = inject(Store); - return store.select(selectTechRecord).pipe( - take(1), - map((vehicleTechRecord) => vehicleTechRecord as TechRecordType<'put'>), - map((vehicleTechRecord) => cleanseApprovalType(vehicleTechRecord, route)), - tap((vehicleTechRecord) => store.dispatch(updateEditingTechRecord({ vehicleTechRecord }))), - map(() => true), - ); + return store.select(selectTechRecord).pipe( + take(1), + map((vehicleTechRecord) => vehicleTechRecord as TechRecordType<'put'>), + map((vehicleTechRecord) => cleanseApprovalType(vehicleTechRecord, route)), + tap((vehicleTechRecord) => store.dispatch(updateEditingTechRecord({ vehicleTechRecord }))), + map(() => true) + ); }; export const cleanseApprovalType = (record: TechRecordType<'put'>, route: ActivatedRouteSnapshot) => { - if (!route.data['isEditing']) return record; + if (!route.data['isEditing']) return record; - const type = record.techRecord_vehicleType; - if (type === VehicleTypes.HGV || type === VehicleTypes.PSV || type === VehicleTypes.TRL) { - const approvalType = record.techRecord_approvalType; - const approvalNumber = record.techRecord_approvalTypeNumber; - if (approvalType?.toString() === 'Small series' && approvalNumber) { - // infer new approval type based on format of approval type number - const patterns = new Map([ - [ApprovalType.SMALL_SERIES_NKSXX, /^(.?)11\*NKS(.{0,2})\/(.{0,4})\*(.{0,6})$/i], - [ApprovalType.SMALL_SERIES_NKS, /^(.?)11\*NKS\*(.{0,6})$/i], - ]); + const type = record.techRecord_vehicleType; + if (type === VehicleTypes.HGV || type === VehicleTypes.PSV || type === VehicleTypes.TRL) { + const approvalType = record.techRecord_approvalType; + const approvalNumber = record.techRecord_approvalTypeNumber; + if (approvalType?.toString() === 'Small series' && approvalNumber) { + // infer new approval type based on format of approval type number + const patterns = new Map([ + [ApprovalType.SMALL_SERIES_NKSXX, /^(.?)11\*NKS(.{0,2})\/(.{0,4})\*(.{0,6})$/i], + [ApprovalType.SMALL_SERIES_NKS, /^(.?)11\*NKS\*(.{0,6})$/i], + ]); - patterns.forEach((value, key) => { - if (value.test(approvalNumber)) { - record.techRecord_approvalType = key; - } - }); - } - } + patterns.forEach((value, key) => { + if (value.test(approvalNumber)) { + record.techRecord_approvalType = key; + } + }); + } + } - return record; + return record; }; diff --git a/src/app/resolvers/tech-record-data/tech-record-data.resolver.spec.ts b/src/app/resolvers/tech-record-data/tech-record-data.resolver.spec.ts index 7523c09da8..798a6ad0ad 100644 --- a/src/app/resolvers/tech-record-data/tech-record-data.resolver.spec.ts +++ b/src/app/resolvers/tech-record-data/tech-record-data.resolver.spec.ts @@ -6,34 +6,34 @@ import { ReferenceDataService } from '@services/reference-data/reference-data.se import { techRecordDataResolver } from './tech-record-data.resolver'; describe('techRecordDataResolver', () => { - let referenceDataService: ReferenceDataService; - - const routeSnapshot = {} as ActivatedRouteSnapshot; - const routerStateSnapshot = {} as RouterStateSnapshot; - - const executeResolver: ResolveFn = (...resolverParameters) => - TestBed.runInInjectionContext(() => techRecordDataResolver(...resolverParameters)); - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [{ provide: ReferenceDataService, useValue: { loadReferenceData: jest.fn() } }], - }); - referenceDataService = TestBed.inject(ReferenceDataService); - }); - - it('should be created', () => { - expect(executeResolver).toBeTruthy(); - }); - - it('should attempt to load the tyres ref data', () => { - const spy = jest.spyOn(referenceDataService, 'loadReferenceData'); - void executeResolver(routeSnapshot, routerStateSnapshot); - expect(spy).toHaveBeenCalledWith(ReferenceDataResourceType.Tyres); - }); - - it('should attempt to load the tyres load index ref data', () => { - const spy = jest.spyOn(referenceDataService, 'loadReferenceData'); - void executeResolver(routeSnapshot, routerStateSnapshot); - expect(spy).toHaveBeenCalledWith(ReferenceDataResourceType.TyreLoadIndex); - }); + let referenceDataService: ReferenceDataService; + + const routeSnapshot = {} as ActivatedRouteSnapshot; + const routerStateSnapshot = {} as RouterStateSnapshot; + + const executeResolver: ResolveFn = (...resolverParameters) => + TestBed.runInInjectionContext(() => techRecordDataResolver(...resolverParameters)); + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [{ provide: ReferenceDataService, useValue: { loadReferenceData: jest.fn() } }], + }); + referenceDataService = TestBed.inject(ReferenceDataService); + }); + + it('should be created', () => { + expect(executeResolver).toBeTruthy(); + }); + + it('should attempt to load the tyres ref data', () => { + const spy = jest.spyOn(referenceDataService, 'loadReferenceData'); + void executeResolver(routeSnapshot, routerStateSnapshot); + expect(spy).toHaveBeenCalledWith(ReferenceDataResourceType.Tyres); + }); + + it('should attempt to load the tyres load index ref data', () => { + const spy = jest.spyOn(referenceDataService, 'loadReferenceData'); + void executeResolver(routeSnapshot, routerStateSnapshot); + expect(spy).toHaveBeenCalledWith(ReferenceDataResourceType.TyreLoadIndex); + }); }); diff --git a/src/app/resolvers/tech-record-data/tech-record-data.resolver.ts b/src/app/resolvers/tech-record-data/tech-record-data.resolver.ts index 81aef69d42..7cbd2c4991 100644 --- a/src/app/resolvers/tech-record-data/tech-record-data.resolver.ts +++ b/src/app/resolvers/tech-record-data/tech-record-data.resolver.ts @@ -4,9 +4,9 @@ import { ReferenceDataResourceType } from '@models/reference-data.model'; import { ReferenceDataService } from '@services/reference-data/reference-data.service'; export const techRecordDataResolver: ResolveFn = () => { - const referenceDataService = inject(ReferenceDataService); - referenceDataService.loadReferenceData(ReferenceDataResourceType.Tyres); - referenceDataService.loadReferenceData(ReferenceDataResourceType.TyreLoadIndex); + const referenceDataService = inject(ReferenceDataService); + referenceDataService.loadReferenceData(ReferenceDataResourceType.Tyres); + referenceDataService.loadReferenceData(ReferenceDataResourceType.TyreLoadIndex); - return true; + return true; }; diff --git a/src/app/resolvers/tech-record-validate/tech-record-validate.resolver.spec.ts b/src/app/resolvers/tech-record-validate/tech-record-validate.resolver.spec.ts index e78cf3604d..47a1b22a9c 100644 --- a/src/app/resolvers/tech-record-validate/tech-record-validate.resolver.spec.ts +++ b/src/app/resolvers/tech-record-validate/tech-record-validate.resolver.spec.ts @@ -1,11 +1,6 @@ import { TestBed } from '@angular/core/testing'; -import { - ActivatedRouteSnapshot, - ResolveFn, - Router, - RouterStateSnapshot, -} from '@angular/router'; +import { ActivatedRouteSnapshot, ResolveFn, Router, RouterStateSnapshot } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { provideMockActions } from '@ngrx/effects/testing'; import { Action } from '@ngrx/store'; @@ -15,153 +10,181 @@ import { Observable, firstValueFrom, of } from 'rxjs'; import { techRecordValidateResolver } from './tech-record-validate.resolver'; describe('TechRecordViewResolver', () => { - let resolver: ResolveFn; - const actions$ = new Observable(); - const mockSnapshot = jest.fn; - let store: MockStore; - let router: Router; + let resolver: ResolveFn; + const actions$ = new Observable(); + const mockSnapshot = jest.fn; + let store: MockStore; + let router: Router; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [RouterTestingModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - provideMockActions(() => actions$), - { provide: RouterStateSnapshot, useValue: mockSnapshot }, - ], - }); - resolver = (...resolverParameters) => - TestBed.runInInjectionContext(() => techRecordValidateResolver(...resolverParameters)); - store = TestBed.inject(MockStore); - router = TestBed.inject(Router); - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + provideMockActions(() => actions$), + { provide: RouterStateSnapshot, useValue: mockSnapshot }, + ], + }); + resolver = (...resolverParameters) => + TestBed.runInInjectionContext(() => techRecordValidateResolver(...resolverParameters)); + store = TestBed.inject(MockStore); + router = TestBed.inject(Router); + }); - it('should be created', () => { - expect(resolver).toBeTruthy(); - }); + it('should be created', () => { + expect(resolver).toBeTruthy(); + }); - describe('fetch tech record result', () => { - it('should dispatch a tech record with null if hgv vehicle configuration invalid', async () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - jest.spyOn(store, 'select').mockReturnValue(of({ - techRecord_vehicleType: 'hgv', - techRecord_vehicleConfiguration: 'semi-trailer', - techRecord_euVehicleCategory: 'o1', - })); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - const resolveResult = await firstValueFrom(result); + describe('fetch tech record result', () => { + it('should dispatch a tech record with null if hgv vehicle configuration invalid', async () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + jest.spyOn(store, 'select').mockReturnValue( + of({ + techRecord_vehicleType: 'hgv', + techRecord_vehicleConfiguration: 'semi-trailer', + techRecord_euVehicleCategory: 'o1', + }) + ); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + const resolveResult = await firstValueFrom(result); - expect(resolveResult).toBe(true); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(expect.objectContaining({ - vehicleTechRecord: { - techRecord_vehicleType: 'hgv', - techRecord_vehicleConfiguration: null, - techRecord_vehicleClass_description: 'heavy goods vehicle', - techRecord_euVehicleCategory: null, - }, - })); - }); - it('should dispatch a tech record with null if psv vehicle configuration invalid', async () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - jest.spyOn(store, 'select').mockReturnValue(of({ - techRecord_vehicleType: 'psv', - techRecord_vehicleConfiguration: 'semi-trailer', - techRecord_euVehicleCategory: 'o1', - })); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - const resolveResult = await firstValueFrom(result); + expect(resolveResult).toBe(true); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith( + expect.objectContaining({ + vehicleTechRecord: { + techRecord_vehicleType: 'hgv', + techRecord_vehicleConfiguration: null, + techRecord_vehicleClass_description: 'heavy goods vehicle', + techRecord_euVehicleCategory: null, + }, + }) + ); + }); + it('should dispatch a tech record with null if psv vehicle configuration invalid', async () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + jest.spyOn(store, 'select').mockReturnValue( + of({ + techRecord_vehicleType: 'psv', + techRecord_vehicleConfiguration: 'semi-trailer', + techRecord_euVehicleCategory: 'o1', + }) + ); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + const resolveResult = await firstValueFrom(result); - expect(resolveResult).toBe(true); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(expect.objectContaining({ - vehicleTechRecord: { - techRecord_vehicleType: 'psv', - techRecord_vehicleConfiguration: null, - techRecord_euVehicleCategory: null, - }, - })); - }); - it('should dispatch a tech record with null if psv vehicle class is invalid', async () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - jest.spyOn(store, 'select').mockReturnValue(of({ techRecord_vehicleType: 'psv', techRecord_vehicleClass_description: 'trailer' })); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - const resolveResult = await firstValueFrom(result); + expect(resolveResult).toBe(true); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith( + expect.objectContaining({ + vehicleTechRecord: { + techRecord_vehicleType: 'psv', + techRecord_vehicleConfiguration: null, + techRecord_euVehicleCategory: null, + }, + }) + ); + }); + it('should dispatch a tech record with null if psv vehicle class is invalid', async () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + jest + .spyOn(store, 'select') + .mockReturnValue(of({ techRecord_vehicleType: 'psv', techRecord_vehicleClass_description: 'trailer' })); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + const resolveResult = await firstValueFrom(result); - expect(resolveResult).toBe(true); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(expect.objectContaining({ - vehicleTechRecord: { techRecord_vehicleType: 'psv', techRecord_vehicleClass_description: null }, - })); - }); - it('should dispatch a tech record with null if trl vehicle configuration invalid', async () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - jest.spyOn(store, 'select').mockReturnValue(of({ - techRecord_vehicleType: 'trl', - techRecord_vehicleConfiguration: 'rigid', - })); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - const resolveResult = await firstValueFrom(result); + expect(resolveResult).toBe(true); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith( + expect.objectContaining({ + vehicleTechRecord: { techRecord_vehicleType: 'psv', techRecord_vehicleClass_description: null }, + }) + ); + }); + it('should dispatch a tech record with null if trl vehicle configuration invalid', async () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + jest.spyOn(store, 'select').mockReturnValue( + of({ + techRecord_vehicleType: 'trl', + techRecord_vehicleConfiguration: 'rigid', + }) + ); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + const resolveResult = await firstValueFrom(result); - expect(resolveResult).toBe(true); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(expect.objectContaining({ - vehicleTechRecord: { - techRecord_vehicleType: 'trl', - techRecord_vehicleConfiguration: null, - techRecord_vehicleClass_description: 'trailer', - }, - })); - }); - it('should not dispatch a tech record with trl vehicle configuration is valid', async () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - jest.spyOn(store, 'select').mockReturnValue(of({ - techRecord_vehicleType: 'trl', - techRecord_vehicleConfiguration: 'semi-trailer', - techRecord_vehicleClass_description: 'trailer', - techRecord_euVehicleCategory: 'o1', - })); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - const resolveResult = await firstValueFrom(result); + expect(resolveResult).toBe(true); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith( + expect.objectContaining({ + vehicleTechRecord: { + techRecord_vehicleType: 'trl', + techRecord_vehicleConfiguration: null, + techRecord_vehicleClass_description: 'trailer', + }, + }) + ); + }); + it('should not dispatch a tech record with trl vehicle configuration is valid', async () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + jest.spyOn(store, 'select').mockReturnValue( + of({ + techRecord_vehicleType: 'trl', + techRecord_vehicleConfiguration: 'semi-trailer', + techRecord_vehicleClass_description: 'trailer', + techRecord_euVehicleCategory: 'o1', + }) + ); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + const resolveResult = await firstValueFrom(result); - expect(resolveResult).toBe(true); - expect(dispatchSpy).toHaveBeenCalledTimes(0); - }); - it('should dispatch a tech record with hgv if hgv vehicle class is invalid', async () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - jest.spyOn(store, 'select').mockReturnValue(of({ techRecord_vehicleType: 'hgv', techRecord_vehicleClass_description: 'trailer' })); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - const resolveResult = await firstValueFrom(result); + expect(resolveResult).toBe(true); + expect(dispatchSpy).toHaveBeenCalledTimes(0); + }); + it('should dispatch a tech record with hgv if hgv vehicle class is invalid', async () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + jest + .spyOn(store, 'select') + .mockReturnValue(of({ techRecord_vehicleType: 'hgv', techRecord_vehicleClass_description: 'trailer' })); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + const resolveResult = await firstValueFrom(result); - expect(resolveResult).toBe(true); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(expect.objectContaining({ - vehicleTechRecord: { techRecord_vehicleType: 'hgv', techRecord_vehicleClass_description: 'heavy goods vehicle' }, - })); - }); - it('should navigate if there is no tech record', async () => { - jest.spyOn(store, 'select').mockReturnValue(of(undefined)); - const routerSpy = jest.spyOn(router, 'navigate').mockImplementation(); - const result = TestBed.runInInjectionContext( - () => resolver({ - params: { systemNumber: '12345', createdTimestamp: 'now' }, - } as unknown as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - await firstValueFrom(result); - expect(routerSpy).toHaveBeenCalled(); - expect(routerSpy).toHaveBeenCalledWith(['./tech-records/12345/now']); - }); - }); + expect(resolveResult).toBe(true); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith( + expect.objectContaining({ + vehicleTechRecord: { + techRecord_vehicleType: 'hgv', + techRecord_vehicleClass_description: 'heavy goods vehicle', + }, + }) + ); + }); + it('should navigate if there is no tech record', async () => { + jest.spyOn(store, 'select').mockReturnValue(of(undefined)); + const routerSpy = jest.spyOn(router, 'navigate').mockImplementation(); + const result = TestBed.runInInjectionContext(() => + resolver( + { + params: { systemNumber: '12345', createdTimestamp: 'now' }, + } as unknown as ActivatedRouteSnapshot, + {} as RouterStateSnapshot + ) + ) as Observable; + await firstValueFrom(result); + expect(routerSpy).toHaveBeenCalled(); + expect(routerSpy).toHaveBeenCalledWith(['./tech-records/12345/now']); + }); + }); }); diff --git a/src/app/resolvers/tech-record-validate/tech-record-validate.resolver.ts b/src/app/resolvers/tech-record-validate/tech-record-validate.resolver.ts index 121e0ed944..75b2239fc5 100644 --- a/src/app/resolvers/tech-record-validate/tech-record-validate.resolver.ts +++ b/src/app/resolvers/tech-record-validate/tech-record-validate.resolver.ts @@ -1,9 +1,5 @@ import { inject } from '@angular/core'; -import { - ActivatedRouteSnapshot, - ResolveFn, - Router, -} from '@angular/router'; +import { ActivatedRouteSnapshot, ResolveFn, Router } from '@angular/router'; import { ApprovalType as approvalType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/approvalType.enum.js'; import { ApprovalType as approvalTypeHgvOrPsv } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/approvalTypeHgvOrPsv.enum.js'; import { EUVehicleCategory as EUVehicleCategoryTrl } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/euVehicleCategory.enum.js'; @@ -12,132 +8,130 @@ import { EUVehicleCategory as EUVehicleCategoryPsv } from '@dvsa/cvs-type-defini import { TyreUseCode as HgvTyreUseCode } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/tyreUseCodeHgv.enum.js'; import { TyreUseCode as TrlTyreUseCode } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/tyreUseCodeTrl.enum.js'; import { VehicleClassDescription } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleClassDescription.enum.js'; -import { - VehicleClassDescription as VehicleClassDescriptionPSV, -} from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleClassDescriptionPSV.enum.js'; -import { - VehicleConfiguration as VehicleConfigurationHgvPsv, -} from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleConfigurationHgvPsv.enum.js'; -import { - VehicleConfiguration as VehicleConfigurationTrl, -} from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleConfigurationTrl.enum.js'; +import { VehicleClassDescription as VehicleClassDescriptionPSV } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleClassDescriptionPSV.enum.js'; +import { VehicleConfiguration as VehicleConfigurationHgvPsv } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleConfigurationHgvPsv.enum.js'; +import { VehicleConfiguration as VehicleConfigurationTrl } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleConfigurationTrl.enum.js'; import { TechRecordType as TechRecordVehicleType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; import { Store } from '@ngrx/store'; import { State } from '@store/.'; import { selectTechRecord, updateEditingTechRecord } from '@store/technical-records'; import { isEqual } from 'lodash'; -import { - map, - take, -} from 'rxjs'; +import { map, take } from 'rxjs'; export const techRecordValidateResolver: ResolveFn = (route: ActivatedRouteSnapshot) => { - const store: Store = inject(Store); - const router: Router = inject(Router); + const store: Store = inject(Store); + const router: Router = inject(Router); - return store.select(selectTechRecord).pipe( - map((record) => { - if (!record) { - void router.navigate([`./tech-records/${route.params['systemNumber']}/${route.params['createdTimestamp']}`]); - } - let validatedRecord = { ...record } as TechRecordType<'put'>; + return store.select(selectTechRecord).pipe( + map((record) => { + if (!record) { + void router.navigate([`./tech-records/${route.params['systemNumber']}/${route.params['createdTimestamp']}`]); + } + let validatedRecord = { ...record } as TechRecordType<'put'>; - if (record) { - switch (true) { - case (record?.techRecord_vehicleType === 'hgv'): { - validatedRecord = handleHgv(record as TechRecordVehicleType<'hgv'>); - break; - } - case (record?.techRecord_vehicleType === 'psv'): { - validatedRecord = handlePsv(record as TechRecordVehicleType<'psv'>); - break; - } - case (record?.techRecord_vehicleType === 'trl'): { - validatedRecord = handleTrl(record as TechRecordVehicleType<'trl'>); - break; - } - default: break; - } - } - if (!isEqual(validatedRecord, record)) { - store.dispatch(updateEditingTechRecord({ vehicleTechRecord: validatedRecord })); - } - }), - take(1), - map(() => { - return true; - }), - ); + if (record) { + switch (true) { + case record?.techRecord_vehicleType === 'hgv': { + validatedRecord = handleHgv(record as TechRecordVehicleType<'hgv'>); + break; + } + case record?.techRecord_vehicleType === 'psv': { + validatedRecord = handlePsv(record as TechRecordVehicleType<'psv'>); + break; + } + case record?.techRecord_vehicleType === 'trl': { + validatedRecord = handleTrl(record as TechRecordVehicleType<'trl'>); + break; + } + default: + break; + } + } + if (!isEqual(validatedRecord, record)) { + store.dispatch(updateEditingTechRecord({ vehicleTechRecord: validatedRecord })); + } + }), + take(1), + map(() => { + return true; + }) + ); }; const handlePsv = (record: TechRecordVehicleType<'psv'>) => { - const validatedRecord: TechRecordVehicleType<'psv'> = { ...record }; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const checks: any = { - techRecord_vehicleConfiguration: VehicleConfigurationHgvPsv, - techRecord_vehicleClass_description: VehicleClassDescriptionPSV, - techRecord_euVehicleCategory: EUVehicleCategoryPsv, - techRecord_approvalType: approvalTypeHgvOrPsv, - } as const; + const validatedRecord: TechRecordVehicleType<'psv'> = { ...record }; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const checks: any = { + techRecord_vehicleConfiguration: VehicleConfigurationHgvPsv, + techRecord_vehicleClass_description: VehicleClassDescriptionPSV, + techRecord_euVehicleCategory: EUVehicleCategoryPsv, + techRecord_approvalType: approvalTypeHgvOrPsv, + } as const; - Object.keys(checks).forEach((key: string) => { - if (record[key as keyof TechRecordVehicleType<'psv'>]) { - const validateValues: boolean = Object.values(checks[`${key}`]).includes(record[key as keyof TechRecordVehicleType<'psv'>]); + Object.keys(checks).forEach((key: string) => { + if (record[key as keyof TechRecordVehicleType<'psv'>]) { + const validateValues: boolean = Object.values(checks[`${key}`]).includes( + record[key as keyof TechRecordVehicleType<'psv'>] + ); - if (!validateValues) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (validatedRecord as any)[key as keyof TechRecordVehicleType<'hgv'>] = null; - } - } - }); - return validatedRecord as TechRecordType<'put'>; + if (!validateValues) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (validatedRecord as any)[key as keyof TechRecordVehicleType<'hgv'>] = null; + } + } + }); + return validatedRecord as TechRecordType<'put'>; }; const handleTrl = (record: TechRecordVehicleType<'trl'>) => { - const validatedRecord: TechRecordVehicleType<'trl'> = { ...record }; - validatedRecord.techRecord_vehicleClass_description = VehicleClassDescription.Trailer; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const checks: any = { - techRecord_tyreUseCode: TrlTyreUseCode, - techRecord_vehicleConfiguration: VehicleConfigurationTrl, - techRecord_euVehicleCategory: EUVehicleCategoryTrl, - techRecord_approvalType: approvalType, - }; + const validatedRecord: TechRecordVehicleType<'trl'> = { ...record }; + validatedRecord.techRecord_vehicleClass_description = VehicleClassDescription.Trailer; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const checks: any = { + techRecord_tyreUseCode: TrlTyreUseCode, + techRecord_vehicleConfiguration: VehicleConfigurationTrl, + techRecord_euVehicleCategory: EUVehicleCategoryTrl, + techRecord_approvalType: approvalType, + }; - Object.keys(checks).forEach((key: string) => { - if (record[key as keyof TechRecordVehicleType<'trl'>]) { - const validateValues: boolean = Object.values(checks[`${key}`]).includes(record[key as keyof TechRecordVehicleType<'trl'>]); + Object.keys(checks).forEach((key: string) => { + if (record[key as keyof TechRecordVehicleType<'trl'>]) { + const validateValues: boolean = Object.values(checks[`${key}`]).includes( + record[key as keyof TechRecordVehicleType<'trl'>] + ); - if (!validateValues) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (validatedRecord as any)[key as keyof TechRecordVehicleType<'hgv'>] = null; - } - } - }); - return validatedRecord as TechRecordType<'put'>; + if (!validateValues) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (validatedRecord as any)[key as keyof TechRecordVehicleType<'hgv'>] = null; + } + } + }); + return validatedRecord as TechRecordType<'put'>; }; const handleHgv = (record: TechRecordVehicleType<'hgv'>) => { - const validatedRecord: TechRecordVehicleType<'hgv'> = { ...record }; - validatedRecord.techRecord_vehicleClass_description = VehicleClassDescription.HeavyGoodsVehicle; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const checks: any = { - techRecord_tyreUseCode: HgvTyreUseCode, - techRecord_vehicleConfiguration: VehicleConfigurationHgvPsv, - techRecord_euVehicleCategory: EUVehicleCategoryHgv, - techRecord_approvalType: approvalTypeHgvOrPsv, - }; + const validatedRecord: TechRecordVehicleType<'hgv'> = { ...record }; + validatedRecord.techRecord_vehicleClass_description = VehicleClassDescription.HeavyGoodsVehicle; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const checks: any = { + techRecord_tyreUseCode: HgvTyreUseCode, + techRecord_vehicleConfiguration: VehicleConfigurationHgvPsv, + techRecord_euVehicleCategory: EUVehicleCategoryHgv, + techRecord_approvalType: approvalTypeHgvOrPsv, + }; - Object.keys(checks).forEach((key: string) => { - if (record[key as keyof TechRecordVehicleType<'hgv'>]) { - const validateValues: boolean = Object.values(checks[`${key}`]).includes(record[key as keyof TechRecordVehicleType<'hgv'>]); + Object.keys(checks).forEach((key: string) => { + if (record[key as keyof TechRecordVehicleType<'hgv'>]) { + const validateValues: boolean = Object.values(checks[`${key}`]).includes( + record[key as keyof TechRecordVehicleType<'hgv'>] + ); - if (!validateValues) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (validatedRecord as any)[key as keyof TechRecordVehicleType<'hgv'>] = null; - } - } - }); - return validatedRecord as TechRecordType<'put'>; + if (!validateValues) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (validatedRecord as any)[key as keyof TechRecordVehicleType<'hgv'>] = null; + } + } + }); + return validatedRecord as TechRecordType<'put'>; }; diff --git a/src/app/resolvers/tech-record-view/tech-record-view.resolver.spec.ts b/src/app/resolvers/tech-record-view/tech-record-view.resolver.spec.ts index 7decd860b2..a9156c8125 100644 --- a/src/app/resolvers/tech-record-view/tech-record-view.resolver.spec.ts +++ b/src/app/resolvers/tech-record-view/tech-record-view.resolver.spec.ts @@ -12,78 +12,85 @@ import { TestScheduler } from 'rxjs/testing'; import { techRecordViewResolver } from './tech-record-view.resolver'; describe('TechRecordViewResolver', () => { - let resolver: ResolveFn; - let actions$ = new Observable(); - let testScheduler: TestScheduler; - const mockSnapshot = jest.fn; - let store: MockStore; + let resolver: ResolveFn; + let actions$ = new Observable(); + let testScheduler: TestScheduler; + const mockSnapshot = jest.fn; + let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [ - provideMockStore({ initialState: initialAppState }), - provideMockActions(() => actions$), - { provide: RouterStateSnapshot, useValue: mockSnapshot }, - ], - }); - store = TestBed.inject(MockStore); - resolver = (...resolverParameters) => TestBed.runInInjectionContext(() => techRecordViewResolver(...resolverParameters)); - }); + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + provideMockStore({ initialState: initialAppState }), + provideMockActions(() => actions$), + { provide: RouterStateSnapshot, useValue: mockSnapshot }, + ], + }); + store = TestBed.inject(MockStore); + resolver = (...resolverParameters) => + TestBed.runInInjectionContext(() => techRecordViewResolver(...resolverParameters)); + }); - beforeEach(() => { - testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - }); + beforeEach(() => { + testScheduler = new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); + }); + }); - it('should be created', () => { - expect(resolver).toBeTruthy(); - }); + it('should be created', () => { + expect(resolver).toBeTruthy(); + }); - describe('fetch tech record result', () => { - it('should resolved to true when both success actions are triggered', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const result = TestBed.runInInjectionContext(() => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot)) as Observable; - store.overrideSelector(selectRouteParam('systemNumber'), undefined); - store.overrideSelector(selectRouteParam('createdTimestamp'), undefined); - testScheduler.run(({ hot, expectObservable }) => { - actions$ = hot('-a-b-', { a: getTechRecordV3Success, b: fetchTestResultsBySystemNumberSuccess }); - expectObservable(result).toBe('---(c|)', { - c: true, - }); - }); + describe('fetch tech record result', () => { + it('should resolved to true when both success actions are triggered', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + store.overrideSelector(selectRouteParam('systemNumber'), undefined); + store.overrideSelector(selectRouteParam('createdTimestamp'), undefined); + testScheduler.run(({ hot, expectObservable }) => { + actions$ = hot('-a-b-', { a: getTechRecordV3Success, b: fetchTestResultsBySystemNumberSuccess }); + expectObservable(result).toBe('---(c|)', { + c: true, + }); + }); - expect(dispatchSpy).toHaveBeenCalledTimes(2); - }); + expect(dispatchSpy).toHaveBeenCalledTimes(2); + }); - it('should resolve to false if \'getTechRecordV3Failure\' action if dispatched', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const result = TestBed.runInInjectionContext(() => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot)) as Observable; - store.overrideSelector(selectRouteParam('systemNumber'), undefined); - store.overrideSelector(selectRouteParam('createdTimestamp'), undefined); - testScheduler.run(({ hot, expectObservable }) => { - actions$ = hot('-a-b-', { a: getTechRecordV3Failure, b: fetchTestResultsBySystemNumberSuccess }); - expectObservable(result).toBe('---(c|)', { - c: false, - }); - }); + it("should resolve to false if 'getTechRecordV3Failure' action if dispatched", () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + store.overrideSelector(selectRouteParam('systemNumber'), undefined); + store.overrideSelector(selectRouteParam('createdTimestamp'), undefined); + testScheduler.run(({ hot, expectObservable }) => { + actions$ = hot('-a-b-', { a: getTechRecordV3Failure, b: fetchTestResultsBySystemNumberSuccess }); + expectObservable(result).toBe('---(c|)', { + c: false, + }); + }); - expect(dispatchSpy).toHaveBeenCalledTimes(2); - }); + expect(dispatchSpy).toHaveBeenCalledTimes(2); + }); - it('should resolved to false if \'fetchTestResultsBySystemNumberFailed\' action is dipatched', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const result = TestBed.runInInjectionContext(() => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot)) as Observable; - store.overrideSelector(selectRouteParam('systemNumber'), undefined); - store.overrideSelector(selectRouteParam('createdTimestamp'), undefined); - testScheduler.run(({ hot, expectObservable }) => { - actions$ = hot('-a-b-', { a: getTechRecordV3Success, b: fetchTestResultsBySystemNumberFailed }); - expectObservable(result).toBe('---(c|)', { - c: false, - }); - }); + it("should resolved to false if 'fetchTestResultsBySystemNumberFailed' action is dipatched", () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + store.overrideSelector(selectRouteParam('systemNumber'), undefined); + store.overrideSelector(selectRouteParam('createdTimestamp'), undefined); + testScheduler.run(({ hot, expectObservable }) => { + actions$ = hot('-a-b-', { a: getTechRecordV3Success, b: fetchTestResultsBySystemNumberFailed }); + expectObservable(result).toBe('---(c|)', { + c: false, + }); + }); - expect(dispatchSpy).toHaveBeenCalledTimes(2); - }); - }); + expect(dispatchSpy).toHaveBeenCalledTimes(2); + }); + }); }); diff --git a/src/app/resolvers/tech-record-view/tech-record-view.resolver.ts b/src/app/resolvers/tech-record-view/tech-record-view.resolver.ts index ac80f3b057..c4d8aa74b9 100644 --- a/src/app/resolvers/tech-record-view/tech-record-view.resolver.ts +++ b/src/app/resolvers/tech-record-view/tech-record-view.resolver.ts @@ -5,25 +5,33 @@ import { Store, select } from '@ngrx/store'; import { State } from '@store/.'; import { selectRouteNestedParams } from '@store/router/selectors/router.selectors'; import { getTechRecordV3, getTechRecordV3Failure, getTechRecordV3Success } from '@store/technical-records'; -import { fetchTestResultsBySystemNumber, fetchTestResultsBySystemNumberFailed, fetchTestResultsBySystemNumberSuccess } from '@store/test-records'; import { - count, - map, - take, -} from 'rxjs'; + fetchTestResultsBySystemNumber, + fetchTestResultsBySystemNumberFailed, + fetchTestResultsBySystemNumberSuccess, +} from '@store/test-records'; +import { count, map, take } from 'rxjs'; export const techRecordViewResolver: ResolveFn = () => { - const store: Store = inject(Store); - const action$: Actions = inject(Actions); - store.pipe(select(selectRouteNestedParams), take(1)).subscribe(({ systemNumber, createdTimestamp }) => { - store.dispatch(getTechRecordV3({ systemNumber, createdTimestamp })); - store.dispatch(fetchTestResultsBySystemNumber({ systemNumber })); - }); + const store: Store = inject(Store); + const action$: Actions = inject(Actions); + store.pipe(select(selectRouteNestedParams), take(1)).subscribe(({ systemNumber, createdTimestamp }) => { + store.dispatch(getTechRecordV3({ systemNumber, createdTimestamp })); + store.dispatch(fetchTestResultsBySystemNumber({ systemNumber })); + }); - return action$.pipe( - ofType(getTechRecordV3Success, fetchTestResultsBySystemNumberSuccess, getTechRecordV3Failure, fetchTestResultsBySystemNumberFailed), - take(2), - count((action) => action.type === getTechRecordV3Success.type || action.type === fetchTestResultsBySystemNumberSuccess.type), - map((total) => (total === 2)), - ); + return action$.pipe( + ofType( + getTechRecordV3Success, + fetchTestResultsBySystemNumberSuccess, + getTechRecordV3Failure, + fetchTestResultsBySystemNumberFailed + ), + take(2), + count( + (action) => + action.type === getTechRecordV3Success.type || action.type === fetchTestResultsBySystemNumberSuccess.type + ), + map((total) => total === 2) + ); }; diff --git a/src/app/resolvers/test-result/test-result.resolver.spec.ts b/src/app/resolvers/test-result/test-result.resolver.spec.ts index cdd921a99e..1c101820c2 100644 --- a/src/app/resolvers/test-result/test-result.resolver.spec.ts +++ b/src/app/resolvers/test-result/test-result.resolver.spec.ts @@ -4,79 +4,79 @@ import { RouterTestingModule } from '@angular/router/testing'; import { provideMockActions } from '@ngrx/effects/testing'; import { Action } from '@ngrx/store'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; -import { initialAppState, State } from '@store/.'; +import { State, initialAppState } from '@store/.'; import { - fetchSelectedTestResult, - fetchSelectedTestResultFailed, - fetchSelectedTestResultSuccess, - selectedTestResultState, + fetchSelectedTestResult, + fetchSelectedTestResultFailed, + fetchSelectedTestResultSuccess, + selectedTestResultState, } from '@store/test-records'; import { Observable } from 'rxjs'; import { TestScheduler } from 'rxjs/testing'; import { testResultResolver } from './test-result.resolver'; describe('TestResultResolver', () => { - let resolver: ResolveFn; - let actions$ = new Observable(); - let testScheduler: TestScheduler; - const mockSnapshot = jest.fn; - let store: MockStore; + let resolver: ResolveFn; + let actions$ = new Observable(); + let testScheduler: TestScheduler; + const mockSnapshot = jest.fn; + let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [RouterTestingModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - provideMockActions(() => actions$), - { provide: RouterStateSnapshot, useValue: mockSnapshot }, - ], - }); - resolver = (...resolverParameters) => - TestBed.runInInjectionContext(() => testResultResolver(...resolverParameters)); - store = TestBed.inject(MockStore); - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + provideMockActions(() => actions$), + { provide: RouterStateSnapshot, useValue: mockSnapshot }, + ], + }); + resolver = (...resolverParameters) => + TestBed.runInInjectionContext(() => testResultResolver(...resolverParameters)); + store = TestBed.inject(MockStore); + }); - beforeEach(() => { - testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - }); + beforeEach(() => { + testScheduler = new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); + }); + }); - it('should be created', () => { - expect(resolver).toBeTruthy(); - }); + it('should be created', () => { + expect(resolver).toBeTruthy(); + }); - describe('fetch test result', () => { - it('should resolve to true when all actions are success type', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - store.overrideSelector(selectedTestResultState, undefined); - testScheduler.run(({ hot, expectObservable }) => { - actions$ = hot('-a', { a: fetchSelectedTestResultSuccess }); - expectObservable(result).toBe('-(b|)', { - b: true, - }); - }); + describe('fetch test result', () => { + it('should resolve to true when all actions are success type', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + store.overrideSelector(selectedTestResultState, undefined); + testScheduler.run(({ hot, expectObservable }) => { + actions$ = hot('-a', { a: fetchSelectedTestResultSuccess }); + expectObservable(result).toBe('-(b|)', { + b: true, + }); + }); - expect(dispatchSpy).toHaveBeenCalledWith(fetchSelectedTestResult()); - }); + expect(dispatchSpy).toHaveBeenCalledWith(fetchSelectedTestResult()); + }); - it('should resolve to false when one or more actions are of failure type', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - store.overrideSelector(selectedTestResultState, undefined); - testScheduler.run(({ hot, expectObservable }) => { - actions$ = hot('-a', { a: fetchSelectedTestResultFailed }); - expectObservable(result).toBe('-(b|)', { - b: false, - }); - }); + it('should resolve to false when one or more actions are of failure type', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + store.overrideSelector(selectedTestResultState, undefined); + testScheduler.run(({ hot, expectObservable }) => { + actions$ = hot('-a', { a: fetchSelectedTestResultFailed }); + expectObservable(result).toBe('-(b|)', { + b: false, + }); + }); - expect(dispatchSpy).toHaveBeenCalledWith(fetchSelectedTestResult()); - }); - }); + expect(dispatchSpy).toHaveBeenCalledWith(fetchSelectedTestResult()); + }); + }); }); diff --git a/src/app/resolvers/test-result/test-result.resolver.ts b/src/app/resolvers/test-result/test-result.resolver.ts index e37915ceb9..f6d1549260 100644 --- a/src/app/resolvers/test-result/test-result.resolver.ts +++ b/src/app/resolvers/test-result/test-result.resolver.ts @@ -4,24 +4,24 @@ import { Actions, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; import { State } from '@store/.'; import { - cancelEditingTestResult, - fetchSelectedTestResult, - fetchSelectedTestResultFailed, - fetchSelectedTestResultSuccess, + cancelEditingTestResult, + fetchSelectedTestResult, + fetchSelectedTestResultFailed, + fetchSelectedTestResultSuccess, } from '@store/test-records'; import { map, take } from 'rxjs'; export const testResultResolver: ResolveFn = () => { - const store: Store = inject(Store); - const action$: Actions = inject(Actions); - store.dispatch(fetchSelectedTestResult()); - store.dispatch(cancelEditingTestResult()); + const store: Store = inject(Store); + const action$: Actions = inject(Actions); + store.dispatch(fetchSelectedTestResult()); + store.dispatch(cancelEditingTestResult()); - return action$.pipe( - ofType(fetchSelectedTestResultSuccess, fetchSelectedTestResultFailed), - take(1), - map((action) => { - return action.type === fetchSelectedTestResultSuccess.type; - }), - ); + return action$.pipe( + ofType(fetchSelectedTestResultSuccess, fetchSelectedTestResultFailed), + take(1), + map((action) => { + return action.type === fetchSelectedTestResultSuccess.type; + }) + ); }; diff --git a/src/app/resolvers/test-stations/test-stations.resolver.spec.ts b/src/app/resolvers/test-stations/test-stations.resolver.spec.ts index cc076c0e67..f76288356f 100644 --- a/src/app/resolvers/test-stations/test-stations.resolver.spec.ts +++ b/src/app/resolvers/test-stations/test-stations.resolver.spec.ts @@ -10,60 +10,60 @@ import { TestScheduler } from 'rxjs/testing'; import { testStationsResolver } from './test-stations.resolver'; describe('TestTypeTaxonomyResolver', () => { - let resolver: ResolveFn; - let actions$ = new Observable(); - let testScheduler: TestScheduler; - let store: MockStore; + let resolver: ResolveFn; + let actions$ = new Observable(); + let testScheduler: TestScheduler; + let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideMockStore({ initialState: initialAppState }), provideMockActions(() => actions$)], - }); - store = TestBed.inject(MockStore); - resolver = (...resolverParameters) => - TestBed.runInInjectionContext(() => testStationsResolver(...resolverParameters)); - }); + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore({ initialState: initialAppState }), provideMockActions(() => actions$)], + }); + store = TestBed.inject(MockStore); + resolver = (...resolverParameters) => + TestBed.runInInjectionContext(() => testStationsResolver(...resolverParameters)); + }); - beforeEach(() => { - testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - }); + beforeEach(() => { + testScheduler = new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); + }); + }); - it('should be created', () => { - expect(resolver).toBeTruthy(); - }); + it('should be created', () => { + expect(resolver).toBeTruthy(); + }); - describe('fetch test stations', () => { - it('should resolve to true when all actions are success type', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - testScheduler.run(({ hot, expectObservable }) => { - actions$ = hot('-a', { a: fetchTestStationsSuccess }); + describe('fetch test stations', () => { + it('should resolve to true when all actions are success type', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + testScheduler.run(({ hot, expectObservable }) => { + actions$ = hot('-a', { a: fetchTestStationsSuccess }); - expectObservable(result).toBe('-(b|)', { - b: true, - }); - }); + expectObservable(result).toBe('-(b|)', { + b: true, + }); + }); - expect(dispatchSpy).toHaveBeenCalledWith(fetchTestStations()); - }); + expect(dispatchSpy).toHaveBeenCalledWith(fetchTestStations()); + }); - it('should resolve to false when one or more actions are of failure type', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - testScheduler.run(({ hot, expectObservable }) => { - actions$ = hot('-a', { a: fetchTestStationsFailed }); - expectObservable(result).toBe('-(b|)', { - b: false, - }); - }); + it('should resolve to false when one or more actions are of failure type', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + testScheduler.run(({ hot, expectObservable }) => { + actions$ = hot('-a', { a: fetchTestStationsFailed }); + expectObservable(result).toBe('-(b|)', { + b: false, + }); + }); - expect(dispatchSpy).toHaveBeenCalledWith(fetchTestStations()); - }); - }); + expect(dispatchSpy).toHaveBeenCalledWith(fetchTestStations()); + }); + }); }); diff --git a/src/app/resolvers/test-stations/test-stations.resolver.ts b/src/app/resolvers/test-stations/test-stations.resolver.ts index e7874e178e..45f8a8d123 100644 --- a/src/app/resolvers/test-stations/test-stations.resolver.ts +++ b/src/app/resolvers/test-stations/test-stations.resolver.ts @@ -7,13 +7,13 @@ import { fetchTestStations, fetchTestStationsFailed, fetchTestStationsSuccess } import { map, take } from 'rxjs'; export const testStationsResolver: ResolveFn = () => { - const store: Store = inject(Store); - const action$: Actions = inject(Actions); - store.dispatch(fetchTestStations()); + const store: Store = inject(Store); + const action$: Actions = inject(Actions); + store.dispatch(fetchTestStations()); - return action$.pipe( - ofType(fetchTestStationsSuccess, fetchTestStationsFailed), - take(1), - map((action) => action.type === fetchTestStationsSuccess.type), - ); + return action$.pipe( + ofType(fetchTestStationsSuccess, fetchTestStationsFailed), + take(1), + map((action) => action.type === fetchTestStationsSuccess.type) + ); }; diff --git a/src/app/resolvers/test-type-taxonomy/test-type-taxonomy.resolver.spec.ts b/src/app/resolvers/test-type-taxonomy/test-type-taxonomy.resolver.spec.ts index 0f8499a73e..82c4e4208a 100644 --- a/src/app/resolvers/test-type-taxonomy/test-type-taxonomy.resolver.spec.ts +++ b/src/app/resolvers/test-type-taxonomy/test-type-taxonomy.resolver.spec.ts @@ -1,68 +1,72 @@ import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot } from '@angular/router'; import { provideMockActions } from '@ngrx/effects/testing'; import { Action } from '@ngrx/store'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; -import { initialAppState, State } from '@store/.'; -import { fetchTestTypes, fetchTestTypesFailed, fetchTestTypesSuccess } from '@store/test-types/actions/test-types.actions'; +import { State, initialAppState } from '@store/.'; +import { + fetchTestTypes, + fetchTestTypesFailed, + fetchTestTypesSuccess, +} from '@store/test-types/actions/test-types.actions'; import { Observable } from 'rxjs'; import { TestScheduler } from 'rxjs/testing'; -import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot } from '@angular/router'; import { testTypeTaxonomyResolver } from './test-type-taxonomy.resolver'; describe('TestTypeTaxonomyResolver', () => { - let resolver: ResolveFn; - let actions$ = new Observable(); - let testScheduler: TestScheduler; - let store: MockStore; + let resolver: ResolveFn; + let actions$ = new Observable(); + let testScheduler: TestScheduler; + let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideMockStore({ initialState: initialAppState }), provideMockActions(() => actions$)], - }); - resolver = (...resolverParameters) => - TestBed.runInInjectionContext(() => testTypeTaxonomyResolver(...resolverParameters)); - store = TestBed.inject(MockStore); - }); + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore({ initialState: initialAppState }), provideMockActions(() => actions$)], + }); + resolver = (...resolverParameters) => + TestBed.runInInjectionContext(() => testTypeTaxonomyResolver(...resolverParameters)); + store = TestBed.inject(MockStore); + }); - beforeEach(() => { - testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - }); + beforeEach(() => { + testScheduler = new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); + }); + }); - it('should be created', () => { - expect(resolver).toBeTruthy(); - }); + it('should be created', () => { + expect(resolver).toBeTruthy(); + }); - describe('fetch test types', () => { - it('should resolve to true when all actions are success type', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - testScheduler.run(({ hot, expectObservable }) => { - actions$ = hot('-a', { a: fetchTestTypesSuccess }); - expectObservable(result).toBe('-(b|)', { - b: true, - }); - }); + describe('fetch test types', () => { + it('should resolve to true when all actions are success type', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + testScheduler.run(({ hot, expectObservable }) => { + actions$ = hot('-a', { a: fetchTestTypesSuccess }); + expectObservable(result).toBe('-(b|)', { + b: true, + }); + }); - expect(dispatchSpy).toHaveBeenCalledWith(fetchTestTypes()); - }); + expect(dispatchSpy).toHaveBeenCalledWith(fetchTestTypes()); + }); - it('should resolve to false when one or more actions are of failure type', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Observable; - testScheduler.run(({ hot, expectObservable }) => { - actions$ = hot('-a', { a: fetchTestTypesFailed }); - expectObservable(result).toBe('-(b|)', { - b: false, - }); - }); + it('should resolve to false when one or more actions are of failure type', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Observable; + testScheduler.run(({ hot, expectObservable }) => { + actions$ = hot('-a', { a: fetchTestTypesFailed }); + expectObservable(result).toBe('-(b|)', { + b: false, + }); + }); - expect(dispatchSpy).toHaveBeenCalledWith(fetchTestTypes()); - }); - }); + expect(dispatchSpy).toHaveBeenCalledWith(fetchTestTypes()); + }); + }); }); diff --git a/src/app/resolvers/test-type-taxonomy/test-type-taxonomy.resolver.ts b/src/app/resolvers/test-type-taxonomy/test-type-taxonomy.resolver.ts index b0565828d6..01db50d442 100644 --- a/src/app/resolvers/test-type-taxonomy/test-type-taxonomy.resolver.ts +++ b/src/app/resolvers/test-type-taxonomy/test-type-taxonomy.resolver.ts @@ -3,17 +3,21 @@ import { ResolveFn } from '@angular/router'; import { Actions, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; import { State } from '@store/.'; -import { fetchTestTypes, fetchTestTypesFailed, fetchTestTypesSuccess } from '@store/test-types/actions/test-types.actions'; +import { + fetchTestTypes, + fetchTestTypesFailed, + fetchTestTypesSuccess, +} from '@store/test-types/actions/test-types.actions'; import { map, take } from 'rxjs'; export const testTypeTaxonomyResolver: ResolveFn = () => { - const store: Store = inject(Store); - const action$: Actions = inject(Actions); - store.dispatch(fetchTestTypes()); + const store: Store = inject(Store); + const action$: Actions = inject(Actions); + store.dispatch(fetchTestTypes()); - return action$.pipe( - ofType(fetchTestTypesSuccess, fetchTestTypesFailed), - take(1), - map((action) => action.type === fetchTestTypesSuccess.type), - ); + return action$.pipe( + ofType(fetchTestTypesSuccess, fetchTestTypesFailed), + take(1), + map((action) => action.type === fetchTestTypesSuccess.type) + ); }; diff --git a/src/app/resolvers/title/title.resolver.spec.ts b/src/app/resolvers/title/title.resolver.spec.ts index ce4a0aab10..674fc1d563 100644 --- a/src/app/resolvers/title/title.resolver.spec.ts +++ b/src/app/resolvers/title/title.resolver.spec.ts @@ -1,68 +1,67 @@ import { TestBed } from '@angular/core/testing'; import { Title } from '@angular/platform-browser'; +import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; -import { initialAppState, State } from '@store/.'; -import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot } from '@angular/router'; +import { State, initialAppState } from '@store/.'; import { titleResolver } from './title.resolver'; describe('TitleResolver', () => { - let resolver: ResolveFn; - let titleService: Title; - let store: MockStore; + let resolver: ResolveFn; + let titleService: Title; + let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [RouterTestingModule], - providers: [Title, provideMockStore({ initialState: initialAppState })], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + providers: [Title, provideMockStore({ initialState: initialAppState })], + }); - resolver = (...resolverParameters) => - TestBed.runInInjectionContext(() => titleResolver(...resolverParameters)); - titleService = TestBed.inject(Title); - store = TestBed.inject(MockStore); - }); + resolver = (...resolverParameters) => TestBed.runInInjectionContext(() => titleResolver(...resolverParameters)); + titleService = TestBed.inject(Title); + store = TestBed.inject(MockStore); + }); - it('should be created', () => { - expect(resolver).toBeTruthy(); - }); + it('should be created', () => { + expect(resolver).toBeTruthy(); + }); - it('should set title using Title service', () => { - const titleServiceSpy = jest.spyOn(titleService, 'setTitle'); - const result = TestBed.runInInjectionContext( - () => resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot), - ) as Promise; - store.setState({ - ...initialAppState, - router: { - state: { - root: { - params: { - systemNumber: 'SYS0001', - }, - data: { - title: 'Test Results', - }, - url: [ - { - path: 'SYS0001', - parameters: {}, - }, - ], - outlet: 'primary', - routeConfig: { - path: ':systemNumber', - }, - queryParams: {}, - fragment: null, - children: [], - }, - }, - navigationId: 1, - }, - }); - const resolved = result; - expect(resolved).toBeTruthy(); - expect(titleServiceSpy).toHaveBeenCalledWith('Vehicle Testing Management - Test Results'); - }); + it('should set title using Title service', () => { + const titleServiceSpy = jest.spyOn(titleService, 'setTitle'); + const result = TestBed.runInInjectionContext(() => + resolver({} as ActivatedRouteSnapshot, {} as RouterStateSnapshot) + ) as Promise; + store.setState({ + ...initialAppState, + router: { + state: { + root: { + params: { + systemNumber: 'SYS0001', + }, + data: { + title: 'Test Results', + }, + url: [ + { + path: 'SYS0001', + parameters: {}, + }, + ], + outlet: 'primary', + routeConfig: { + path: ':systemNumber', + }, + queryParams: {}, + fragment: null, + children: [], + }, + }, + navigationId: 1, + }, + }); + const resolved = result; + expect(resolved).toBeTruthy(); + expect(titleServiceSpy).toHaveBeenCalledWith('Vehicle Testing Management - Test Results'); + }); }); diff --git a/src/app/resolvers/title/title.resolver.ts b/src/app/resolvers/title/title.resolver.ts index 996a5d0dc1..ac248af656 100644 --- a/src/app/resolvers/title/title.resolver.ts +++ b/src/app/resolvers/title/title.resolver.ts @@ -6,15 +6,15 @@ import { State } from '@store/.'; import { selectRouteData } from '@store/router/selectors/router.selectors'; export const titleResolver: ResolveFn = () => { - const store: Store = inject(Store); - const titleService: Title = inject(Title); - return new Promise((resolve) => { - store.pipe(select(selectRouteData)).subscribe((navigationData) => { - const { title } = navigationData; - if (title) { - titleService.setTitle(`Vehicle Testing Management - ${title as string}`); - } - }); - resolve(true); - }); + const store: Store = inject(Store); + const titleService: Title = inject(Title); + return new Promise((resolve) => { + store.pipe(select(selectRouteData)).subscribe((navigationData) => { + const { title } = navigationData; + if (title) { + titleService.setTitle(`Vehicle Testing Management - ${title as string}`); + } + }); + resolve(true); + }); }; diff --git a/src/app/services/adr/adr.service.spec.ts b/src/app/services/adr/adr.service.spec.ts index c56465de82..b65e059c39 100644 --- a/src/app/services/adr/adr.service.spec.ts +++ b/src/app/services/adr/adr.service.spec.ts @@ -5,86 +5,112 @@ import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/ import { AdrService } from './adr.service'; describe('AdrService', () => { - let service: AdrService; + let service: AdrService; - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(AdrService); - }); + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(AdrService); + }); - it('should be created', () => { - expect(service).toBeTruthy(); - }); + it('should be created', () => { + expect(service).toBeTruthy(); + }); - describe('carriesDangerousGoods', () => { - it('should return true if vehicle carries dangerous goods', () => { - expect(service.carriesDangerousGoods({ techRecord_adrDetails_batteryListNumber: 'number' } as TechRecordType<'hgv'>)).toBe(true); - }); - it('should return false if vehicle does not carry dangerous goods', () => { - expect(service.carriesDangerousGoods({ techRecord_reasonForCreation: 'carries non-dangerous goods' } as TechRecordType<'hgv'>)).toBe(false); - }); - }); + describe('carriesDangerousGoods', () => { + it('should return true if vehicle carries dangerous goods', () => { + expect( + service.carriesDangerousGoods({ techRecord_adrDetails_batteryListNumber: 'number' } as TechRecordType<'hgv'>) + ).toBe(true); + }); + it('should return false if vehicle does not carry dangerous goods', () => { + expect( + service.carriesDangerousGoods({ + techRecord_reasonForCreation: 'carries non-dangerous goods', + } as TechRecordType<'hgv'>) + ).toBe(false); + }); + }); - describe('determineTankStatementSelect', () => { - it('should return STATEMENT if tankStatement_statement is truthy', () => { - const techRecord = { techRecord_adrDetails_tank_tankDetails_tankStatement_statement: 'Reference no.' } as TechRecordType<'hgv'>; - expect(service.determineTankStatementSelect(techRecord)).toBe(ADRTankDetailsTankStatementSelect.STATEMENT); - }); + describe('determineTankStatementSelect', () => { + it('should return STATEMENT if tankStatement_statement is truthy', () => { + const techRecord = { + techRecord_adrDetails_tank_tankDetails_tankStatement_statement: 'Reference no.', + } as TechRecordType<'hgv'>; + expect(service.determineTankStatementSelect(techRecord)).toBe(ADRTankDetailsTankStatementSelect.STATEMENT); + }); - it('should return PRODUCT_LIST if tankStatement_productList is truthy', () => { - const techRecord = { techRecord_adrDetails_tank_tankDetails_tankStatement_productList: 'Product list' } as TechRecordType<'hgv'>; - expect(service.determineTankStatementSelect(techRecord)).toBe(ADRTankDetailsTankStatementSelect.PRODUCT_LIST); - }); + it('should return PRODUCT_LIST if tankStatement_productList is truthy', () => { + const techRecord = { + techRecord_adrDetails_tank_tankDetails_tankStatement_productList: 'Product list', + } as TechRecordType<'hgv'>; + expect(service.determineTankStatementSelect(techRecord)).toBe(ADRTankDetailsTankStatementSelect.PRODUCT_LIST); + }); - it('should return PRODUCT_LIST if tankStatement_productListRefNo is truthy', () => { - const techRecord = { techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo: 'Reference no.' } as TechRecordType<'hgv'>; - expect(service.determineTankStatementSelect(techRecord)).toBe(ADRTankDetailsTankStatementSelect.PRODUCT_LIST); - }); + it('should return PRODUCT_LIST if tankStatement_productListRefNo is truthy', () => { + const techRecord = { + techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo: 'Reference no.', + } as TechRecordType<'hgv'>; + expect(service.determineTankStatementSelect(techRecord)).toBe(ADRTankDetailsTankStatementSelect.PRODUCT_LIST); + }); - it('should return PRODUCT_LIST if tankStatement_productListUnNo is truthy AND has 1 index', () => { - const techRecord = { techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: ['UN no.'] } as TechRecordType<'hgv'>; - expect(service.determineTankStatementSelect(techRecord)).toBe(ADRTankDetailsTankStatementSelect.PRODUCT_LIST); - }); + it('should return PRODUCT_LIST if tankStatement_productListUnNo is truthy AND has 1 index', () => { + const techRecord = { + techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: ['UN no.'], + } as TechRecordType<'hgv'>; + expect(service.determineTankStatementSelect(techRecord)).toBe(ADRTankDetailsTankStatementSelect.PRODUCT_LIST); + }); - it('should return null if tankStatement_statement is falsy', () => { - const a = { } as TechRecordType<'hgv'>; - const b = { techRecord_adrDetails_tank_tankDetails_tankStatement_statement: null } as TechRecordType<'hgv'>; - const c = { techRecord_adrDetails_tank_tankDetails_tankStatement_statement: undefined } as TechRecordType<'hgv'>; - expect(service.determineTankStatementSelect(a)).toBeNull(); - expect(service.determineTankStatementSelect(b)).toBeNull(); - expect(service.determineTankStatementSelect(c)).toBeNull(); - }); + it('should return null if tankStatement_statement is falsy', () => { + const a = {} as TechRecordType<'hgv'>; + const b = { techRecord_adrDetails_tank_tankDetails_tankStatement_statement: null } as TechRecordType<'hgv'>; + const c = { techRecord_adrDetails_tank_tankDetails_tankStatement_statement: undefined } as TechRecordType<'hgv'>; + expect(service.determineTankStatementSelect(a)).toBeNull(); + expect(service.determineTankStatementSelect(b)).toBeNull(); + expect(service.determineTankStatementSelect(c)).toBeNull(); + }); - it('should return null if tankStatement_productList is falsy', () => { - const a = { } as TechRecordType<'hgv'>; - const b = { techRecord_adrDetails_tank_tankDetails_tankStatement_productList: null } as TechRecordType<'hgv'>; - const c = { techRecord_adrDetails_tank_tankDetails_tankStatement_productList: undefined } as TechRecordType<'hgv'>; - expect(service.determineTankStatementSelect(a)).toBeNull(); - expect(service.determineTankStatementSelect(b)).toBeNull(); - expect(service.determineTankStatementSelect(c)).toBeNull(); - }); + it('should return null if tankStatement_productList is falsy', () => { + const a = {} as TechRecordType<'hgv'>; + const b = { techRecord_adrDetails_tank_tankDetails_tankStatement_productList: null } as TechRecordType<'hgv'>; + const c = { + techRecord_adrDetails_tank_tankDetails_tankStatement_productList: undefined, + } as TechRecordType<'hgv'>; + expect(service.determineTankStatementSelect(a)).toBeNull(); + expect(service.determineTankStatementSelect(b)).toBeNull(); + expect(service.determineTankStatementSelect(c)).toBeNull(); + }); - it('should return null if tankStatement_productListRefNo is falsy', () => { - const a = { } as TechRecordType<'hgv'>; - const b = { techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo: null } as TechRecordType<'hgv'>; - const c = { techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo: undefined } as TechRecordType<'hgv'>; - expect(service.determineTankStatementSelect(a)).toBeNull(); - expect(service.determineTankStatementSelect(b)).toBeNull(); - expect(service.determineTankStatementSelect(c)).toBeNull(); - }); + it('should return null if tankStatement_productListRefNo is falsy', () => { + const a = {} as TechRecordType<'hgv'>; + const b = { + techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo: null, + } as TechRecordType<'hgv'>; + const c = { + techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo: undefined, + } as TechRecordType<'hgv'>; + expect(service.determineTankStatementSelect(a)).toBeNull(); + expect(service.determineTankStatementSelect(b)).toBeNull(); + expect(service.determineTankStatementSelect(c)).toBeNull(); + }); - it('should return null if tankStatement_productListUnNo is falsy AND has 1 index', () => { - const techRecord = { techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: ['UN no.'] } as TechRecordType<'hgv'>; - expect(service.determineTankStatementSelect(techRecord)).toBe(ADRTankDetailsTankStatementSelect.PRODUCT_LIST); + it('should return null if tankStatement_productListUnNo is falsy AND has 1 index', () => { + const techRecord = { + techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: ['UN no.'], + } as TechRecordType<'hgv'>; + expect(service.determineTankStatementSelect(techRecord)).toBe(ADRTankDetailsTankStatementSelect.PRODUCT_LIST); - const a = { } as TechRecordType<'hgv'>; - const b = { techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: null } as TechRecordType<'hgv'>; - const c = { techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: undefined } as TechRecordType<'hgv'>; - const d = { techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: [] as string[] } as TechRecordType<'hgv'>; - expect(service.determineTankStatementSelect(a)).toBeNull(); - expect(service.determineTankStatementSelect(b)).toBeNull(); - expect(service.determineTankStatementSelect(c)).toBeNull(); - expect(service.determineTankStatementSelect(d)).toBeNull(); - }); - }); + const a = {} as TechRecordType<'hgv'>; + const b = { techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: null } as TechRecordType<'hgv'>; + const c = { + techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: undefined, + } as TechRecordType<'hgv'>; + const d = { + techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: [] as string[], + } as TechRecordType<'hgv'>; + expect(service.determineTankStatementSelect(a)).toBeNull(); + expect(service.determineTankStatementSelect(b)).toBeNull(); + expect(service.determineTankStatementSelect(c)).toBeNull(); + expect(service.determineTankStatementSelect(d)).toBeNull(); + }); + }); }); diff --git a/src/app/services/adr/adr.service.ts b/src/app/services/adr/adr.service.ts index 5ad10f5fbe..a1d6e33057 100644 --- a/src/app/services/adr/adr.service.ts +++ b/src/app/services/adr/adr.service.ts @@ -3,28 +3,36 @@ import { ADRTankDetailsTankStatementSelect } from '@dvsa/cvs-type-definitions/ty import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class AdrService { - determineTankStatementSelect(techRecord: TechRecordType<'hgv' | 'lgv' | 'trl'>) { - const { - techRecord_adrDetails_tank_tankDetails_tankStatement_statement: statement, - techRecord_adrDetails_tank_tankDetails_tankStatement_productList: productList, - techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: productListUnNo, - techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo: productListRefNo, - } = techRecord; + determineTankStatementSelect(techRecord: TechRecordType<'hgv' | 'lgv' | 'trl'>) { + const { + techRecord_adrDetails_tank_tankDetails_tankStatement_statement: statement, + techRecord_adrDetails_tank_tankDetails_tankStatement_productList: productList, + techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: productListUnNo, + techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo: productListRefNo, + } = techRecord; - if (statement) return ADRTankDetailsTankStatementSelect.STATEMENT; - if (productList || productListRefNo || (productListUnNo && productListUnNo.length > 0)) return ADRTankDetailsTankStatementSelect.PRODUCT_LIST; + if (statement) return ADRTankDetailsTankStatementSelect.STATEMENT; + if (productList || productListRefNo || (productListUnNo && productListUnNo.length > 0)) + return ADRTankDetailsTankStatementSelect.PRODUCT_LIST; - return null; - } + return null; + } - carriesDangerousGoods(techRecord: TechRecordType<'hgv' | 'lgv' | 'trl'>) { - return techRecord.techRecord_adrDetails_dangerousGoods - || (techRecord.techRecord_adrDetails_dangerousGoods !== false && Boolean(Object.keys(techRecord).find((key) => - key !== 'techRecord_adrDetails_dangerousGoods' - && key.includes('adrDetails') - && techRecord[key as keyof TechRecordType<'hgv' | 'lgv' | 'trl'>] != null))); - } + carriesDangerousGoods(techRecord: TechRecordType<'hgv' | 'lgv' | 'trl'>) { + return ( + techRecord.techRecord_adrDetails_dangerousGoods || + (techRecord.techRecord_adrDetails_dangerousGoods !== false && + Boolean( + Object.keys(techRecord).find( + (key) => + key !== 'techRecord_adrDetails_dangerousGoods' && + key.includes('adrDetails') && + techRecord[key as keyof TechRecordType<'hgv' | 'lgv' | 'trl'>] != null + ) + )) + ); + } } diff --git a/src/app/services/axles/axles.service.spec.ts b/src/app/services/axles/axles.service.spec.ts index ba5ee047d5..d55a1d175f 100644 --- a/src/app/services/axles/axles.service.spec.ts +++ b/src/app/services/axles/axles.service.spec.ts @@ -2,102 +2,110 @@ import { TestBed } from '@angular/core/testing'; import { AxlesService } from './axles.service'; describe('AxlesService', () => { - let service: AxlesService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(AxlesService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('normaliseVehicleTechRecordAxles', () => { - it('should not change anything if the tech record is correct', () => { - const generateAxleSpacingSpy = jest.spyOn(service, 'generateAxleSpacing').mockImplementation(); - const generateAxlesFromAxleSpacingsSpy = jest.spyOn(service, 'generateAxlesFromAxleSpacings').mockImplementation(); - - expect(generateAxleSpacingSpy).not.toHaveBeenCalled(); - expect(generateAxlesFromAxleSpacingsSpy).not.toHaveBeenCalled(); - }); - - it('should call generate spacings if there are more axles', () => { - const expectedResult = [{ axles: '1-2' }]; - - const generateAxleSpacingSpy = jest.spyOn(service, 'generateAxleSpacing').mockImplementation(() => expectedResult); - const generateAxlesFromAxleSpacingsSpy = jest.spyOn(service, 'generateAxlesFromAxleSpacings').mockImplementation(); - - const [, newAxleSpacings] = service.normaliseAxles([{}, {}], []); - - expect(newAxleSpacings).toBe(expectedResult); - expect(generateAxleSpacingSpy).toHaveBeenCalledWith(2, []); - expect(generateAxlesFromAxleSpacingsSpy).not.toHaveBeenCalled(); - }); - - it('should call generate axles if there are more spacings', () => { - const expectedResult = [{ axleNumber: 1 }]; - - const generateAxleSpacingSpy = jest.spyOn(service, 'generateAxleSpacing').mockImplementation(); - const generateAxlesFromAxleSpacingsSpy = jest.spyOn(service, 'generateAxlesFromAxleSpacings').mockImplementation(() => expectedResult); - - const [newAxles] = service.normaliseAxles([{}], [{}]); - - expect(newAxles).toBe(expectedResult); - expect(generateAxleSpacingSpy).not.toHaveBeenCalled(); - expect(generateAxlesFromAxleSpacingsSpy).toHaveBeenCalledWith(1, [{}]); - }); - }); - - describe('generateAxleSpacing', () => { - it('should generate 3 axle spacings', () => { - const result = service.generateAxleSpacing(4); - - expect(result).toStrictEqual([ - { axles: '1-2', value: null }, - { axles: '2-3', value: null }, - { axles: '3-4', value: null }, - ]); - }); - - it('should generate no axle spacings', () => { - const result = service.generateAxleSpacing(1); - - expect(result).toStrictEqual([]); - }); - - it('should generate 3 axle spacings when adding a axle', () => { - const originalAxleSpacings = [ - { axles: '1-2', value: 100 }, - { axles: '2-3', value: 200 }, - ]; - - const result = service.generateAxleSpacing(4, originalAxleSpacings); - - expect(result).toStrictEqual([ - { axles: '1-2', value: 100 }, - { axles: '2-3', value: 200 }, - { axles: '3-4', value: null }, - ]); - }); - }); - - describe('generateAxles', () => { - it('should generate 3 axles from no previous data', () => { - const result = service.generateAxlesFromAxleSpacings(2); - - expect(result).toHaveLength(3); - expect(result[0]?.axleNumber).toBe(1); - expect(result[2]?.axleNumber).toBe(3); - }); - - it('should generate 3 axles from 1 previous axle', () => { - const previousAxles = [{ axleNumber: 1 }]; - const result = service.generateAxlesFromAxleSpacings(2, previousAxles); - - expect(result).toHaveLength(3); - expect(result[0]?.axleNumber).toBe(1); - expect(result[2]?.axleNumber).toBe(3); - }); - }); + let service: AxlesService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(AxlesService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + describe('normaliseVehicleTechRecordAxles', () => { + it('should not change anything if the tech record is correct', () => { + const generateAxleSpacingSpy = jest.spyOn(service, 'generateAxleSpacing').mockImplementation(); + const generateAxlesFromAxleSpacingsSpy = jest + .spyOn(service, 'generateAxlesFromAxleSpacings') + .mockImplementation(); + + expect(generateAxleSpacingSpy).not.toHaveBeenCalled(); + expect(generateAxlesFromAxleSpacingsSpy).not.toHaveBeenCalled(); + }); + + it('should call generate spacings if there are more axles', () => { + const expectedResult = [{ axles: '1-2' }]; + + const generateAxleSpacingSpy = jest + .spyOn(service, 'generateAxleSpacing') + .mockImplementation(() => expectedResult); + const generateAxlesFromAxleSpacingsSpy = jest + .spyOn(service, 'generateAxlesFromAxleSpacings') + .mockImplementation(); + + const [, newAxleSpacings] = service.normaliseAxles([{}, {}], []); + + expect(newAxleSpacings).toBe(expectedResult); + expect(generateAxleSpacingSpy).toHaveBeenCalledWith(2, []); + expect(generateAxlesFromAxleSpacingsSpy).not.toHaveBeenCalled(); + }); + + it('should call generate axles if there are more spacings', () => { + const expectedResult = [{ axleNumber: 1 }]; + + const generateAxleSpacingSpy = jest.spyOn(service, 'generateAxleSpacing').mockImplementation(); + const generateAxlesFromAxleSpacingsSpy = jest + .spyOn(service, 'generateAxlesFromAxleSpacings') + .mockImplementation(() => expectedResult); + + const [newAxles] = service.normaliseAxles([{}], [{}]); + + expect(newAxles).toBe(expectedResult); + expect(generateAxleSpacingSpy).not.toHaveBeenCalled(); + expect(generateAxlesFromAxleSpacingsSpy).toHaveBeenCalledWith(1, [{}]); + }); + }); + + describe('generateAxleSpacing', () => { + it('should generate 3 axle spacings', () => { + const result = service.generateAxleSpacing(4); + + expect(result).toStrictEqual([ + { axles: '1-2', value: null }, + { axles: '2-3', value: null }, + { axles: '3-4', value: null }, + ]); + }); + + it('should generate no axle spacings', () => { + const result = service.generateAxleSpacing(1); + + expect(result).toStrictEqual([]); + }); + + it('should generate 3 axle spacings when adding a axle', () => { + const originalAxleSpacings = [ + { axles: '1-2', value: 100 }, + { axles: '2-3', value: 200 }, + ]; + + const result = service.generateAxleSpacing(4, originalAxleSpacings); + + expect(result).toStrictEqual([ + { axles: '1-2', value: 100 }, + { axles: '2-3', value: 200 }, + { axles: '3-4', value: null }, + ]); + }); + }); + + describe('generateAxles', () => { + it('should generate 3 axles from no previous data', () => { + const result = service.generateAxlesFromAxleSpacings(2); + + expect(result).toHaveLength(3); + expect(result[0]?.axleNumber).toBe(1); + expect(result[2]?.axleNumber).toBe(3); + }); + + it('should generate 3 axles from 1 previous axle', () => { + const previousAxles = [{ axleNumber: 1 }]; + const result = service.generateAxlesFromAxleSpacings(2, previousAxles); + + expect(result).toHaveLength(3); + expect(result[0]?.axleNumber).toBe(1); + expect(result[2]?.axleNumber).toBe(3); + }); + }); }); diff --git a/src/app/services/axles/axles.service.ts b/src/app/services/axles/axles.service.ts index 5626a7765e..3e2bfc27c3 100644 --- a/src/app/services/axles/axles.service.ts +++ b/src/app/services/axles/axles.service.ts @@ -1,70 +1,63 @@ import { Injectable } from '@angular/core'; -import { - Axle, AxleSpacing, Axles, Empty, -} from '@models/vehicle-tech-record.model'; +import { Axle, AxleSpacing, Axles, Empty } from '@models/vehicle-tech-record.model'; import cloneDeep from 'lodash.clonedeep'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class AxlesService { - normaliseAxles( - axles?: Axles, - axleSpacings?: AxleSpacing[], - ): [Axles | undefined, AxleSpacing[] | undefined] { - let newAxles = cloneDeep(axles ?? []); - let newAxleSpacings = cloneDeep(axleSpacings ?? []); - - if (newAxles.length > newAxleSpacings.length + 1) { - newAxleSpacings = this.generateAxleSpacing(newAxles.length, newAxleSpacings); - } else if (newAxles.length < newAxleSpacings.length + 1 && newAxles.length) { - newAxles = this.generateAxlesFromAxleSpacings(newAxleSpacings.length, newAxles); - } - - newAxles.sort((a, b) => (a.axleNumber ?? 0) - (b.axleNumber ?? 0)); - - return [newAxles, newAxleSpacings]; - } - - generateAxleSpacing(numberOfAxles: number, axleSpacingOriginal?: AxleSpacing[]): AxleSpacing[] { - const axleSpacing: AxleSpacing[] = []; - - let axleNumber = 1; - while (axleNumber < numberOfAxles) { - axleSpacing.push({ - axles: `${axleNumber}-${axleNumber + 1}`, - value: axleSpacingOriginal && axleSpacingOriginal[axleNumber - 1] ? axleSpacingOriginal[axleNumber - 1].value : null, - }); - axleNumber++; - } - - return axleSpacing; - } - - generateAxlesFromAxleSpacings( - vehicleAxleSpacingsLength: number, - previousAxles?: Empty[], - ): Empty[] { - const axles = previousAxles ?? []; - - for (let i = axles.length; i < vehicleAxleSpacingsLength + 1; i++) { - axles.push(this.generateEmptyAxle(i + 1)); - } - - return axles; - } - - generateEmptyAxle(axleNumber: number): Empty & { axleNumber?: number } { - return { - axleNumber, - weights_gbWeight: null, - weights_eecWeight: null, - weights_designWeight: null, - tyres_tyreSize: null, - tyres_fitmentCode: null, - tyres_dataTrAxles: null, - tyres_plyRating: null, - tyres_tyreCode: null, - }; - } + normaliseAxles(axles?: Axles, axleSpacings?: AxleSpacing[]): [Axles | undefined, AxleSpacing[] | undefined] { + let newAxles = cloneDeep(axles ?? []); + let newAxleSpacings = cloneDeep(axleSpacings ?? []); + + if (newAxles.length > newAxleSpacings.length + 1) { + newAxleSpacings = this.generateAxleSpacing(newAxles.length, newAxleSpacings); + } else if (newAxles.length < newAxleSpacings.length + 1 && newAxles.length) { + newAxles = this.generateAxlesFromAxleSpacings(newAxleSpacings.length, newAxles); + } + + newAxles.sort((a, b) => (a.axleNumber ?? 0) - (b.axleNumber ?? 0)); + + return [newAxles, newAxleSpacings]; + } + + generateAxleSpacing(numberOfAxles: number, axleSpacingOriginal?: AxleSpacing[]): AxleSpacing[] { + const axleSpacing: AxleSpacing[] = []; + + let axleNumber = 1; + while (axleNumber < numberOfAxles) { + axleSpacing.push({ + axles: `${axleNumber}-${axleNumber + 1}`, + value: + axleSpacingOriginal && axleSpacingOriginal[axleNumber - 1] ? axleSpacingOriginal[axleNumber - 1].value : null, + }); + axleNumber++; + } + + return axleSpacing; + } + + generateAxlesFromAxleSpacings(vehicleAxleSpacingsLength: number, previousAxles?: Empty[]): Empty[] { + const axles = previousAxles ?? []; + + for (let i = axles.length; i < vehicleAxleSpacingsLength + 1; i++) { + axles.push(this.generateEmptyAxle(i + 1)); + } + + return axles; + } + + generateEmptyAxle(axleNumber: number): Empty & { axleNumber?: number } { + return { + axleNumber, + weights_gbWeight: null, + weights_eecWeight: null, + weights_designWeight: null, + tyres_tyreSize: null, + tyres_fitmentCode: null, + tyres_dataTrAxles: null, + tyres_plyRating: null, + tyres_tyreCode: null, + }; + } } diff --git a/src/app/services/batch-technical-record/batch-technical-record.service.spec.ts b/src/app/services/batch-technical-record/batch-technical-record.service.spec.ts index 7abfbcfb76..4b477fd789 100644 --- a/src/app/services/batch-technical-record/batch-technical-record.service.spec.ts +++ b/src/app/services/batch-technical-record/batch-technical-record.service.spec.ts @@ -1,8 +1,6 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; -import { - AbstractControl, FormControl, FormGroup, ValidationErrors, -} from '@angular/forms'; +import { AbstractControl, FormControl, FormGroup, ValidationErrors } from '@angular/forms'; import { RouterTestingModule } from '@angular/router/testing'; import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; import { CustomFormControl, FormNodeTypes } from '@forms/services/dynamic-form.types'; @@ -15,198 +13,220 @@ import { Observable, firstValueFrom, of } from 'rxjs'; import { BatchTechnicalRecordService } from './batch-technical-record.service'; describe('TechnicalRecordService', () => { - let service: BatchTechnicalRecordService; - let httpClient: HttpTestingController; - let technicalRecordHttpService: TechnicalRecordHttpService; - let technicalRecordService: TechnicalRecordService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule], - providers: [ - BatchTechnicalRecordService, - provideMockStore({ initialState: initialAppState }), - TechnicalRecordHttpService, - TechnicalRecordService, - ], - }); - httpClient = TestBed.inject(HttpTestingController); - service = TestBed.inject(BatchTechnicalRecordService); - technicalRecordHttpService = TestBed.inject(TechnicalRecordHttpService); - technicalRecordService = TestBed.inject(TechnicalRecordService); - }); - - afterEach(() => { - // After every test, assert that there are no more pending requests. - httpClient.verify(); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('validateForBatch', () => { - let testGroup: FormGroup; - beforeEach(() => { - testGroup = new FormGroup({ - vin: new CustomFormControl({ name: 'vin', type: FormNodeTypes.CONTROL }, null, null), - trailerIdOrVrm: new FormControl({ name: 'trailerIdOrVrm', value: '' }, null), - systemNumber: new FormControl({ name: 'systemNumber', value: '' }, null), - oldVehicleStatus: new FormControl({ name: 'oldVehicleStatus', value: '' }, null), - vehicleType: new FormControl({ name: 'vehicleType', value: '' }, null), - createdTimestamp: new FormControl({ name: 'createdTimestamp', value: '' }, null), - }); - }); - - it('return null if vin and trailer id are not provided', (done) => { - expect.assertions(1); - testGroup.get('vin')?.setValue(null); - testGroup.get('trailerIdOrVrm')?.setValue(null); - const serviceCall = service.validateForBatch()(testGroup.get('vin') as AbstractControl); - (serviceCall as Observable).subscribe((errors) => { - expect(errors).toBeNull(); - done(); - }); - }); - - it('return null if the required controls do not exist', (done) => { - expect.assertions(1); - testGroup = new FormGroup({ vin: new FormControl({ name: 'vin' }) }); - const serviceCall = service.validateForBatch()(testGroup.get('vin') as AbstractControl); - (serviceCall as Observable).subscribe((errors) => { - expect(errors).toBeNull(); - done(); - }); - }); - - it('throws an error if trailer id is provided but vin is not', (done) => { - expect.assertions(1); - testGroup.get('trailerIdOrVrm')?.setValue('test'); - - const serviceCall = service.validateForBatch()(testGroup.get('vin') as AbstractControl); - (serviceCall as Observable).subscribe((errors) => { - expect(errors).toEqual({ validateForBatch: { message: 'VIN is required' } }); - done(); - }); - }); - - describe('when only vin is provided', () => { - it('should return null when it is a unique vin', async () => { - testGroup.get('trailerIdOrVrm')?.setValue(''); - testGroup.get('vin')?.setValue('TESTVIN'); - - const isUniqueSpy = jest.spyOn(technicalRecordService, 'isUnique').mockReturnValueOnce(of(true)); - - const serviceCall = service.validateForBatch()(testGroup.get('vin') as AbstractControl) as Observable; - const errors = await firstValueFrom(serviceCall); - expect(isUniqueSpy).toHaveBeenCalled(); - expect(errors).toBeNull(); - }); - - it('should set a warning when it is not a unique vin', async () => { - testGroup.get('trailerIdOrVrm')?.setValue(''); - const vinControl = testGroup.get('vin') as CustomFormControl; - vinControl.setValue('TESTVIN'); - jest.spyOn(technicalRecordService, 'isUnique').mockReturnValueOnce(of(false)); - await firstValueFrom(service.validateForBatch()(testGroup.get('vin') as AbstractControl) as Observable); - expect(vinControl.meta.warning).toBe('This VIN already exists, if you continue it will be associated with two vehicles'); - }); - }); - - describe('when both vin and trailer id are provided', () => { - it('returns null if only 1 vehicle exists with those values with no current tech record', async () => { - expect.assertions(1); - testGroup.get('vin')?.setValue('TESTVIN'); - testGroup.get('trailerIdOrVrm')?.setValue('TESTTRAILERID'); - const mockSearchResult = { - vin: 'TESTVIN', - trailerId: 'TESTTRAILERID', - systemNumber: 'TESTSYSTEMNUMBER', - techRecord_statusCode: StatusCodes.PROVISIONAL, - createdTimestamp: '1234', - } as TechRecordSearchSchema; - - jest.spyOn(technicalRecordHttpService, 'search$').mockReturnValue(of([mockSearchResult])); - - const serviceCall = service.validateForBatch()(testGroup.get('vin') as AbstractControl) as Observable; - const errors = await firstValueFrom(serviceCall); - expect(errors).toBeNull(); - }); - - it('throws error if only 1 trailer exists with those values with a current tech record', async () => { - expect.assertions(1); - testGroup.get('vin')?.setValue('TESTVIN'); - testGroup.get('trailerIdOrVrm')?.setValue('TESTTRAILERID'); - testGroup.get('vehicleType')?.setValue(VehicleTypes.TRL); - const mockSearchResult = { - vin: 'TESTVIN', - trailerId: 'TESTTRAILERID', - systemNumber: 'TESTSYSTEMNUMBER', - techRecord_statusCode: StatusCodes.CURRENT, - techRecord_vehicleType: VehicleTypes.TRL, - } as TechRecordSearchSchema; - - jest.spyOn(technicalRecordHttpService, 'search$').mockReturnValue(of([mockSearchResult])); - - const serviceCall = service.validateForBatch()(testGroup.get('vin') as AbstractControl) as Observable; - const errors = await firstValueFrom(serviceCall); - expect(errors).toEqual({ validateForBatch: { message: 'This record cannot be updated as it has a current tech record' } }); - }); - - it('returns null if only 1 vehicle other than trailer exists with those values with a current tech record', async () => { - expect.assertions(1); - testGroup.get('vin')?.setValue('TESTVIN'); - testGroup.get('trailerIdOrVrm')?.setValue('TESTTRAILERID'); - const mockSearchResult = { - vin: '1234', - trailerId: 'TESTTRAILERID', - systemNumber: 'TESTSYSTEMNUMBER', - techRecord_statusCode: StatusCodes.CURRENT, - techRecord_vehicleType: VehicleTypes.PSV, - createdTimestamp: '1234', - } as TechRecordSearchSchema; - - jest.spyOn(technicalRecordHttpService, 'search$').mockReturnValue(of([mockSearchResult])); - - const serviceCall = service.validateForBatch()(testGroup.get('vin') as AbstractControl) as Observable; - const errors = await firstValueFrom(serviceCall); - expect(errors).toBeNull(); - }); - - it('throws an error if more than 1 vehicle exists with those values', async () => { - expect.assertions(1); - testGroup.get('vin')?.setValue('TESTVIN'); - testGroup.get('trailerIdOrVrm')?.setValue('TESTTRAILERID'); - const mockSearchResult = { - vin: 'TESTVIN', - trailerId: 'TESTTRAILERID', - techRecord_statusCode: StatusCodes.PROVISIONAL, - } as TechRecordSearchSchema; - - jest.spyOn(technicalRecordHttpService, 'search$').mockReturnValue(of([mockSearchResult, { ...mockSearchResult, systemNumber: 'foobar' }])); - - const errors = await firstValueFrom( - service.validateForBatch()(testGroup.get('vin') as AbstractControl) as Observable, - ); - expect(errors).toEqual({ validateForBatch: { message: 'More than one vehicle has this VIN and VRM/Trailer ID' } }); - }); - }); - - it('throws an error if no vehicle exists with those values', async () => { - expect.assertions(1); - - const vinControl = testGroup.get('vin'); - const trailerIdOrVrmControl = testGroup.get('trailerIdOrVrm'); - - if (vinControl && trailerIdOrVrmControl) { - vinControl.setValue('TESTVIN'); - trailerIdOrVrmControl.setValue('TESTTRAILERID'); - } - - jest.spyOn(technicalRecordHttpService, 'search$').mockReturnValue(of([])); - - const errors = await firstValueFrom(service.validateForBatch()(testGroup.get('vin') as AbstractControl) as Observable); - expect(errors).toEqual({ validateForBatch: { message: 'Could not find a record with matching VIN and VRM/Trailer ID' } }); - }); - }); + let service: BatchTechnicalRecordService; + let httpClient: HttpTestingController; + let technicalRecordHttpService: TechnicalRecordHttpService; + let technicalRecordService: TechnicalRecordService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule, RouterTestingModule], + providers: [ + BatchTechnicalRecordService, + provideMockStore({ initialState: initialAppState }), + TechnicalRecordHttpService, + TechnicalRecordService, + ], + }); + httpClient = TestBed.inject(HttpTestingController); + service = TestBed.inject(BatchTechnicalRecordService); + technicalRecordHttpService = TestBed.inject(TechnicalRecordHttpService); + technicalRecordService = TestBed.inject(TechnicalRecordService); + }); + + afterEach(() => { + // After every test, assert that there are no more pending requests. + httpClient.verify(); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + describe('validateForBatch', () => { + let testGroup: FormGroup; + beforeEach(() => { + testGroup = new FormGroup({ + vin: new CustomFormControl({ name: 'vin', type: FormNodeTypes.CONTROL }, null, null), + trailerIdOrVrm: new FormControl({ name: 'trailerIdOrVrm', value: '' }, null), + systemNumber: new FormControl({ name: 'systemNumber', value: '' }, null), + oldVehicleStatus: new FormControl({ name: 'oldVehicleStatus', value: '' }, null), + vehicleType: new FormControl({ name: 'vehicleType', value: '' }, null), + createdTimestamp: new FormControl({ name: 'createdTimestamp', value: '' }, null), + }); + }); + + it('return null if vin and trailer id are not provided', (done) => { + expect.assertions(1); + testGroup.get('vin')?.setValue(null); + testGroup.get('trailerIdOrVrm')?.setValue(null); + const serviceCall = service.validateForBatch()(testGroup.get('vin') as AbstractControl); + (serviceCall as Observable).subscribe((errors) => { + expect(errors).toBeNull(); + done(); + }); + }); + + it('return null if the required controls do not exist', (done) => { + expect.assertions(1); + testGroup = new FormGroup({ vin: new FormControl({ name: 'vin' }) }); + const serviceCall = service.validateForBatch()(testGroup.get('vin') as AbstractControl); + (serviceCall as Observable).subscribe((errors) => { + expect(errors).toBeNull(); + done(); + }); + }); + + it('throws an error if trailer id is provided but vin is not', (done) => { + expect.assertions(1); + testGroup.get('trailerIdOrVrm')?.setValue('test'); + + const serviceCall = service.validateForBatch()(testGroup.get('vin') as AbstractControl); + (serviceCall as Observable).subscribe((errors) => { + expect(errors).toEqual({ validateForBatch: { message: 'VIN is required' } }); + done(); + }); + }); + + describe('when only vin is provided', () => { + it('should return null when it is a unique vin', async () => { + testGroup.get('trailerIdOrVrm')?.setValue(''); + testGroup.get('vin')?.setValue('TESTVIN'); + + const isUniqueSpy = jest.spyOn(technicalRecordService, 'isUnique').mockReturnValueOnce(of(true)); + + const serviceCall = service.validateForBatch()( + testGroup.get('vin') as AbstractControl + ) as Observable; + const errors = await firstValueFrom(serviceCall); + expect(isUniqueSpy).toHaveBeenCalled(); + expect(errors).toBeNull(); + }); + + it('should set a warning when it is not a unique vin', async () => { + testGroup.get('trailerIdOrVrm')?.setValue(''); + const vinControl = testGroup.get('vin') as CustomFormControl; + vinControl.setValue('TESTVIN'); + jest.spyOn(technicalRecordService, 'isUnique').mockReturnValueOnce(of(false)); + await firstValueFrom( + service.validateForBatch()(testGroup.get('vin') as AbstractControl) as Observable + ); + expect(vinControl.meta.warning).toBe( + 'This VIN already exists, if you continue it will be associated with two vehicles' + ); + }); + }); + + describe('when both vin and trailer id are provided', () => { + it('returns null if only 1 vehicle exists with those values with no current tech record', async () => { + expect.assertions(1); + testGroup.get('vin')?.setValue('TESTVIN'); + testGroup.get('trailerIdOrVrm')?.setValue('TESTTRAILERID'); + const mockSearchResult = { + vin: 'TESTVIN', + trailerId: 'TESTTRAILERID', + systemNumber: 'TESTSYSTEMNUMBER', + techRecord_statusCode: StatusCodes.PROVISIONAL, + createdTimestamp: '1234', + } as TechRecordSearchSchema; + + jest.spyOn(technicalRecordHttpService, 'search$').mockReturnValue(of([mockSearchResult])); + + const serviceCall = service.validateForBatch()( + testGroup.get('vin') as AbstractControl + ) as Observable; + const errors = await firstValueFrom(serviceCall); + expect(errors).toBeNull(); + }); + + it('throws error if only 1 trailer exists with those values with a current tech record', async () => { + expect.assertions(1); + testGroup.get('vin')?.setValue('TESTVIN'); + testGroup.get('trailerIdOrVrm')?.setValue('TESTTRAILERID'); + testGroup.get('vehicleType')?.setValue(VehicleTypes.TRL); + const mockSearchResult = { + vin: 'TESTVIN', + trailerId: 'TESTTRAILERID', + systemNumber: 'TESTSYSTEMNUMBER', + techRecord_statusCode: StatusCodes.CURRENT, + techRecord_vehicleType: VehicleTypes.TRL, + } as TechRecordSearchSchema; + + jest.spyOn(technicalRecordHttpService, 'search$').mockReturnValue(of([mockSearchResult])); + + const serviceCall = service.validateForBatch()( + testGroup.get('vin') as AbstractControl + ) as Observable; + const errors = await firstValueFrom(serviceCall); + expect(errors).toEqual({ + validateForBatch: { message: 'This record cannot be updated as it has a current tech record' }, + }); + }); + + it('returns null if only 1 vehicle other than trailer exists with those values with a current tech record', async () => { + expect.assertions(1); + testGroup.get('vin')?.setValue('TESTVIN'); + testGroup.get('trailerIdOrVrm')?.setValue('TESTTRAILERID'); + const mockSearchResult = { + vin: '1234', + trailerId: 'TESTTRAILERID', + systemNumber: 'TESTSYSTEMNUMBER', + techRecord_statusCode: StatusCodes.CURRENT, + techRecord_vehicleType: VehicleTypes.PSV, + createdTimestamp: '1234', + } as TechRecordSearchSchema; + + jest.spyOn(technicalRecordHttpService, 'search$').mockReturnValue(of([mockSearchResult])); + + const serviceCall = service.validateForBatch()( + testGroup.get('vin') as AbstractControl + ) as Observable; + const errors = await firstValueFrom(serviceCall); + expect(errors).toBeNull(); + }); + + it('throws an error if more than 1 vehicle exists with those values', async () => { + expect.assertions(1); + testGroup.get('vin')?.setValue('TESTVIN'); + testGroup.get('trailerIdOrVrm')?.setValue('TESTTRAILERID'); + const mockSearchResult = { + vin: 'TESTVIN', + trailerId: 'TESTTRAILERID', + techRecord_statusCode: StatusCodes.PROVISIONAL, + } as TechRecordSearchSchema; + + jest + .spyOn(technicalRecordHttpService, 'search$') + .mockReturnValue(of([mockSearchResult, { ...mockSearchResult, systemNumber: 'foobar' }])); + + const errors = await firstValueFrom( + service.validateForBatch()(testGroup.get('vin') as AbstractControl) as Observable + ); + expect(errors).toEqual({ + validateForBatch: { message: 'More than one vehicle has this VIN and VRM/Trailer ID' }, + }); + }); + }); + + it('throws an error if no vehicle exists with those values', async () => { + expect.assertions(1); + + const vinControl = testGroup.get('vin'); + const trailerIdOrVrmControl = testGroup.get('trailerIdOrVrm'); + + if (vinControl && trailerIdOrVrmControl) { + vinControl.setValue('TESTVIN'); + trailerIdOrVrmControl.setValue('TESTTRAILERID'); + } + + jest.spyOn(technicalRecordHttpService, 'search$').mockReturnValue(of([])); + + const errors = await firstValueFrom( + service.validateForBatch()(testGroup.get('vin') as AbstractControl) as Observable + ); + expect(errors).toEqual({ + validateForBatch: { message: 'Could not find a record with matching VIN and VRM/Trailer ID' }, + }); + }); + }); }); diff --git a/src/app/services/batch-technical-record/batch-technical-record.service.ts b/src/app/services/batch-technical-record/batch-technical-record.service.ts index 7a34016b41..2f11df8021 100644 --- a/src/app/services/batch-technical-record/batch-technical-record.service.ts +++ b/src/app/services/batch-technical-record/batch-technical-record.service.ts @@ -1,194 +1,196 @@ import { Injectable } from '@angular/core'; import { AbstractControl, AsyncValidatorFn, ValidationErrors } from '@angular/forms'; import { CustomFormControl } from '@forms/services/dynamic-form.types'; +import { SEARCH_TYPES } from '@models/search-types-enum'; import { StatusCodes, VehicleTypes } from '@models/vehicle-tech-record.model'; import { Store, select } from '@ngrx/store'; import { TechnicalRecordHttpService } from '@services/technical-record-http/technical-record-http.service'; -import { SEARCH_TYPES } from '@models/search-types-enum'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { updateEditingTechRecordCancel } from '@store/technical-records'; import { - clearBatch, - setApplicationId, - setGenerateNumberFlag, - setVehicleStatus, - setVehicleType, - upsertVehicleBatch, + clearBatch, + setApplicationId, + setGenerateNumberFlag, + setVehicleStatus, + setVehicleType, + upsertVehicleBatch, } from '@store/technical-records/actions/batch-create.actions'; import { BatchRecord } from '@store/technical-records/reducers/batch-create.reducer'; import { - selectAllBatch, - selectApplicationId, - selectBatchCount, - selectBatchCreatedCount, - selectBatchCreatedSuccessCount, - selectBatchSuccess, - selectBatchSuccessCount, - selectBatchUpdatedCount, - selectBatchUpdatedSuccessCount, - selectGenerateNumber, - selectIsBatch, - selectVehicleStatus, - selectVehicleType, + selectAllBatch, + selectApplicationId, + selectBatchCount, + selectBatchCreatedCount, + selectBatchCreatedSuccessCount, + selectBatchSuccess, + selectBatchSuccessCount, + selectBatchUpdatedCount, + selectBatchUpdatedSuccessCount, + selectGenerateNumber, + selectIsBatch, + selectVehicleStatus, + selectVehicleType, } from '@store/technical-records/selectors/batch-create.selectors'; -import { - Observable, - catchError, - map, - of, -} from 'rxjs'; +import { Observable, catchError, map, of } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class BatchTechnicalRecordService { - constructor( - private store: Store, - private techRecordHttpService: TechnicalRecordHttpService, - private technicalRecordService: TechnicalRecordService, - ) {} - - validateForBatch(): AsyncValidatorFn { - return (control: AbstractControl): Observable => { - const trailerIdOrVrmControl = control.parent?.get('trailerIdOrVrm') as CustomFormControl; - const vinControl = control.parent?.get('vin') as CustomFormControl; - const systemNumberControl = control.parent?.get('systemNumber') as CustomFormControl; - const createdTimeStampControl = control.parent?.get('createdTimestamp') as CustomFormControl; - - if (trailerIdOrVrmControl && vinControl) { - const trailerIdOrVrm = trailerIdOrVrmControl.value; - const vin = vinControl.value; - delete vinControl.meta.warning; - - if (trailerIdOrVrm && vin) { - return this.validateVinAndTrailerIdOrVrm(vin, trailerIdOrVrm, systemNumberControl, createdTimeStampControl); - } if (!trailerIdOrVrm && vin) { - return this.validateVinForBatch(vinControl); - } if (trailerIdOrVrm && !vin) { - return of({ validateForBatch: { message: 'VIN is required' } }); - } - } - return of(null); - }; - } - - private validateVinAndTrailerIdOrVrm( - vin: string, - trailerIdOrVrm: string, - systemNumberControl: CustomFormControl, - createdTimestampControl: CustomFormControl, - ): Observable { - return this.techRecordHttpService.search$(SEARCH_TYPES.VIN, vin).pipe( - map((result) => { - const recordsWithTrailerIdOrVrm = result.filter( - (vehicleTechRecord) => vehicleTechRecord.trailerId === trailerIdOrVrm || vehicleTechRecord.primaryVrm === trailerIdOrVrm, - ); - if (!recordsWithTrailerIdOrVrm.length) { - return { validateForBatch: { message: 'Could not find a record with matching VIN and VRM/Trailer ID' } }; - } - if (new Set(recordsWithTrailerIdOrVrm.map((record) => record.systemNumber)).size > 1) { - return { validateForBatch: { message: 'More than one vehicle has this VIN and VRM/Trailer ID' } }; - } - if ( - recordsWithTrailerIdOrVrm.find( - (techRecord) => techRecord.techRecord_statusCode === StatusCodes.CURRENT && techRecord.techRecord_vehicleType === VehicleTypes.TRL, - ) - ) { - return { validateForBatch: { message: 'This record cannot be updated as it has a current tech record' } }; - } - systemNumberControl.setValue(result[0].systemNumber); - const techRecordToUpdate = recordsWithTrailerIdOrVrm.find((techRecord) => techRecord.techRecord_statusCode !== StatusCodes.ARCHIVED); - createdTimestampControl.setValue(techRecordToUpdate?.createdTimestamp); - return null; - }), - catchError(() => of({ validateForBatch: { message: 'Could not find a record with matching VIN' } })), - ); - } - - private validateVinForBatch(vinControl: CustomFormControl): Observable { - return this.technicalRecordService.isUnique(vinControl.value, SEARCH_TYPES.VIN).pipe( - map((result) => { - if (!result) { - vinControl.meta.warning = 'This VIN already exists, if you continue it will be associated with two vehicles'; - } - return null; - }), - catchError(() => of(null)), - ); - } - - upsertVehicleBatch(vehicles: Array<{ vin: string; trailerId?: string; primaryVrm?: string }>) { - this.store.dispatch(upsertVehicleBatch({ vehicles })); - } - - clearEditingTechRecord() { - this.store.dispatch(updateEditingTechRecordCancel()); - } - - setApplicationId(applicationId: string) { - this.store.dispatch(setApplicationId({ applicationId })); - } - setGenerateNumberFlag(generateNumber: boolean) { - this.store.dispatch(setGenerateNumberFlag({ generateNumber })); - } - setVehicleStatus(vehicleStatus: string) { - this.store.dispatch(setVehicleStatus({ vehicleStatus })); - } - setVehicleType(vehicleType: VehicleTypes) { - this.store.dispatch(setVehicleType({ vehicleType })); - } - - clearBatch() { - this.store.dispatch(clearBatch()); - } - - get batchVehicles$(): Observable { - return this.store.pipe(select(selectAllBatch)); - } - - get batchVehiclesSuccess$(): Observable { - return this.store.pipe(select(selectBatchSuccess)); - } - - get isBatchCreate$(): Observable { - return this.store.pipe(select(selectIsBatch)); - } - - get batchCount$(): Observable { - return this.store.pipe(select(selectBatchCount)); - } - - get batchSuccessCount$(): Observable { - return this.store.pipe(select(selectBatchSuccessCount)); - } - - get batchCreatedCount$(): Observable { - return this.store.pipe(select(selectBatchCreatedSuccessCount)); - } - - get batchTotalCreatedCount$(): Observable { - return this.store.pipe(select(selectBatchCreatedCount)); - } - - get batchUpdatedCount$(): Observable { - return this.store.pipe(select(selectBatchUpdatedSuccessCount)); - } - - get batchTotalUpdatedCount$(): Observable { - return this.store.pipe(select(selectBatchUpdatedCount)); - } - - get applicationId$(): Observable { - return this.store.pipe(select(selectApplicationId)); - } - - get vehicleStatus$(): Observable { - return this.store.pipe(select(selectVehicleStatus)); - } - - get vehicleType$(): Observable { - return this.store.pipe(select(selectVehicleType)); - } - - get generateNumber$(): Observable { - return this.store.pipe(select(selectGenerateNumber)); - } + constructor( + private store: Store, + private techRecordHttpService: TechnicalRecordHttpService, + private technicalRecordService: TechnicalRecordService + ) {} + + validateForBatch(): AsyncValidatorFn { + return (control: AbstractControl): Observable => { + const trailerIdOrVrmControl = control.parent?.get('trailerIdOrVrm') as CustomFormControl; + const vinControl = control.parent?.get('vin') as CustomFormControl; + const systemNumberControl = control.parent?.get('systemNumber') as CustomFormControl; + const createdTimeStampControl = control.parent?.get('createdTimestamp') as CustomFormControl; + + if (trailerIdOrVrmControl && vinControl) { + const trailerIdOrVrm = trailerIdOrVrmControl.value; + const vin = vinControl.value; + delete vinControl.meta.warning; + + if (trailerIdOrVrm && vin) { + return this.validateVinAndTrailerIdOrVrm(vin, trailerIdOrVrm, systemNumberControl, createdTimeStampControl); + } + if (!trailerIdOrVrm && vin) { + return this.validateVinForBatch(vinControl); + } + if (trailerIdOrVrm && !vin) { + return of({ validateForBatch: { message: 'VIN is required' } }); + } + } + return of(null); + }; + } + + private validateVinAndTrailerIdOrVrm( + vin: string, + trailerIdOrVrm: string, + systemNumberControl: CustomFormControl, + createdTimestampControl: CustomFormControl + ): Observable { + return this.techRecordHttpService.search$(SEARCH_TYPES.VIN, vin).pipe( + map((result) => { + const recordsWithTrailerIdOrVrm = result.filter( + (vehicleTechRecord) => + vehicleTechRecord.trailerId === trailerIdOrVrm || vehicleTechRecord.primaryVrm === trailerIdOrVrm + ); + if (!recordsWithTrailerIdOrVrm.length) { + return { validateForBatch: { message: 'Could not find a record with matching VIN and VRM/Trailer ID' } }; + } + if (new Set(recordsWithTrailerIdOrVrm.map((record) => record.systemNumber)).size > 1) { + return { validateForBatch: { message: 'More than one vehicle has this VIN and VRM/Trailer ID' } }; + } + if ( + recordsWithTrailerIdOrVrm.find( + (techRecord) => + techRecord.techRecord_statusCode === StatusCodes.CURRENT && + techRecord.techRecord_vehicleType === VehicleTypes.TRL + ) + ) { + return { validateForBatch: { message: 'This record cannot be updated as it has a current tech record' } }; + } + systemNumberControl.setValue(result[0].systemNumber); + const techRecordToUpdate = recordsWithTrailerIdOrVrm.find( + (techRecord) => techRecord.techRecord_statusCode !== StatusCodes.ARCHIVED + ); + createdTimestampControl.setValue(techRecordToUpdate?.createdTimestamp); + return null; + }), + catchError(() => of({ validateForBatch: { message: 'Could not find a record with matching VIN' } })) + ); + } + + private validateVinForBatch(vinControl: CustomFormControl): Observable { + return this.technicalRecordService.isUnique(vinControl.value, SEARCH_TYPES.VIN).pipe( + map((result) => { + if (!result) { + vinControl.meta.warning = 'This VIN already exists, if you continue it will be associated with two vehicles'; + } + return null; + }), + catchError(() => of(null)) + ); + } + + upsertVehicleBatch(vehicles: Array<{ vin: string; trailerId?: string; primaryVrm?: string }>) { + this.store.dispatch(upsertVehicleBatch({ vehicles })); + } + + clearEditingTechRecord() { + this.store.dispatch(updateEditingTechRecordCancel()); + } + + setApplicationId(applicationId: string) { + this.store.dispatch(setApplicationId({ applicationId })); + } + setGenerateNumberFlag(generateNumber: boolean) { + this.store.dispatch(setGenerateNumberFlag({ generateNumber })); + } + setVehicleStatus(vehicleStatus: string) { + this.store.dispatch(setVehicleStatus({ vehicleStatus })); + } + setVehicleType(vehicleType: VehicleTypes) { + this.store.dispatch(setVehicleType({ vehicleType })); + } + + clearBatch() { + this.store.dispatch(clearBatch()); + } + + get batchVehicles$(): Observable { + return this.store.pipe(select(selectAllBatch)); + } + + get batchVehiclesSuccess$(): Observable { + return this.store.pipe(select(selectBatchSuccess)); + } + + get isBatchCreate$(): Observable { + return this.store.pipe(select(selectIsBatch)); + } + + get batchCount$(): Observable { + return this.store.pipe(select(selectBatchCount)); + } + + get batchSuccessCount$(): Observable { + return this.store.pipe(select(selectBatchSuccessCount)); + } + + get batchCreatedCount$(): Observable { + return this.store.pipe(select(selectBatchCreatedSuccessCount)); + } + + get batchTotalCreatedCount$(): Observable { + return this.store.pipe(select(selectBatchCreatedCount)); + } + + get batchUpdatedCount$(): Observable { + return this.store.pipe(select(selectBatchUpdatedSuccessCount)); + } + + get batchTotalUpdatedCount$(): Observable { + return this.store.pipe(select(selectBatchUpdatedCount)); + } + + get applicationId$(): Observable { + return this.store.pipe(select(selectApplicationId)); + } + + get vehicleStatus$(): Observable { + return this.store.pipe(select(selectVehicleStatus)); + } + + get vehicleType$(): Observable { + return this.store.pipe(select(selectVehicleType)); + } + + get generateNumber$(): Observable { + return this.store.pipe(select(selectGenerateNumber)); + } } diff --git a/src/app/services/defects/defects.service.spec.ts b/src/app/services/defects/defects.service.spec.ts index 377716317a..7b318c9a55 100644 --- a/src/app/services/defects/defects.service.spec.ts +++ b/src/app/services/defects/defects.service.spec.ts @@ -6,92 +6,92 @@ import { environment } from '../../../environments/environment'; import { DefectsService } from './defects.service'; describe('DefectsService', () => { - let service: DefectsService; - let httpTestingController: HttpTestingController; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - }); - - httpTestingController = TestBed.inject(HttpTestingController); - service = TestBed.inject(DefectsService); - }); - - afterEach(() => { - // After every test, assert that there are no more pending requests. - httpTestingController.verify(); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('fetchDefects', () => { - it('should get an array of matching results', () => { - const expectedResult = [{ imDescription: 'Some Description' } as Defect]; - service.fetchDefects().subscribe((response) => expect(response).toEqual(expectedResult)); - - // Check for correct requests: should have made one request to search from expected URL - const req = httpTestingController.expectOne(`${environment.VTM_API_URI}/defects`); - expect(req.request.method).toBe('GET'); - - // Provide each request with a mock response - req.flush(expectedResult); - }); - - it('should handle errors', (done) => { - service.fetchDefects().subscribe({ - next: () => {}, - error: (e) => { - expect(e.error).toBe('Deliberate 500 error'); - expect(e.status).toBe(500); - expect(e.statusText).toBe('Server Error'); - done(); - }, - }); - - // Check for correct requests: should have made one request to search from expected URL - const req = httpTestingController.expectOne(`${environment.VTM_API_URI}/defects`); - expect(req.request.method).toBe('GET'); - - // Respond with mock error - req.flush('Deliberate 500 error', { status: 500, statusText: 'Server Error' }); - }); - }); - - describe('fetchDefect', () => { - it('should get a matching result', () => { - const expectedId = 1; - const expectedResult = { imDescription: 'Some Description' } as Defect; - service.fetchDefect(expectedId).subscribe((response) => expect(response).toEqual(expectedResult)); - - // Check for correct requests: should have made one request to search from expected URL - const req = httpTestingController.expectOne(`${environment.VTM_API_URI}/defects/${expectedId}`); - expect(req.request.method).toBe('GET'); - - // Provide each request with a mock response - req.flush(expectedResult); - }); - - it('should handle errors', (done) => { - const expectedId = 1; - service.fetchDefect(expectedId).subscribe({ - next: () => {}, - error: (e) => { - expect(e.error).toBe('Deliberate 500 error'); - expect(e.status).toBe(500); - expect(e.statusText).toBe('Server Error'); - done(); - }, - }); - - // Check for correct requests: should have made one request to search from expected URL - const req = httpTestingController.expectOne(`${environment.VTM_API_URI}/defects/${expectedId}`); - expect(req.request.method).toBe('GET'); - - // Respond with mock error - req.flush('Deliberate 500 error', { status: 500, statusText: 'Server Error' }); - }); - }); + let service: DefectsService; + let httpTestingController: HttpTestingController; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + }); + + httpTestingController = TestBed.inject(HttpTestingController); + service = TestBed.inject(DefectsService); + }); + + afterEach(() => { + // After every test, assert that there are no more pending requests. + httpTestingController.verify(); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + describe('fetchDefects', () => { + it('should get an array of matching results', () => { + const expectedResult = [{ imDescription: 'Some Description' } as Defect]; + service.fetchDefects().subscribe((response) => expect(response).toEqual(expectedResult)); + + // Check for correct requests: should have made one request to search from expected URL + const req = httpTestingController.expectOne(`${environment.VTM_API_URI}/defects`); + expect(req.request.method).toBe('GET'); + + // Provide each request with a mock response + req.flush(expectedResult); + }); + + it('should handle errors', (done) => { + service.fetchDefects().subscribe({ + next: () => {}, + error: (e) => { + expect(e.error).toBe('Deliberate 500 error'); + expect(e.status).toBe(500); + expect(e.statusText).toBe('Server Error'); + done(); + }, + }); + + // Check for correct requests: should have made one request to search from expected URL + const req = httpTestingController.expectOne(`${environment.VTM_API_URI}/defects`); + expect(req.request.method).toBe('GET'); + + // Respond with mock error + req.flush('Deliberate 500 error', { status: 500, statusText: 'Server Error' }); + }); + }); + + describe('fetchDefect', () => { + it('should get a matching result', () => { + const expectedId = 1; + const expectedResult = { imDescription: 'Some Description' } as Defect; + service.fetchDefect(expectedId).subscribe((response) => expect(response).toEqual(expectedResult)); + + // Check for correct requests: should have made one request to search from expected URL + const req = httpTestingController.expectOne(`${environment.VTM_API_URI}/defects/${expectedId}`); + expect(req.request.method).toBe('GET'); + + // Provide each request with a mock response + req.flush(expectedResult); + }); + + it('should handle errors', (done) => { + const expectedId = 1; + service.fetchDefect(expectedId).subscribe({ + next: () => {}, + error: (e) => { + expect(e.error).toBe('Deliberate 500 error'); + expect(e.status).toBe(500); + expect(e.statusText).toBe('Server Error'); + done(); + }, + }); + + // Check for correct requests: should have made one request to search from expected URL + const req = httpTestingController.expectOne(`${environment.VTM_API_URI}/defects/${expectedId}`); + expect(req.request.method).toBe('GET'); + + // Respond with mock error + req.flush('Deliberate 500 error', { status: 500, statusText: 'Server Error' }); + }); + }); }); diff --git a/src/app/services/defects/defects.service.ts b/src/app/services/defects/defects.service.ts index 737ebcfee3..06f66c4114 100644 --- a/src/app/services/defects/defects.service.ts +++ b/src/app/services/defects/defects.service.ts @@ -6,15 +6,15 @@ import { environment } from '../../../environments/environment'; @Injectable({ providedIn: 'root' }) export class DefectsService { - private url = `${environment.VTM_API_URI}/defects`; + private url = `${environment.VTM_API_URI}/defects`; - constructor(private http: HttpClient) {} + constructor(private http: HttpClient) {} - fetchDefects(): Observable { - return this.http.get(this.url, { responseType: 'json' }); - } + fetchDefects(): Observable { + return this.http.get(this.url, { responseType: 'json' }); + } - fetchDefect(id: number): Observable { - return this.http.get(`${this.url}/${id}`, { responseType: 'json' }); - } + fetchDefect(id: number): Observable { + return this.http.get(`${this.url}/${id}`, { responseType: 'json' }); + } } diff --git a/src/app/services/documents/documents.service.spec.ts b/src/app/services/documents/documents.service.spec.ts index daf77764fd..2aa993f966 100644 --- a/src/app/services/documents/documents.service.spec.ts +++ b/src/app/services/documents/documents.service.spec.ts @@ -9,80 +9,80 @@ const responseBody = 'Response body'; const domParser = new DOMParser(); const fakeAnchor = domParser - .parseFromString('', 'text/html') - .querySelector('a'); + .parseFromString('', 'text/html') + .querySelector('a'); describe('DocumentsService', () => { - let service: DocumentsService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(DocumentsService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('openDocumentFromResponse', () => { - it('should download a document sent back from a http response', () => { - const convertToBlobSpy = jest.spyOn(service, 'convertToBlob'); - const createFileLinkSpy = jest.spyOn(service, 'createFileLink'); - const simulateClickSpy = jest.spyOn(service, 'simulateClick'); - - service.openDocumentFromResponse(fileName, responseBody); - - expect(convertToBlobSpy).toHaveBeenCalledWith(responseBody, 'pdf'); - expect(createFileLinkSpy).toHaveBeenCalledWith(fileName, new Blob(), 'pdf'); - expect(simulateClickSpy).toHaveBeenCalledWith(fakeAnchor); - }); - - it('should download a document sent back with a signed url', () => { - const convertToBlobSpy = jest.spyOn(service, 'convertToBlob'); - const createFileLinkSpy = jest.spyOn(service, 'createFileLink'); - const simulateClickSpy = jest.spyOn(service, 'simulateClick'); - - const fakeAnchorZip = domParser - .parseFromString('', 'text/html') - .querySelector('a'); - - service.openDocumentFromResponse(fileName, responseBody, 'zip'); - - expect(convertToBlobSpy).not.toHaveBeenCalled(); - expect(createFileLinkSpy).not.toHaveBeenCalled(); - expect(simulateClickSpy).toHaveBeenCalledWith(fakeAnchorZip); - }); - }); - - describe('convertToBlob', () => { - it('should throw an error if the data provided is not a string', () => { - expect(service.convertToBlob.bind(0)).toThrow(); - expect(service.convertToBlob.bind(null)).toThrow(); - expect(service.convertToBlob.bind(undefined)).toThrow(); - }); - - it('should return a blob of type application/pdf based on the string provided', () => { - expect(service.convertToBlob('')).toEqual(new Blob()); - }); - }); - - describe('createFileLink', () => { - it('should create a downloadable anchor link for a pdf file, using the file name and blob provided', () => { - expect(service.createFileLink(fileName, new Blob(), 'pdf')).toEqual(fakeAnchor); - }); - }); - - describe('simulateClick', () => { - it('should add the downloadable pdf anchor element to the DOM, programmatically click it, then remove it', () => { - const appendChildSpy = jest.spyOn(document.body, 'appendChild'); - const clickSpy = jest.spyOn(fakeAnchor as HTMLAnchorElement, 'click'); - const removeChildSpy = jest.spyOn(document.body, 'removeChild'); - - service.simulateClick(fakeAnchor as HTMLAnchorElement); - - expect(appendChildSpy).toHaveBeenCalled(); - expect(clickSpy).toHaveBeenCalled(); - expect(removeChildSpy).toHaveBeenCalled(); - }); - }); + let service: DocumentsService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(DocumentsService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + describe('openDocumentFromResponse', () => { + it('should download a document sent back from a http response', () => { + const convertToBlobSpy = jest.spyOn(service, 'convertToBlob'); + const createFileLinkSpy = jest.spyOn(service, 'createFileLink'); + const simulateClickSpy = jest.spyOn(service, 'simulateClick'); + + service.openDocumentFromResponse(fileName, responseBody); + + expect(convertToBlobSpy).toHaveBeenCalledWith(responseBody, 'pdf'); + expect(createFileLinkSpy).toHaveBeenCalledWith(fileName, new Blob(), 'pdf'); + expect(simulateClickSpy).toHaveBeenCalledWith(fakeAnchor); + }); + + it('should download a document sent back with a signed url', () => { + const convertToBlobSpy = jest.spyOn(service, 'convertToBlob'); + const createFileLinkSpy = jest.spyOn(service, 'createFileLink'); + const simulateClickSpy = jest.spyOn(service, 'simulateClick'); + + const fakeAnchorZip = domParser + .parseFromString('', 'text/html') + .querySelector('a'); + + service.openDocumentFromResponse(fileName, responseBody, 'zip'); + + expect(convertToBlobSpy).not.toHaveBeenCalled(); + expect(createFileLinkSpy).not.toHaveBeenCalled(); + expect(simulateClickSpy).toHaveBeenCalledWith(fakeAnchorZip); + }); + }); + + describe('convertToBlob', () => { + it('should throw an error if the data provided is not a string', () => { + expect(service.convertToBlob.bind(0)).toThrow(); + expect(service.convertToBlob.bind(null)).toThrow(); + expect(service.convertToBlob.bind(undefined)).toThrow(); + }); + + it('should return a blob of type application/pdf based on the string provided', () => { + expect(service.convertToBlob('')).toEqual(new Blob()); + }); + }); + + describe('createFileLink', () => { + it('should create a downloadable anchor link for a pdf file, using the file name and blob provided', () => { + expect(service.createFileLink(fileName, new Blob(), 'pdf')).toEqual(fakeAnchor); + }); + }); + + describe('simulateClick', () => { + it('should add the downloadable pdf anchor element to the DOM, programmatically click it, then remove it', () => { + const appendChildSpy = jest.spyOn(document.body, 'appendChild'); + const clickSpy = jest.spyOn(fakeAnchor as HTMLAnchorElement, 'click'); + const removeChildSpy = jest.spyOn(document.body, 'removeChild'); + + service.simulateClick(fakeAnchor as HTMLAnchorElement); + + expect(appendChildSpy).toHaveBeenCalled(); + expect(clickSpy).toHaveBeenCalled(); + expect(removeChildSpy).toHaveBeenCalled(); + }); + }); }); diff --git a/src/app/services/documents/documents.service.ts b/src/app/services/documents/documents.service.ts index 9338e2ca51..84eb99ee51 100644 --- a/src/app/services/documents/documents.service.ts +++ b/src/app/services/documents/documents.service.ts @@ -2,54 +2,53 @@ import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class DocumentsService { - openDocumentFromResponse(fileName: string, responseBody: unknown, fileType: string = 'pdf'): void { - if (fileType === 'zip') { - const link: HTMLAnchorElement = document.createElement('a'); + openDocumentFromResponse(fileName: string, responseBody: unknown, fileType = 'pdf'): void { + if (fileType === 'zip') { + const link: HTMLAnchorElement = document.createElement('a'); - link.href = (responseBody as string).toString(); - link.download = `${fileName}.${fileType}`; + link.href = (responseBody as string).toString(); + link.download = `${fileName}.${fileType}`; - this.simulateClick(link); - } else { - const blob = this.convertToBlob(responseBody, fileType); + this.simulateClick(link); + } else { + const blob = this.convertToBlob(responseBody, fileType); - const link = this.createFileLink(fileName, blob, fileType); + const link = this.createFileLink(fileName, blob, fileType); - this.simulateClick(link); - } + this.simulateClick(link); + } + } - } + convertToBlob(data: unknown, fileType?: string): Blob { + if (typeof data !== 'string') throw new Error('Cannot convert to a blob. Data needs to be of type string'); - convertToBlob(data: unknown, fileType?: string): Blob { - if (typeof data !== 'string') throw new Error('Cannot convert to a blob. Data needs to be of type string'); + const byteArray = new Uint8Array( + window + .atob(data) + .split('') + .map((char) => char.charCodeAt(0)) + ); - const byteArray = new Uint8Array( - window - .atob(data) - .split('') - .map((char) => char.charCodeAt(0)), - ); + return new Blob([byteArray], { type: `application/${fileType}; charset=utf-8` }); + } - return new Blob([byteArray], { type: `application/${fileType}; charset=utf-8` }); - } + createFileLink(fileName: string, blob: Blob, fileType?: string): HTMLAnchorElement { + const url = window.URL.createObjectURL(blob); - createFileLink(fileName: string, blob: Blob, fileType?: string): HTMLAnchorElement { - const url = window.URL.createObjectURL(blob); + const link: HTMLAnchorElement = document.createElement('a'); - const link: HTMLAnchorElement = document.createElement('a'); + link.href = url; + link.target = '_blank'; + link.download = `${fileName}.${fileType}`; - link.href = url; - link.target = '_blank'; - link.download = `${fileName}.${fileType}`; + return link; + } - return link; - } + simulateClick(link: HTMLAnchorElement): void { + document.body.appendChild(link); - simulateClick(link: HTMLAnchorElement): void { - document.body.appendChild(link); + link.click(); - link.click(); - - document.body.removeChild(link); - } + document.body.removeChild(link); + } } diff --git a/src/app/services/feature-toggle-service/feature-toggle-service.spec.ts b/src/app/services/feature-toggle-service/feature-toggle-service.spec.ts index b6777c472b..5e257424d2 100644 --- a/src/app/services/feature-toggle-service/feature-toggle-service.spec.ts +++ b/src/app/services/feature-toggle-service/feature-toggle-service.spec.ts @@ -3,92 +3,92 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/ import { TestBed } from '@angular/core/testing'; import { Store } from '@ngrx/store'; import { of } from 'rxjs'; -import { FeatureToggleService } from './feature-toggle-service'; import { environment } from '../../../environments/environment'; +import { FeatureToggleService } from './feature-toggle-service'; describe('feature toggle service', () => { - let service: FeatureToggleService; - let httpClient: HttpClient; + let service: FeatureToggleService; + let httpClient: HttpClient; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [Store, FeatureToggleService], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [Store, FeatureToggleService], + }); - httpClient = TestBed.inject(HttpClient); - TestBed.inject(HttpTestingController); - service = TestBed.inject(FeatureToggleService); - }); + httpClient = TestBed.inject(HttpClient); + TestBed.inject(HttpTestingController); + service = TestBed.inject(FeatureToggleService); + }); - it('should create the user service', () => { - expect(service).toBeTruthy(); - }); + it('should create the user service', () => { + expect(service).toBeTruthy(); + }); - describe('loadConfig', () => { - it('should create the config from a http request', async () => { - service.configPath = 'test/path.json'; + describe('loadConfig', () => { + it('should create the config from a http request', async () => { + service.configPath = 'test/path.json'; - const expectedConfig = { - testToggle: 'true', - }; + const expectedConfig = { + testToggle: 'true', + }; - jest.spyOn(httpClient, 'get').mockReturnValueOnce(of(expectedConfig)); + jest.spyOn(httpClient, 'get').mockReturnValueOnce(of(expectedConfig)); - await service.loadConfig(); + await service.loadConfig(); - expect(service.config).toBeTruthy(); - expect(service.config).toEqual(expectedConfig); - }); - }); + expect(service.config).toBeTruthy(); + expect(service.config).toEqual(expectedConfig); + }); + }); - describe('getConfig', () => { - it('should return the correct feature toggle config', () => { - environment.TARGET_ENV = 'dev'; - expect(service.getConfig()).toBe('assets/featureToggle.json'); + describe('getConfig', () => { + it('should return the correct feature toggle config', () => { + environment.TARGET_ENV = 'dev'; + expect(service.getConfig()).toBe('assets/featureToggle.json'); - environment.TARGET_ENV = 'undefined'; - expect(service.getConfig()).toBe('assets/featureToggle.json'); + environment.TARGET_ENV = 'undefined'; + expect(service.getConfig()).toBe('assets/featureToggle.json'); - environment.TARGET_ENV = 'integration'; - expect(service.getConfig()).toBe('assets/featureToggle.int.json'); + environment.TARGET_ENV = 'integration'; + expect(service.getConfig()).toBe('assets/featureToggle.int.json'); - environment.TARGET_ENV = 'preprod'; - expect(service.getConfig()).toBe('assets/featureToggle.preprod.json'); + environment.TARGET_ENV = 'preprod'; + expect(service.getConfig()).toBe('assets/featureToggle.preprod.json'); - environment.TARGET_ENV = 'prod'; - expect(service.getConfig()).toBe('assets/featureToggle.prod.json'); - }); - }); + environment.TARGET_ENV = 'prod'; + expect(service.getConfig()).toBe('assets/featureToggle.prod.json'); + }); + }); - describe('isFeatureEnabled', () => { - it('should return false if there is no config', () => { - service.config = null; - const result = service.isFeatureEnabled('testToggle'); - expect(result).toBeFalsy(); - }); - it('should return false if the key is not in the config', () => { - service.config = { - randomKey: false, - }; - const result = service.isFeatureEnabled('testToggle'); - expect(result).toBeFalsy(); - }); - it('should return false if the key is in the config but is set to false', () => { - service.config = { - randomKey: false, - testToggle: false, - }; - const result = service.isFeatureEnabled('testToggle'); - expect(result).toBeFalsy(); - }); - it('should return true if the key is in the config but is set to false so should be hidden', () => { - service.config = { - randomKey: false, - testToggle: true, - }; - const result = service.isFeatureEnabled('testToggle'); - expect(result).toBeTruthy(); - }); - }); + describe('isFeatureEnabled', () => { + it('should return false if there is no config', () => { + service.config = null; + const result = service.isFeatureEnabled('testToggle'); + expect(result).toBeFalsy(); + }); + it('should return false if the key is not in the config', () => { + service.config = { + randomKey: false, + }; + const result = service.isFeatureEnabled('testToggle'); + expect(result).toBeFalsy(); + }); + it('should return false if the key is in the config but is set to false', () => { + service.config = { + randomKey: false, + testToggle: false, + }; + const result = service.isFeatureEnabled('testToggle'); + expect(result).toBeFalsy(); + }); + it('should return true if the key is in the config but is set to false so should be hidden', () => { + service.config = { + randomKey: false, + testToggle: true, + }; + const result = service.isFeatureEnabled('testToggle'); + expect(result).toBeTruthy(); + }); + }); }); diff --git a/src/app/services/feature-toggle-service/feature-toggle-service.ts b/src/app/services/feature-toggle-service/feature-toggle-service.ts index b0bd080d0d..21c930a63a 100644 --- a/src/app/services/feature-toggle-service/feature-toggle-service.ts +++ b/src/app/services/feature-toggle-service/feature-toggle-service.ts @@ -5,41 +5,40 @@ import { lastValueFrom, take } from 'rxjs'; import { environment } from '../../../environments/environment'; export interface FeatureConfig { - [key:string]:boolean; + [key: string]: boolean; } @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class FeatureToggleService { - config: FeatureConfig | null = null; - configPath = this.getConfig(); + config: FeatureConfig | null = null; + configPath = this.getConfig(); - constructor(private http: HttpClient) {} + constructor(private http: HttpClient) {} - async loadConfig() { - // eslint-disable-next-line no-return-assign - return this.config = await lastValueFrom(this.http.get(this.configPath).pipe(take(1))); - } + async loadConfig() { + // eslint-disable-next-line no-return-assign + return (this.config = await lastValueFrom(this.http.get(this.configPath).pipe(take(1)))); + } - getConfig() { - switch (environment.TARGET_ENV) { - case 'prod': - return 'assets/featureToggle.prod.json'; - case 'integration': - return 'assets/featureToggle.int.json'; - case 'preprod': - return 'assets/featureToggle.preprod.json'; - default: - return 'assets/featureToggle.json'; - } - } - - isFeatureEnabled(key: string) { - if (this.config && has(this.config, key)) { - return get(this.config, key, false); - } - return false; - } + getConfig() { + switch (environment.TARGET_ENV) { + case 'prod': + return 'assets/featureToggle.prod.json'; + case 'integration': + return 'assets/featureToggle.int.json'; + case 'preprod': + return 'assets/featureToggle.preprod.json'; + default: + return 'assets/featureToggle.json'; + } + } + isFeatureEnabled(key: string) { + if (this.config && has(this.config, key)) { + return get(this.config, key, false); + } + return false; + } } diff --git a/src/app/services/loading/loading.service.spec.ts b/src/app/services/loading/loading.service.spec.ts index dfad671222..e973318133 100644 --- a/src/app/services/loading/loading.service.spec.ts +++ b/src/app/services/loading/loading.service.spec.ts @@ -1,7 +1,7 @@ import { TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; -import { initialAppState, State } from '@store/.'; +import { State, initialAppState } from '@store/.'; import { getSpinner } from '@store/spinner/selectors/spinner.selectors'; import { technicalRecordsLoadingState } from '@store/technical-records'; import { testResultLoadingState } from '@store/test-records'; @@ -12,59 +12,59 @@ import { SpinnerComponent } from '../../core/components/spinner/spinner.componen import { LoadingService } from './loading.service'; describe('Spinner-Service', () => { - let service: LoadingService; - let mockStore: MockStore; + let service: LoadingService; + let mockStore: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [SpinnerComponent], - imports: [RouterTestingModule], - providers: [LoadingService, provideMockStore({ initialState: initialAppState })], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [SpinnerComponent], + imports: [RouterTestingModule], + providers: [LoadingService, provideMockStore({ initialState: initialAppState })], + }); - service = TestBed.inject(LoadingService); - mockStore = TestBed.inject(MockStore); - }); + service = TestBed.inject(LoadingService); + mockStore = TestBed.inject(MockStore); + }); - it('should create the spinner service', () => { - expect(service).toBeTruthy(); - }); + it('should create the spinner service', () => { + expect(service).toBeTruthy(); + }); - describe('showSpinner$', () => { - beforeEach(() => { - mockStore.resetSelectors(); - }); + describe('showSpinner$', () => { + beforeEach(() => { + mockStore.resetSelectors(); + }); - it('Should return false when global spinner, testResult and technicalRecords loading state is false', async () => { - mockStore.overrideSelector(getSpinner, false); - mockStore.overrideSelector(testResultLoadingState, false); - mockStore.overrideSelector(technicalRecordsLoadingState, false); - expect(await firstValueFrom(service.showSpinner$.pipe(take(1)))).toBeFalsy(); - }); + it('Should return false when global spinner, testResult and technicalRecords loading state is false', async () => { + mockStore.overrideSelector(getSpinner, false); + mockStore.overrideSelector(testResultLoadingState, false); + mockStore.overrideSelector(technicalRecordsLoadingState, false); + expect(await firstValueFrom(service.showSpinner$.pipe(take(1)))).toBeFalsy(); + }); - it('Should return true when global spinner state is true', async () => { - mockStore.overrideSelector(getSpinner, true); - expect(await firstValueFrom(service.showSpinner$.pipe(take(1)))).toBeTruthy(); - }); + it('Should return true when global spinner state is true', async () => { + mockStore.overrideSelector(getSpinner, true); + expect(await firstValueFrom(service.showSpinner$.pipe(take(1)))).toBeTruthy(); + }); - it('Should return true when testResult loading state is true', async () => { - mockStore.overrideSelector(testResultLoadingState, true); - expect(await firstValueFrom(service.showSpinner$.pipe(take(1)))).toBeTruthy(); - }); + it('Should return true when testResult loading state is true', async () => { + mockStore.overrideSelector(testResultLoadingState, true); + expect(await firstValueFrom(service.showSpinner$.pipe(take(1)))).toBeTruthy(); + }); - it('Should return true when TechnicalRecords loading state is true', async () => { - mockStore.overrideSelector(technicalRecordsLoadingState, true); - expect(await firstValueFrom(service.showSpinner$.pipe(take(1)))).toBeTruthy(); - }); + it('Should return true when TechnicalRecords loading state is true', async () => { + mockStore.overrideSelector(technicalRecordsLoadingState, true); + expect(await firstValueFrom(service.showSpinner$.pipe(take(1)))).toBeTruthy(); + }); - it('Should return true when testTypes loading state is true', async () => { - mockStore.overrideSelector(selectTestTypesLoadingState, true); - expect(await firstValueFrom(service.showSpinner$.pipe(take(1)))).toBeTruthy(); - }); + it('Should return true when testTypes loading state is true', async () => { + mockStore.overrideSelector(selectTestTypesLoadingState, true); + expect(await firstValueFrom(service.showSpinner$.pipe(take(1)))).toBeTruthy(); + }); - it('Should return true when test stations loading state is true', async () => { - mockStore.overrideSelector(testStationsLoadingState, true); - expect(await firstValueFrom(service.showSpinner$.pipe(take(1)))).toBeTruthy(); - }); - }); + it('Should return true when test stations loading state is true', async () => { + mockStore.overrideSelector(testStationsLoadingState, true); + expect(await firstValueFrom(service.showSpinner$.pipe(take(1)))).toBeTruthy(); + }); + }); }); diff --git a/src/app/services/loading/loading.service.ts b/src/app/services/loading/loading.service.ts index 6a62e419d4..a0a573f442 100644 --- a/src/app/services/loading/loading.service.ts +++ b/src/app/services/loading/loading.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core'; -import { select, Store } from '@ngrx/store'; +import { Store, select } from '@ngrx/store'; import { defectsLoadingState } from '@store/defects'; import { referenceDataLoadingState } from '@store/reference-data'; import { requiredStandardsLoadingState } from '@store/required-standards/selectors/required-standards.selector'; @@ -9,39 +9,39 @@ import { technicalRecordsLoadingState } from '@store/technical-records'; import { testResultLoadingState } from '@store/test-records'; import { testStationsLoadingState } from '@store/test-stations'; import { selectTestTypesLoadingState } from '@store/test-types/selectors/test-types.selectors'; -import { combineLatest, map, Observable } from 'rxjs'; +import { Observable, combineLatest, map } from 'rxjs'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class LoadingService { - globalLoadingState$: Observable = this.store.pipe(select(getSpinner)); - testResultLoadingState$: Observable = this.store.pipe(select(testResultLoadingState)); - techRecordsLoadingState$: Observable = this.store.pipe(select(technicalRecordsLoadingState)); - testTypesLoadingState$: Observable = this.store.pipe(select(selectTestTypesLoadingState)); - testStationsLoadingState$: Observable = this.store.pipe(select(testStationsLoadingState)); - defectsLoadingState$: Observable = this.store.pipe(select(defectsLoadingState)); - referenceDataLoadingState$: Observable = this.store.pipe(select(referenceDataLoadingState)); - techRecordSearchLoadingState$: Observable = this.store.pipe(select(selectTechRecordSearchLoadingState)); - requiredStandardsLoadingState$: Observable = this.store.pipe(select(requiredStandardsLoadingState)); + globalLoadingState$: Observable = this.store.pipe(select(getSpinner)); + testResultLoadingState$: Observable = this.store.pipe(select(testResultLoadingState)); + techRecordsLoadingState$: Observable = this.store.pipe(select(technicalRecordsLoadingState)); + testTypesLoadingState$: Observable = this.store.pipe(select(selectTestTypesLoadingState)); + testStationsLoadingState$: Observable = this.store.pipe(select(testStationsLoadingState)); + defectsLoadingState$: Observable = this.store.pipe(select(defectsLoadingState)); + referenceDataLoadingState$: Observable = this.store.pipe(select(referenceDataLoadingState)); + techRecordSearchLoadingState$: Observable = this.store.pipe(select(selectTechRecordSearchLoadingState)); + requiredStandardsLoadingState$: Observable = this.store.pipe(select(requiredStandardsLoadingState)); - constructor(private store: Store) {} + constructor(private store: Store) {} - private get reduceLoadingStates$() { - return combineLatest([ - this.globalLoadingState$, - this.testResultLoadingState$, - this.techRecordsLoadingState$, - this.testTypesLoadingState$, - this.testStationsLoadingState$, - this.defectsLoadingState$, - this.referenceDataLoadingState$, - this.techRecordSearchLoadingState$, - this.requiredStandardsLoadingState$, - ]).pipe(map((states) => states.some((b) => b))); - } + private get reduceLoadingStates$() { + return combineLatest([ + this.globalLoadingState$, + this.testResultLoadingState$, + this.techRecordsLoadingState$, + this.testTypesLoadingState$, + this.testStationsLoadingState$, + this.defectsLoadingState$, + this.referenceDataLoadingState$, + this.techRecordSearchLoadingState$, + this.requiredStandardsLoadingState$, + ]).pipe(map((states) => states.some((b) => b))); + } - get showSpinner$(): Observable { - return this.reduceLoadingStates$; - } + get showSpinner$(): Observable { + return this.reduceLoadingStates$; + } } diff --git a/src/app/services/reference-data/reference-data.service.spec.ts b/src/app/services/reference-data/reference-data.service.spec.ts index cc6fff2ae1..db229ec402 100644 --- a/src/app/services/reference-data/reference-data.service.spec.ts +++ b/src/app/services/reference-data/reference-data.service.spec.ts @@ -3,405 +3,415 @@ import { TestBed } from '@angular/core/testing'; import { ReferenceDataApiResponse, ReferenceDataItem } from '@api/reference-data'; import { MultiOptions } from '@forms/models/options.model'; import { - ReferenceDataModelBase, ReferenceDataResourceType, ReferenceDataTyre, User, + ReferenceDataModelBase, + ReferenceDataResourceType, + ReferenceDataTyre, + User, } from '@models/reference-data.model'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { UserService } from '@services/user-service/user-service'; import { initialAppState } from '@store/.'; import { - ReferenceDataEntityStateSearch, - STORE_FEATURE_REFERENCE_DATA_KEY, - addSearchInformation, - fetchReferenceData, - fetchReferenceDataByKeySearch, - fetchTyreReferenceDataByKeySearch, - initialReferenceDataState, - referencePsvMakeLoadingState, - removeTyreSearch, - selectTyreSearchCriteria, + ReferenceDataEntityStateSearch, + STORE_FEATURE_REFERENCE_DATA_KEY, + addSearchInformation, + fetchReferenceData, + fetchReferenceDataByKeySearch, + fetchTyreReferenceDataByKeySearch, + initialReferenceDataState, + referencePsvMakeLoadingState, + removeTyreSearch, + selectTyreSearchCriteria, } from '@store/reference-data'; import { testCases } from '@store/reference-data/reference-data.test-cases'; import { firstValueFrom, of, take } from 'rxjs'; import { ReferenceDataService } from './reference-data.service'; describe('ReferenceDataService', () => { - let service: ReferenceDataService; - let controller: HttpTestingController; - let store: MockStore; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - provideMockStore({ initialState: initialAppState }), - ReferenceDataService, - { provide: UserService, useValue: { id$: of('id'), name$: of('Jack') } }, - ], - }); - - service = TestBed.inject(ReferenceDataService); - controller = TestBed.inject(HttpTestingController); - store = TestBed.inject(MockStore); - - controller.verify(); - }); - - afterEach(() => { - store.refreshState(); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('API', () => { - describe('resourceTypes', () => { - it.each(testCases)('should return all data for a given resourceType', (value) => { - const apiResponse: ReferenceDataApiResponse = { data: value.payload }; - service.fetchReferenceData(value.resourceType).subscribe((response) => { - expect(response).toEqual(apiResponse); - }); - - const req = controller.expectOne('https://url/api/v1/reference/COUNTRY_OF_REGISTRATION'); - req.flush(apiResponse); - }); - }); - - it('should thrown an error if resource type is not given', (done) => { - service.fetchReferenceData(undefined as unknown as ReferenceDataResourceType).subscribe({ - error: (e) => { - expect(e.message).toBe('Reference data resourceType is required'); - done(); - }, - }); - }); - }); - - describe('fetchReferenceDataByKeySearch', () => { - it('should call the correct end point', () => { - const value = { - payload: [ - { - tyreCode: '123', - resourceType: ReferenceDataResourceType.Tyres, - resourceKey: '123', - code: '123', - loadIndexSingleLoad: '102', - tyreSize: 'size', - dateTimeStamp: 'time', - userId: '1234', - loadIndexTwinLoad: '101', - plyRating: '18', - }, - ], - }; - const apiResponse: ReferenceDataApiResponse = { data: value.payload }; - service.fetchReferenceDataByKeySearch(ReferenceDataResourceType.Tyres, '101').subscribe((data) => { - expect(data).toEqual(apiResponse); - }); - - const req = controller.expectOne('https://url/api/v1/reference/lookup/TYRES/101'); - req.flush(apiResponse); - }); - }); - - describe('fetchTyreReferenceDataByKeySearch', () => { - it('should call the correct end point', () => { - const value = { - payload: [ - { - tyreCode: '123', - resourceType: ReferenceDataResourceType.Tyres, - resourceKey: '123', - code: '123', - loadIndexSingleLoad: '102', - tyreSize: 'size', - dateTimeStamp: 'time', - userId: '1234', - loadIndexTwinLoad: '101', - plyRating: '18', - }, - ], - }; - const apiResponse: ReferenceDataApiResponse = { data: value.payload }; - service.fetchTyreReferenceDataByKeySearch('plyrating', '10').subscribe((data) => { - expect(data).toEqual(apiResponse); - }); - - const req = controller.expectOne('https://url/api/v1/reference/lookup/tyres/plyrating/10'); - req.flush(apiResponse); - }); - }); - - describe('resourceKeys', () => { - it.each(testCases)('should return one result for a given resourceType and resourceKey', (value) => { - const getOneFromResourceSpy = jest.spyOn(service, 'referenceResourceTypeResourceKeyGet'); - const { resourceType, resourceKey, payload } = value; - const resource = payload.find((p) => p.resourceKey === resourceKey) as ReferenceDataItem; - expect(resource).toBeDefined(); - const expectedResult: ReferenceDataApiResponse = { data: [resource] }; - - service.fetchReferenceDataByKey(resourceType, resourceKey).subscribe((response) => { - expect(response).toEqual(expectedResult); - expect(getOneFromResourceSpy).toHaveBeenCalled(); - }); - - const req = controller.expectOne('https://url/api/v1/reference/COUNTRY_OF_REGISTRATION/gb'); - req.flush(expectedResult); - }); - }); - describe('createReferenceDataItem', () => { - it('should return the created item', () => { - const resourceType = ReferenceDataResourceType.CountryOfRegistration; - const resourceKey = 'testKey'; - const item = { description: 'test Item' }; - const apiResponse = { resourceType, resourceKey, ...item }; - service.createReferenceDataItem(resourceType, resourceKey, item).subscribe((data) => { - expect(data).toEqual(item); - }); - - const req = controller.expectOne(`https://url/api/v1/reference/${resourceType}/${resourceKey}`); - expect(req.request.method).toBe('POST'); - - req.flush(apiResponse); - }); - }); - - describe('amendReferenceDataItem', () => { - it('should return the amended item', () => { - const resourceType = ReferenceDataResourceType.CountryOfRegistration; - const resourceKey = 'testKey'; - const item = { description: 'test Item' }; - const apiResponse = { resourceType, resourceKey, ...item }; - service.amendReferenceDataItem(resourceType, resourceKey, item).subscribe((data) => { - expect(data).toEqual(apiResponse); - }); - - const req = controller.expectOne(`https://url/api/v1/reference/${resourceType}/${resourceKey}`); - expect(req.request.method).toBe('PUT'); - - req.flush(apiResponse); - }); - }); - - describe('deleteReferenceDataItem', () => { - it('should return a delete item', () => { - const resourceType = ReferenceDataResourceType.CountryOfRegistration; - const resourceKey = 'testKey'; - const apiResponse = { success: 'true' }; - service.deleteReferenceDataItem(resourceType, resourceKey, { createdId: 'test' }).subscribe((data) => { - expect(data).toEqual(apiResponse); - }); - const req = controller.expectOne(`https://url/api/v1/reference/${resourceType}/${resourceKey}`); - expect(req.request.method).toBe('DELETE'); - - req.flush(apiResponse); - }); - }); - - describe('selectors', () => { - beforeEach(() => { - store.setState({ - ...initialAppState, - [STORE_FEATURE_REFERENCE_DATA_KEY]: { - ...initialReferenceDataState, - [ReferenceDataResourceType.CountryOfRegistration]: { - ids: ['gb', 'gba'], - entities: { - gb: { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'gb', - description: 'Great Britain and Northern Ireland - GB', - }, - gba: { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'gba', - description: 'Alderney - GBA', - }, - }, - }, - [ReferenceDataResourceType.ReasonsForAbandoningPsv]: { - ids: ['foobar'], - entities: { - foobar: { - resourceType: ReferenceDataResourceType.ReasonsForAbandoningPsv, - resourceKey: 'foobar', - }, - }, - }, - }, - }); - }); - - it('should get all of the reference data', (done) => { - service.getAll$(ReferenceDataResourceType.CountryOfRegistration).subscribe((response) => { - expect(response).toEqual([ - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'gb', - description: 'Great Britain and Northern Ireland - GB', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'gba', - description: 'Alderney - GBA', - }, - ]); - done(); - }); - }); - - it('should get a specific reference data record', (done) => { - service.getByKey$(ReferenceDataResourceType.CountryOfRegistration, 'gba').subscribe((response) => { - expect(response).toEqual({ - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'gba', - description: 'Alderney - GBA', - }); - done(); - }); - }); - - it('should get the tyre search results', (done) => { - const mockReferenceDataTyre = [{ code: 'foo' }] as ReferenceDataTyre[]; - jest.spyOn(service, 'getTyreSearchReturn$').mockReturnValue(of(mockReferenceDataTyre)); - service - .getTyreSearchReturn$() - .pipe(take(1)) - .subscribe((referenceData) => { - expect(referenceData).toEqual(mockReferenceDataTyre); - done(); - }); - }); - it('should get the tyre search criteria', (done) => { - const mockState = { loading: false } as ReferenceDataEntityStateSearch; - store.overrideSelector(selectTyreSearchCriteria, mockState); - service - .getTyreSearchCriteria$() - .pipe(take(1)) - .subscribe((referenceData) => { - expect(referenceData).toEqual(mockState); - done(); - }); - }); - it('should get the psv make reference data loading', (done) => { - store.overrideSelector(referencePsvMakeLoadingState, false); - service - .getReferencePsvMakeDataLoading$() - .pipe(take(1)) - .subscribe((loadingFlag) => { - expect(loadingFlag).toBe(false); - done(); - }); - }); - - it('should get the data from state and format the response', (done) => { - service - .getReferenceDataOptions(ReferenceDataResourceType.CountryOfRegistration) - .pipe(take(1)) - .subscribe((data) => { - expect(data).toEqual([ - { label: 'Great Britain and Northern Ireland - GB', value: 'gb' }, - { label: 'Alderney - GBA', value: 'gba' }, - ]); - done(); - }); - }); - it('should get the psv data from state and format the response', (done) => { - service - .getReasonsForAbandoning(VehicleTypes.PSV) - .pipe(take(1)) - .subscribe((data) => { - expect(data).toEqual([{ label: 'foobar', value: 'foobar' }]); - done(); - }); - }); - - it('should return if vehicle Type if undefined', (done) => { - service - .getReasonsForAbandoning(undefined) - .pipe(take(1)) - .subscribe((data) => { - expect(data).toEqual([]); - done(); - }); - }); - }); - - describe('helper function', () => { - describe('mapReferenceDataOptions', () => { - it.each([ - { - refData: [ - { - resourceType: ReferenceDataResourceType.Brakes, - resourceKey: 'banana', - description: 'yellow', - }, - ] as ReferenceDataModelBase[], - output: [{ label: 'yellow', value: 'banana' }] as MultiOptions, - }, - { - refData: [ - { - resourceType: ReferenceDataResourceType.User, - resourceKey: 'mike@mail.com', - name: 'Mike', - }, - ] as Array>, - output: [{ label: 'Mike', value: 'mike@mail.com' }], - }, - { - refData: [ - { - resourceType: ReferenceDataResourceType.User, - resourceKey: 'mike@mail.com', - }, - ] as Array>, - output: [{ label: 'mike@mail.com', value: 'mike@mail.com' }], - }, - ])('should return MultiOption Array with description as label', async ({ refData, output }) => { - const options = await firstValueFrom(of(refData).pipe(take(1), service['mapReferenceDataOptions'])); - expect(options).toEqual(output); - }); - }); - }); - - describe('search methods', () => { - describe('fetchReferenceDataByKeySearch', () => { - it('should dispatch the action to fetchReferenceDataByKeySearch', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.loadReferenceDataByKeySearch(ReferenceDataResourceType.CountryOfRegistration, 'foo'); - expect(dispatchSpy).toHaveBeenCalledWith( - fetchReferenceDataByKeySearch({ resourceType: ReferenceDataResourceType.CountryOfRegistration, resourceKey: 'foo' }), - ); - }); - }); - describe('loadTyreReferenceDataByKeySearch', () => { - it('should dispatch the action to loadTyreReferenceDataByKeySearch', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.loadTyreReferenceDataByKeySearch('foo', 'bar'); - expect(dispatchSpy).toHaveBeenCalledWith(fetchTyreReferenceDataByKeySearch({ searchFilter: 'foo', searchTerm: 'bar' })); - }); - }); - }); - - describe('store methods', () => { - it('should dispatch the fetchReferenceData action', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.loadReferenceData(ReferenceDataResourceType.CountryOfRegistration); - expect(dispatchSpy).toHaveBeenCalledWith(fetchReferenceData({ resourceType: ReferenceDataResourceType.CountryOfRegistration })); - }); - it('should dispatch the addSearchInformation action', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.addSearchInformation('foo', 'bar'); - expect(dispatchSpy).toHaveBeenCalledWith(addSearchInformation({ filter: 'foo', term: 'bar' })); - }); - it('should dispatch the removeTyreSearch action', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.removeTyreSearch(); - expect(dispatchSpy).toHaveBeenCalledWith(removeTyreSearch()); - }); - }); + let service: ReferenceDataService; + let controller: HttpTestingController; + let store: MockStore; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + provideMockStore({ initialState: initialAppState }), + ReferenceDataService, + { provide: UserService, useValue: { id$: of('id'), name$: of('Jack') } }, + ], + }); + + service = TestBed.inject(ReferenceDataService); + controller = TestBed.inject(HttpTestingController); + store = TestBed.inject(MockStore); + + controller.verify(); + }); + + afterEach(() => { + store.refreshState(); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + describe('API', () => { + describe('resourceTypes', () => { + it.each(testCases)('should return all data for a given resourceType', (value) => { + const apiResponse: ReferenceDataApiResponse = { data: value.payload }; + service.fetchReferenceData(value.resourceType).subscribe((response) => { + expect(response).toEqual(apiResponse); + }); + + const req = controller.expectOne('https://url/api/v1/reference/COUNTRY_OF_REGISTRATION'); + req.flush(apiResponse); + }); + }); + + it('should thrown an error if resource type is not given', (done) => { + service.fetchReferenceData(undefined as unknown as ReferenceDataResourceType).subscribe({ + error: (e) => { + expect(e.message).toBe('Reference data resourceType is required'); + done(); + }, + }); + }); + }); + + describe('fetchReferenceDataByKeySearch', () => { + it('should call the correct end point', () => { + const value = { + payload: [ + { + tyreCode: '123', + resourceType: ReferenceDataResourceType.Tyres, + resourceKey: '123', + code: '123', + loadIndexSingleLoad: '102', + tyreSize: 'size', + dateTimeStamp: 'time', + userId: '1234', + loadIndexTwinLoad: '101', + plyRating: '18', + }, + ], + }; + const apiResponse: ReferenceDataApiResponse = { data: value.payload }; + service.fetchReferenceDataByKeySearch(ReferenceDataResourceType.Tyres, '101').subscribe((data) => { + expect(data).toEqual(apiResponse); + }); + + const req = controller.expectOne('https://url/api/v1/reference/lookup/TYRES/101'); + req.flush(apiResponse); + }); + }); + + describe('fetchTyreReferenceDataByKeySearch', () => { + it('should call the correct end point', () => { + const value = { + payload: [ + { + tyreCode: '123', + resourceType: ReferenceDataResourceType.Tyres, + resourceKey: '123', + code: '123', + loadIndexSingleLoad: '102', + tyreSize: 'size', + dateTimeStamp: 'time', + userId: '1234', + loadIndexTwinLoad: '101', + plyRating: '18', + }, + ], + }; + const apiResponse: ReferenceDataApiResponse = { data: value.payload }; + service.fetchTyreReferenceDataByKeySearch('plyrating', '10').subscribe((data) => { + expect(data).toEqual(apiResponse); + }); + + const req = controller.expectOne('https://url/api/v1/reference/lookup/tyres/plyrating/10'); + req.flush(apiResponse); + }); + }); + + describe('resourceKeys', () => { + it.each(testCases)('should return one result for a given resourceType and resourceKey', (value) => { + const getOneFromResourceSpy = jest.spyOn(service, 'referenceResourceTypeResourceKeyGet'); + const { resourceType, resourceKey, payload } = value; + const resource = payload.find((p) => p.resourceKey === resourceKey) as ReferenceDataItem; + expect(resource).toBeDefined(); + const expectedResult: ReferenceDataApiResponse = { data: [resource] }; + + service.fetchReferenceDataByKey(resourceType, resourceKey).subscribe((response) => { + expect(response).toEqual(expectedResult); + expect(getOneFromResourceSpy).toHaveBeenCalled(); + }); + + const req = controller.expectOne('https://url/api/v1/reference/COUNTRY_OF_REGISTRATION/gb'); + req.flush(expectedResult); + }); + }); + describe('createReferenceDataItem', () => { + it('should return the created item', () => { + const resourceType = ReferenceDataResourceType.CountryOfRegistration; + const resourceKey = 'testKey'; + const item = { description: 'test Item' }; + const apiResponse = { resourceType, resourceKey, ...item }; + service.createReferenceDataItem(resourceType, resourceKey, item).subscribe((data) => { + expect(data).toEqual(item); + }); + + const req = controller.expectOne(`https://url/api/v1/reference/${resourceType}/${resourceKey}`); + expect(req.request.method).toBe('POST'); + + req.flush(apiResponse); + }); + }); + + describe('amendReferenceDataItem', () => { + it('should return the amended item', () => { + const resourceType = ReferenceDataResourceType.CountryOfRegistration; + const resourceKey = 'testKey'; + const item = { description: 'test Item' }; + const apiResponse = { resourceType, resourceKey, ...item }; + service.amendReferenceDataItem(resourceType, resourceKey, item).subscribe((data) => { + expect(data).toEqual(apiResponse); + }); + + const req = controller.expectOne(`https://url/api/v1/reference/${resourceType}/${resourceKey}`); + expect(req.request.method).toBe('PUT'); + + req.flush(apiResponse); + }); + }); + + describe('deleteReferenceDataItem', () => { + it('should return a delete item', () => { + const resourceType = ReferenceDataResourceType.CountryOfRegistration; + const resourceKey = 'testKey'; + const apiResponse = { success: 'true' }; + service.deleteReferenceDataItem(resourceType, resourceKey, { createdId: 'test' }).subscribe((data) => { + expect(data).toEqual(apiResponse); + }); + const req = controller.expectOne(`https://url/api/v1/reference/${resourceType}/${resourceKey}`); + expect(req.request.method).toBe('DELETE'); + + req.flush(apiResponse); + }); + }); + + describe('selectors', () => { + beforeEach(() => { + store.setState({ + ...initialAppState, + [STORE_FEATURE_REFERENCE_DATA_KEY]: { + ...initialReferenceDataState, + [ReferenceDataResourceType.CountryOfRegistration]: { + ids: ['gb', 'gba'], + entities: { + gb: { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'gb', + description: 'Great Britain and Northern Ireland - GB', + }, + gba: { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'gba', + description: 'Alderney - GBA', + }, + }, + }, + [ReferenceDataResourceType.ReasonsForAbandoningPsv]: { + ids: ['foobar'], + entities: { + foobar: { + resourceType: ReferenceDataResourceType.ReasonsForAbandoningPsv, + resourceKey: 'foobar', + }, + }, + }, + }, + }); + }); + + it('should get all of the reference data', (done) => { + service.getAll$(ReferenceDataResourceType.CountryOfRegistration).subscribe((response) => { + expect(response).toEqual([ + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'gb', + description: 'Great Britain and Northern Ireland - GB', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'gba', + description: 'Alderney - GBA', + }, + ]); + done(); + }); + }); + + it('should get a specific reference data record', (done) => { + service.getByKey$(ReferenceDataResourceType.CountryOfRegistration, 'gba').subscribe((response) => { + expect(response).toEqual({ + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'gba', + description: 'Alderney - GBA', + }); + done(); + }); + }); + + it('should get the tyre search results', (done) => { + const mockReferenceDataTyre = [{ code: 'foo' }] as ReferenceDataTyre[]; + jest.spyOn(service, 'getTyreSearchReturn$').mockReturnValue(of(mockReferenceDataTyre)); + service + .getTyreSearchReturn$() + .pipe(take(1)) + .subscribe((referenceData) => { + expect(referenceData).toEqual(mockReferenceDataTyre); + done(); + }); + }); + it('should get the tyre search criteria', (done) => { + const mockState = { loading: false } as ReferenceDataEntityStateSearch; + store.overrideSelector(selectTyreSearchCriteria, mockState); + service + .getTyreSearchCriteria$() + .pipe(take(1)) + .subscribe((referenceData) => { + expect(referenceData).toEqual(mockState); + done(); + }); + }); + it('should get the psv make reference data loading', (done) => { + store.overrideSelector(referencePsvMakeLoadingState, false); + service + .getReferencePsvMakeDataLoading$() + .pipe(take(1)) + .subscribe((loadingFlag) => { + expect(loadingFlag).toBe(false); + done(); + }); + }); + + it('should get the data from state and format the response', (done) => { + service + .getReferenceDataOptions(ReferenceDataResourceType.CountryOfRegistration) + .pipe(take(1)) + .subscribe((data) => { + expect(data).toEqual([ + { label: 'Great Britain and Northern Ireland - GB', value: 'gb' }, + { label: 'Alderney - GBA', value: 'gba' }, + ]); + done(); + }); + }); + it('should get the psv data from state and format the response', (done) => { + service + .getReasonsForAbandoning(VehicleTypes.PSV) + .pipe(take(1)) + .subscribe((data) => { + expect(data).toEqual([{ label: 'foobar', value: 'foobar' }]); + done(); + }); + }); + + it('should return if vehicle Type if undefined', (done) => { + service + .getReasonsForAbandoning(undefined) + .pipe(take(1)) + .subscribe((data) => { + expect(data).toEqual([]); + done(); + }); + }); + }); + + describe('helper function', () => { + describe('mapReferenceDataOptions', () => { + it.each([ + { + refData: [ + { + resourceType: ReferenceDataResourceType.Brakes, + resourceKey: 'banana', + description: 'yellow', + }, + ] as ReferenceDataModelBase[], + output: [{ label: 'yellow', value: 'banana' }] as MultiOptions, + }, + { + refData: [ + { + resourceType: ReferenceDataResourceType.User, + resourceKey: 'mike@mail.com', + name: 'Mike', + }, + ] as Array>, + output: [{ label: 'Mike', value: 'mike@mail.com' }], + }, + { + refData: [ + { + resourceType: ReferenceDataResourceType.User, + resourceKey: 'mike@mail.com', + }, + ] as Array>, + output: [{ label: 'mike@mail.com', value: 'mike@mail.com' }], + }, + ])('should return MultiOption Array with description as label', async ({ refData, output }) => { + const options = await firstValueFrom(of(refData).pipe(take(1), service['mapReferenceDataOptions'])); + expect(options).toEqual(output); + }); + }); + }); + + describe('search methods', () => { + describe('fetchReferenceDataByKeySearch', () => { + it('should dispatch the action to fetchReferenceDataByKeySearch', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.loadReferenceDataByKeySearch(ReferenceDataResourceType.CountryOfRegistration, 'foo'); + expect(dispatchSpy).toHaveBeenCalledWith( + fetchReferenceDataByKeySearch({ + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'foo', + }) + ); + }); + }); + describe('loadTyreReferenceDataByKeySearch', () => { + it('should dispatch the action to loadTyreReferenceDataByKeySearch', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.loadTyreReferenceDataByKeySearch('foo', 'bar'); + expect(dispatchSpy).toHaveBeenCalledWith( + fetchTyreReferenceDataByKeySearch({ searchFilter: 'foo', searchTerm: 'bar' }) + ); + }); + }); + }); + + describe('store methods', () => { + it('should dispatch the fetchReferenceData action', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.loadReferenceData(ReferenceDataResourceType.CountryOfRegistration); + expect(dispatchSpy).toHaveBeenCalledWith( + fetchReferenceData({ resourceType: ReferenceDataResourceType.CountryOfRegistration }) + ); + }); + it('should dispatch the addSearchInformation action', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.addSearchInformation('foo', 'bar'); + expect(dispatchSpy).toHaveBeenCalledWith(addSearchInformation({ filter: 'foo', term: 'bar' })); + }); + it('should dispatch the removeTyreSearch action', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.removeTyreSearch(); + expect(dispatchSpy).toHaveBeenCalledWith(removeTyreSearch()); + }); + }); }); diff --git a/src/app/services/reference-data/reference-data.service.ts b/src/app/services/reference-data/reference-data.service.ts index dff54d4f24..5aef4fd692 100644 --- a/src/app/services/reference-data/reference-data.service.ts +++ b/src/app/services/reference-data/reference-data.service.ts @@ -1,192 +1,223 @@ import { HttpClient } from '@angular/common/http'; import { Inject, Injectable, Optional } from '@angular/core'; import { - BASE_PATH, - Configuration, - ReferenceDataApiResponse, - ReferenceDataService as ReferenceDataApiService, - ReferenceDataItemApiResponse, + BASE_PATH, + Configuration, + ReferenceDataApiResponse, + ReferenceDataService as ReferenceDataApiService, + ReferenceDataItemApiResponse, } from '@api/reference-data'; import { MultiOptions } from '@forms/models/options.model'; import { - ReferenceDataModelBase, ReferenceDataResourceType, ReferenceDataTyre, User, + ReferenceDataModelBase, + ReferenceDataResourceType, + ReferenceDataTyre, + User, } from '@models/reference-data.model'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { Store, select } from '@ngrx/store'; import { UserService } from '@services/user-service/user-service'; import { - ReferenceDataEntityStateSearch, - ReferenceDataState, - addSearchInformation, - fetchReferenceData, - fetchReferenceDataByKey, - fetchReferenceDataByKeySearch, - fetchTyreReferenceDataByKeySearch, - referencePsvMakeLoadingState, - removeReferenceDataByKey, - removeTyreSearch, - selectAllReferenceDataByResourceType, - selectReasonsForAbandoning, - selectReferenceDataByResourceKey, - selectSearchReturn, - selectTyreSearchCriteria, + ReferenceDataEntityStateSearch, + ReferenceDataState, + addSearchInformation, + fetchReferenceData, + fetchReferenceDataByKey, + fetchReferenceDataByKeySearch, + fetchTyreReferenceDataByKeySearch, + referencePsvMakeLoadingState, + removeReferenceDataByKey, + removeTyreSearch, + selectAllReferenceDataByResourceType, + selectReasonsForAbandoning, + selectReferenceDataByResourceKey, + selectSearchReturn, + selectTyreSearchCriteria, } from '@store/reference-data'; -import { - Observable, of, switchMap, throwError, withLatestFrom, -} from 'rxjs'; +import { Observable, of, switchMap, throwError, withLatestFrom } from 'rxjs'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class ReferenceDataService extends ReferenceDataApiService { - constructor( - @Optional() @Inject(BASE_PATH) basePath: string, - @Optional() configuration: Configuration, - httpClient: HttpClient, - private usersService: UserService, - private store: Store, - ) { - super(httpClient, basePath, configuration); - } - - // URL to POST new reference data items: /reference/{ type capitalized }/{ new key } POST - // eslint-disable-next-line @typescript-eslint/no-explicit-any - createReferenceDataItem(type: ReferenceDataResourceType, key: string, data: any) { - return this.usersService.id$.pipe( - withLatestFrom(this.usersService.name$), - switchMap(([createdId, createdName]) => { - const referenceData = { - ...data, createdId, createdName, createdAt: new Date(), - }; - return this.referenceResourceTypeResourceKeyPost(type, key, referenceData, 'body', false); - }), - ); - } - - // URL to PUT new reference data items: /reference/{ type capitalized }/{ new key } PUT - // eslint-disable-next-line @typescript-eslint/no-explicit-any - amendReferenceDataItem(type: ReferenceDataResourceType, key: string, data: any) { - return this.usersService.id$.pipe( - withLatestFrom(this.usersService.name$), - switchMap(([createdId, createdName]) => { - const referenceData = { - ...data, createdId, createdName, createdAt: new Date(), - }; - return this.referenceResourceTypeResourceKeyPut(type, key, referenceData, 'body', false); - }), - ); - } - - deleteReferenceDataItem(type: ReferenceDataResourceType, key: string, payload: Record) { - return this.usersService.id$.pipe( - withLatestFrom(this.usersService.name$), - switchMap(([createdId, createdName]) => { - const deleteObject = { - ...payload, createdId, createdName, createdAt: new Date(), - }; - return this.referenceResourceTypeResourceKeyDelete(type, key, deleteObject, 'body', false); - }), - ); - } - - fetchReferenceData(resourceType: ReferenceDataResourceType, paginationToken?: string): Observable { - if (!resourceType) { - return throwError(() => new Error('Reference data resourceType is required')); - } - - return this.referenceResourceTypeGet(resourceType, paginationToken, 'body'); - } - - fetchReferenceDataAudit(resourceType: ReferenceDataResourceType, paginationToken?: string): Observable { - if (!resourceType) { - return throwError(() => new Error('Reference data resourceType is required')); - } - - return this.referenceResourceTypeGet(resourceType, paginationToken, 'body'); - } - - fetchReferenceDataByKey(resourceType: ReferenceDataResourceType, resourceKey: string | number): Observable { - return this.referenceResourceTypeResourceKeyGet(resourceType, resourceKey, 'body'); - } - - loadReferenceDataByKey(resourceType: ReferenceDataResourceType, resourceKey: string | number): void { - return this.store.dispatch(fetchReferenceDataByKey({ resourceType, resourceKey })); - } - - fetchReferenceDataByKeySearch(resourceType: ReferenceDataResourceType, resourceKey: string | number): Observable { - return this.referenceLookupResourceTypeResourceKeyGet(resourceType, resourceKey, 'body'); - } - - fetchTyreReferenceDataByKeySearch(searchFilter: string, searchTerm: string): Observable { - return this.referenceLookupTyresSearchKeyParamGet(searchFilter, searchTerm, 'body'); - } - - loadReferenceDataByKeySearch(resourceType: ReferenceDataResourceType, resourceKey: string | number): void { - this.store.dispatch(fetchReferenceDataByKeySearch({ resourceType, resourceKey })); - } - - loadTyreReferenceDataByKeySearch(searchFilter: string, searchTerm: string): void { - this.store.dispatch(fetchTyreReferenceDataByKeySearch({ searchFilter, searchTerm })); - } - - loadReferenceData(resourceType: ReferenceDataResourceType): void { - this.store.dispatch(fetchReferenceData({ resourceType })); - } - - removeReferenceDataByKey(resourceType: ReferenceDataResourceType, resourceKey: string): void { - this.store.dispatch(removeReferenceDataByKey({ resourceType, resourceKey })); - } - - addSearchInformation(filter: string, term: string): void { - this.store.dispatch(addSearchInformation({ filter, term })); - } - - removeTyreSearch(): void { - this.store.dispatch(removeTyreSearch()); - } - - getTyreSearchReturn$(): Observable { - return this.store.pipe(select(selectSearchReturn(ReferenceDataResourceType.Tyres))) as Observable; - } - - getTyreSearchCriteria$(): Observable { - return this.store.pipe(select(selectTyreSearchCriteria)); - } - - getAll$(resourceType: ReferenceDataResourceType): Observable { - return this.store.pipe(select(selectAllReferenceDataByResourceType(resourceType))); - } - - getByKey$(resourceType: ReferenceDataResourceType, resourceKey: string | number) { - return this.store.pipe(select(selectReferenceDataByResourceKey(resourceType, resourceKey))); - } - - getReferenceDataOptions(resourceType: ReferenceDataResourceType): Observable { - return this.getAll$(resourceType).pipe((source) => this.mapReferenceDataOptions(source)); - } - - private mapReferenceDataOptions( - source: Observable> | undefined>, - ): Observable { - return new Observable((subscriber) => { - source.subscribe({ - next: (val) => { - subscriber.next(val?.map((option) => ({ value: option.resourceKey, label: option.description ?? option.name ?? `${option.resourceKey}` }))); - }, - error: (e) => subscriber.error(e), - complete: () => subscriber.complete(), - }); - }); - } - - getReasonsForAbandoning(vehicleType: VehicleTypes | undefined): Observable { - if (!vehicleType) { - return of([]); - } - return this.store.pipe(select(selectReasonsForAbandoning(vehicleType)), (source) => this.mapReferenceDataOptions(source)); - } - - getReferencePsvMakeDataLoading$(): Observable { - return this.store.pipe(select(referencePsvMakeLoadingState)); - } + constructor( + @Optional() @Inject(BASE_PATH) basePath: string, + @Optional() configuration: Configuration, + httpClient: HttpClient, + private usersService: UserService, + private store: Store + ) { + super(httpClient, basePath, configuration); + } + + // URL to POST new reference data items: /reference/{ type capitalized }/{ new key } POST + // eslint-disable-next-line @typescript-eslint/no-explicit-any + createReferenceDataItem(type: ReferenceDataResourceType, key: string, data: any) { + return this.usersService.id$.pipe( + withLatestFrom(this.usersService.name$), + switchMap(([createdId, createdName]) => { + const referenceData = { + ...data, + createdId, + createdName, + createdAt: new Date(), + }; + return this.referenceResourceTypeResourceKeyPost(type, key, referenceData, 'body', false); + }) + ); + } + + // URL to PUT new reference data items: /reference/{ type capitalized }/{ new key } PUT + // eslint-disable-next-line @typescript-eslint/no-explicit-any + amendReferenceDataItem(type: ReferenceDataResourceType, key: string, data: any) { + return this.usersService.id$.pipe( + withLatestFrom(this.usersService.name$), + switchMap(([createdId, createdName]) => { + const referenceData = { + ...data, + createdId, + createdName, + createdAt: new Date(), + }; + return this.referenceResourceTypeResourceKeyPut(type, key, referenceData, 'body', false); + }) + ); + } + + deleteReferenceDataItem(type: ReferenceDataResourceType, key: string, payload: Record) { + return this.usersService.id$.pipe( + withLatestFrom(this.usersService.name$), + switchMap(([createdId, createdName]) => { + const deleteObject = { + ...payload, + createdId, + createdName, + createdAt: new Date(), + }; + return this.referenceResourceTypeResourceKeyDelete(type, key, deleteObject, 'body', false); + }) + ); + } + + fetchReferenceData( + resourceType: ReferenceDataResourceType, + paginationToken?: string + ): Observable { + if (!resourceType) { + return throwError(() => new Error('Reference data resourceType is required')); + } + + return this.referenceResourceTypeGet(resourceType, paginationToken, 'body'); + } + + fetchReferenceDataAudit( + resourceType: ReferenceDataResourceType, + paginationToken?: string + ): Observable { + if (!resourceType) { + return throwError(() => new Error('Reference data resourceType is required')); + } + + return this.referenceResourceTypeGet(resourceType, paginationToken, 'body'); + } + + fetchReferenceDataByKey( + resourceType: ReferenceDataResourceType, + resourceKey: string | number + ): Observable { + return this.referenceResourceTypeResourceKeyGet(resourceType, resourceKey, 'body'); + } + + loadReferenceDataByKey(resourceType: ReferenceDataResourceType, resourceKey: string | number): void { + return this.store.dispatch(fetchReferenceDataByKey({ resourceType, resourceKey })); + } + + fetchReferenceDataByKeySearch( + resourceType: ReferenceDataResourceType, + resourceKey: string | number + ): Observable { + return this.referenceLookupResourceTypeResourceKeyGet(resourceType, resourceKey, 'body'); + } + + fetchTyreReferenceDataByKeySearch(searchFilter: string, searchTerm: string): Observable { + return this.referenceLookupTyresSearchKeyParamGet(searchFilter, searchTerm, 'body'); + } + + loadReferenceDataByKeySearch(resourceType: ReferenceDataResourceType, resourceKey: string | number): void { + this.store.dispatch(fetchReferenceDataByKeySearch({ resourceType, resourceKey })); + } + + loadTyreReferenceDataByKeySearch(searchFilter: string, searchTerm: string): void { + this.store.dispatch(fetchTyreReferenceDataByKeySearch({ searchFilter, searchTerm })); + } + + loadReferenceData(resourceType: ReferenceDataResourceType): void { + this.store.dispatch(fetchReferenceData({ resourceType })); + } + + removeReferenceDataByKey(resourceType: ReferenceDataResourceType, resourceKey: string): void { + this.store.dispatch(removeReferenceDataByKey({ resourceType, resourceKey })); + } + + addSearchInformation(filter: string, term: string): void { + this.store.dispatch(addSearchInformation({ filter, term })); + } + + removeTyreSearch(): void { + this.store.dispatch(removeTyreSearch()); + } + + getTyreSearchReturn$(): Observable { + return this.store.pipe(select(selectSearchReturn(ReferenceDataResourceType.Tyres))) as Observable< + ReferenceDataTyre[] | null + >; + } + + getTyreSearchCriteria$(): Observable { + return this.store.pipe(select(selectTyreSearchCriteria)); + } + + getAll$(resourceType: ReferenceDataResourceType): Observable { + return this.store.pipe(select(selectAllReferenceDataByResourceType(resourceType))); + } + + getByKey$(resourceType: ReferenceDataResourceType, resourceKey: string | number) { + return this.store.pipe(select(selectReferenceDataByResourceKey(resourceType, resourceKey))); + } + + getReferenceDataOptions(resourceType: ReferenceDataResourceType): Observable { + return this.getAll$(resourceType).pipe((source) => this.mapReferenceDataOptions(source)); + } + + private mapReferenceDataOptions( + source: Observable> | undefined> + ): Observable { + return new Observable((subscriber) => { + source.subscribe({ + next: (val) => { + subscriber.next( + val?.map((option) => ({ + value: option.resourceKey, + label: option.description ?? option.name ?? `${option.resourceKey}`, + })) + ); + }, + error: (e) => subscriber.error(e), + complete: () => subscriber.complete(), + }); + }); + } + + getReasonsForAbandoning(vehicleType: VehicleTypes | undefined): Observable { + if (!vehicleType) { + return of([]); + } + return this.store.pipe(select(selectReasonsForAbandoning(vehicleType)), (source) => + this.mapReferenceDataOptions(source) + ); + } + + getReferencePsvMakeDataLoading$(): Observable { + return this.store.pipe(select(referencePsvMakeLoadingState)); + } } diff --git a/src/app/services/required-standards/required-standards.service.ts b/src/app/services/required-standards/required-standards.service.ts index 8eaa8f3307..b80503116f 100644 --- a/src/app/services/required-standards/required-standards.service.ts +++ b/src/app/services/required-standards/required-standards.service.ts @@ -6,12 +6,13 @@ import { environment } from '../../../environments/environment'; @Injectable({ providedIn: 'root' }) export class RequiredStandardsService { - private url = `${environment.VTM_API_URI}/defects/required-standards`; + private url = `${environment.VTM_API_URI}/defects/required-standards`; - constructor(private http: HttpClient) {} - - getRequiredStandards(euVehicleCategory: string): Observable { - return this.http.get(`${this.url}?euVehicleCategory=${euVehicleCategory}`, { responseType: 'json' }); - } + constructor(private http: HttpClient) {} + getRequiredStandards(euVehicleCategory: string): Observable { + return this.http.get(`${this.url}?euVehicleCategory=${euVehicleCategory}`, { + responseType: 'json', + }); + } } diff --git a/src/app/services/result-of-test/result-of-test.service.spec.ts b/src/app/services/result-of-test/result-of-test.service.spec.ts index f6bb728f6a..c1d8d42f70 100644 --- a/src/app/services/result-of-test/result-of-test.service.spec.ts +++ b/src/app/services/result-of-test/result-of-test.service.spec.ts @@ -1,36 +1,38 @@ import { TestBed } from '@angular/core/testing'; import { resultOfTestEnum } from '@models/test-types/test-type.model'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; -import { initialAppState, State } from '@store/.'; +import { State, initialAppState } from '@store/.'; import { resultOfTestSelector } from '@store/test-records'; import { ResultOfTestService } from './result-of-test.service'; describe('ResultOfTestService', () => { - let service: ResultOfTestService; - let store: MockStore; + let service: ResultOfTestService; + let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ providers: [ResultOfTestService, provideMockStore({ initialState: initialAppState })] }); - service = TestBed.inject(ResultOfTestService); - store = TestBed.inject(MockStore); - }); + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ResultOfTestService, provideMockStore({ initialState: initialAppState })], + }); + service = TestBed.inject(ResultOfTestService); + store = TestBed.inject(MockStore); + }); - it('should be created', () => { - expect(service).toBeTruthy(); - }); + it('should be created', () => { + expect(service).toBeTruthy(); + }); - it('should dispatch the action to update the result of the test', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.updateResultOfTest(); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - }); + it('should dispatch the action to update the result of the test', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.updateResultOfTest(); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + }); - it('should get the result from the selector', (done) => { - store.overrideSelector(resultOfTestSelector, resultOfTestEnum.pass); - service.resultOfTest.subscribe((result) => { - expect(result).toBe(resultOfTestEnum.pass); - done(); - }); - }); + it('should get the result from the selector', (done) => { + store.overrideSelector(resultOfTestSelector, resultOfTestEnum.pass); + service.resultOfTest.subscribe((result) => { + expect(result).toBe(resultOfTestEnum.pass); + done(); + }); + }); }); diff --git a/src/app/services/result-of-test/result-of-test.service.ts b/src/app/services/result-of-test/result-of-test.service.ts index 5d04f47d47..39f7356664 100644 --- a/src/app/services/result-of-test/result-of-test.service.ts +++ b/src/app/services/result-of-test/result-of-test.service.ts @@ -1,36 +1,39 @@ import { Injectable } from '@angular/core'; import { resultOfTestEnum } from '@models/test-types/test-type.model'; -import { select, Store } from '@ngrx/store'; +import { Store, select } from '@ngrx/store'; import { State } from '@store/.'; import { - resultOfTestSelector, setResultOfTest, updateResultOfTest, updateResultOfTestRequiredStandards, + resultOfTestSelector, + setResultOfTest, + updateResultOfTest, + updateResultOfTestRequiredStandards, } from '@store/test-records'; import { Observable } from 'rxjs'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class ResultOfTestService { - constructor(private store: Store) {} + constructor(private store: Store) {} - get resultOfTest(): Observable { - return this.store.pipe(select(resultOfTestSelector)); - } + get resultOfTest(): Observable { + return this.store.pipe(select(resultOfTestSelector)); + } - updateResultOfTest() { - this.store.dispatch(updateResultOfTest()); - } + updateResultOfTest() { + this.store.dispatch(updateResultOfTest()); + } - updateResultOfTestRequiredStandards() { - this.store.dispatch(updateResultOfTestRequiredStandards()); - } + updateResultOfTestRequiredStandards() { + this.store.dispatch(updateResultOfTestRequiredStandards()); + } - toggleAbandoned(result: resultOfTestEnum) { - if (result !== resultOfTestEnum.abandoned) { - this.store.dispatch(setResultOfTest({ result })); - } else { - this.store.dispatch(setResultOfTest({ result })); - this.updateResultOfTest(); - } - } + toggleAbandoned(result: resultOfTestEnum) { + if (result !== resultOfTestEnum.abandoned) { + this.store.dispatch(setResultOfTest({ result })); + } else { + this.store.dispatch(setResultOfTest({ result })); + this.updateResultOfTest(); + } + } } diff --git a/src/app/services/router/router.service.spec.ts b/src/app/services/router/router.service.spec.ts index f9f144bec5..349f34af0a 100644 --- a/src/app/services/router/router.service.spec.ts +++ b/src/app/services/router/router.service.spec.ts @@ -1,72 +1,76 @@ import { TestBed } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; -import { initialAppState, State } from '@store/.'; -import { selectQueryParams, selectRouteNestedParams, selectRouteParams } from '@store/router/selectors/router.selectors'; +import { State, initialAppState } from '@store/.'; +import { + selectQueryParams, + selectRouteNestedParams, + selectRouteParams, +} from '@store/router/selectors/router.selectors'; import { firstValueFrom, of, take } from 'rxjs'; -import { RouterTestingModule } from '@angular/router/testing'; import { RouterService } from './router.service'; describe('RouterService', () => { - let service: RouterService; - let store: MockStore; + let service: RouterService; + let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [RouterTestingModule], - providers: [RouterService, provideMockStore({ initialState: initialAppState })], - }); - service = TestBed.inject(RouterService); - store = TestBed.inject(MockStore); - store.resetSelectors(); - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + providers: [RouterService, provideMockStore({ initialState: initialAppState })], + }); + service = TestBed.inject(RouterService); + store = TestBed.inject(MockStore); + store.resetSelectors(); + }); - it('should be created', () => { - expect(service).toBeTruthy(); - }); + it('should be created', () => { + expect(service).toBeTruthy(); + }); - describe('queryParams$', () => { - it('should return the query params', async () => { - const queryParams = { foo: 'bar', baz: 'qux' }; - store.overrideSelector(selectQueryParams, queryParams); - expect(await firstValueFrom(service.queryParams$.pipe(take(1)))).toEqual(queryParams); - }); - }); + describe('queryParams$', () => { + it('should return the query params', async () => { + const queryParams = { foo: 'bar', baz: 'qux' }; + store.overrideSelector(selectQueryParams, queryParams); + expect(await firstValueFrom(service.queryParams$.pipe(take(1)))).toEqual(queryParams); + }); + }); - describe('RouterService.prototype.getQueryParam$.name', () => { - it('should return the query param', async () => { - // overriding selectQueryParam(param) has no effect here, I think because it might use selectQueryParams internally so we override that instead - store.overrideSelector(selectQueryParams, { bar: 'foo' }); - store.refreshState(); - expect(await firstValueFrom(service.getQueryParam$('bar').pipe(take(1)))).toBe('foo'); - }); - }); + describe('RouterService.prototype.getQueryParam$.name', () => { + it('should return the query param', async () => { + // overriding selectQueryParam(param) has no effect here, I think because it might use selectQueryParams internally so we override that instead + store.overrideSelector(selectQueryParams, { bar: 'foo' }); + store.refreshState(); + expect(await firstValueFrom(service.getQueryParam$('bar').pipe(take(1)))).toBe('foo'); + }); + }); - describe('RouterService.prototype.getRouteParam$.name', () => { - it('should return an Observable of the given route param', async () => { - store.overrideSelector(selectRouteParams, { bar: 'baz' }); - store.refreshState(); - expect(await firstValueFrom(service.getRouteParam$('bar').pipe(take(1)))).toBe('baz'); - }); - }); + describe('RouterService.prototype.getRouteParam$.name', () => { + it('should return an Observable of the given route param', async () => { + store.overrideSelector(selectRouteParams, { bar: 'baz' }); + store.refreshState(); + expect(await firstValueFrom(service.getRouteParam$('bar').pipe(take(1)))).toBe('baz'); + }); + }); - describe('get routeNestedParams$', () => { - it('should return an Observable route Params', (done) => { - store.overrideSelector(selectRouteNestedParams, { foo: 'bar' }); - store.refreshState(); - service.routeNestedParams$.subscribe((value) => { - expect(value).toEqual({ foo: 'bar' }); - done(); - }); - }); - }); + describe('get routeNestedParams$', () => { + it('should return an Observable route Params', (done) => { + store.overrideSelector(selectRouteNestedParams, { foo: 'bar' }); + store.refreshState(); + service.routeNestedParams$.subscribe((value) => { + expect(value).toEqual({ foo: 'bar' }); + done(); + }); + }); + }); - describe('getRouteNestedParam', () => { - it('should return the correct value', (done) => { - jest.spyOn(service, 'routeNestedParams$', 'get').mockReturnValue(of({ foo: 'bar' })); - service.getRouteNestedParam$('foo').subscribe((value) => { - expect(value).toBe('bar'); - done(); - }); - }); - }); + describe('getRouteNestedParam', () => { + it('should return the correct value', (done) => { + jest.spyOn(service, 'routeNestedParams$', 'get').mockReturnValue(of({ foo: 'bar' })); + service.getRouteNestedParam$('foo').subscribe((value) => { + expect(value).toBe('bar'); + done(); + }); + }); + }); }); diff --git a/src/app/services/router/router.service.ts b/src/app/services/router/router.service.ts index 2a52adbe0b..c4cc5cd093 100644 --- a/src/app/services/router/router.service.ts +++ b/src/app/services/router/router.service.ts @@ -1,64 +1,71 @@ +import { Location } from '@angular/common'; import { Injectable } from '@angular/core'; import { ActivatedRoute, Params, Router } from '@angular/router'; -import { select, Store } from '@ngrx/store'; +import { Store, select } from '@ngrx/store'; import { State } from '@store/.'; import { - routeEditable, - routerState, - selectQueryParam, - selectQueryParams, - selectRouteData, - selectRouteDataProperty, - selectRouteNestedParams, - selectRouteParam, + routeEditable, + routerState, + selectQueryParam, + selectQueryParams, + selectRouteData, + selectRouteDataProperty, + selectRouteNestedParams, + selectRouteParam, } from '@store/router/selectors/router.selectors'; import { Observable, map } from 'rxjs'; -import { Location } from '@angular/common'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class RouterService { - constructor(private store: Store, private router: Router, private activatedRoute: ActivatedRoute, private location: Location) {} + constructor( + private store: Store, + private router: Router, + private activatedRoute: ActivatedRoute, + private location: Location + ) {} - get router$() { - return this.store.pipe(select(routerState)); - } + get router$() { + return this.store.pipe(select(routerState)); + } - get queryParams$(): Observable { - return this.store.pipe(select(selectQueryParams)); - } + get queryParams$(): Observable { + return this.store.pipe(select(selectQueryParams)); + } - getQueryParam$(param: string) { - return this.store.pipe(select(selectQueryParam(param))); - } + getQueryParam$(param: string) { + return this.store.pipe(select(selectQueryParam(param))); + } - getRouteParam$(param: string) { - return this.store.pipe(select(selectRouteParam(param))); - } + getRouteParam$(param: string) { + return this.store.pipe(select(selectRouteParam(param))); + } - get routeNestedParams$() { - return this.store.pipe(select(selectRouteNestedParams)); - } + get routeNestedParams$() { + return this.store.pipe(select(selectRouteNestedParams)); + } - getRouteNestedParam$(param: string): Observable { - return this.routeNestedParams$.pipe(map((route) => route[`${param}`])); - } + getRouteNestedParam$(param: string): Observable { + return this.routeNestedParams$.pipe(map((route) => route[`${param}`])); + } - get routeEditable$() { - return this.store.pipe(select(routeEditable)); - } + get routeEditable$() { + return this.store.pipe(select(routeEditable)); + } - get routeData$() { - return this.store.pipe(select(selectRouteData)); - } + get routeData$() { + return this.store.pipe(select(selectRouteData)); + } - getRouteDataProperty$(property: string) { - return this.store.pipe(select(selectRouteDataProperty(property))); - } + getRouteDataProperty$(property: string) { + return this.store.pipe(select(selectRouteDataProperty(property))); + } - async addQueryParams(queryParams: Params) { - const url = this.router.createUrlTree([], { relativeTo: this.activatedRoute, queryParams, queryParamsHandling: 'merge' }).toString(); - await this.router.navigateByUrl(url); - } + async addQueryParams(queryParams: Params) { + const url = this.router + .createUrlTree([], { relativeTo: this.activatedRoute, queryParams, queryParamsHandling: 'merge' }) + .toString(); + await this.router.navigateByUrl(url); + } } diff --git a/src/app/services/technical-record-http/technical-record-http.service.spec.ts b/src/app/services/technical-record-http/technical-record-http.service.spec.ts index bc3cc44e73..656ea3f387 100644 --- a/src/app/services/technical-record-http/technical-record-http.service.spec.ts +++ b/src/app/services/technical-record-http/technical-record-http.service.spec.ts @@ -14,186 +14,207 @@ import { TechnicalRecordHttpService } from './technical-record-http.service'; // TODO: need to include tests for search$, seachBy, getBySystemNumber, getRecordV3, AmendVrm, promoteTechRecord, generatePlate, generateLetter describe('TechnicalRecordService', () => { - let service: TechnicalRecordHttpService; - let httpClient: HttpTestingController; - let store: MockStore; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule], - providers: [TechnicalRecordHttpService, provideMockStore({ initialState: initialAppState })], - }); - httpClient = TestBed.inject(HttpTestingController); - service = TestBed.inject(TechnicalRecordHttpService); - store = TestBed.inject(MockStore); - }); - - afterEach(() => { - // After every test, assert that there are no more pending requests. - httpClient.verify(); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('API', () => { - describe('createVehicleRecord', () => { - it('should call post with the correct URL, body and response type', fakeAsync(() => { - const expectedVehicle = { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testvin', - primaryVrm: 'vrm1', - techRecord_reasonForCreation: 'test', - } as unknown as TechRecordType<'put'>; - - service.createVehicleRecord$(expectedVehicle).subscribe(); - - const request = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records`); - - expect(request.request.method).toBe('POST'); - expect(request.request.body).toEqual(expectedVehicle); - - request.flush(expectedVehicle); - })); - - it('should return an array with the newly created vehicle record', () => { - const expectedVehicle = { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testvin', - primaryVrm: 'vrm1', - techRecord_reasonForCreation: 'test', - } as unknown as TechRecordType<'put'>; - - service.createVehicleRecord$(expectedVehicle).pipe(first()).subscribe((response) => { - expect(response).toEqual(expectedVehicle); - }); - - const request = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records`); - request.flush(expectedVehicle); - }); - }); - - describe('updateTechRecords', () => { - it('should return a new tech record and updated status code', fakeAsync(() => { - const systemNumber = '123456'; - const createdTimestamp = '2022'; - const expectedVehicle = { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testvin', - primaryVrm: 'vrm1', - techRecord_reasonForCreation: 'test', - secondaryVrms: undefined, - } as TechRecordType<'get'>; - service.updateTechRecords$(systemNumber, createdTimestamp, expectedVehicle as TechRecordType<'put'>).subscribe(); - - // Check for correct requests: should have made one request to the PUT URL - const req = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records/${systemNumber}/${createdTimestamp}`); - expect(req.request.method).toBe('PATCH'); - - // should format the vrms for the update payload - expect(req.request.body).toHaveProperty('primaryVrm'); - expect(req.request.body).toHaveProperty('secondaryVrms'); - })); - }); - - describe('archiveTechRecord', () => { - it('should return a new tech record with status archived', fakeAsync(() => { - service.archiveTechnicalRecord$('foo', 'bar', 'foobar').subscribe(); - - const req = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records/archive/foo/bar`); - expect(req.request.method).toBe('PATCH'); - expect(req.request.body).toHaveProperty('reasonForArchiving'); - })); - }); - - describe('generateLetter', () => { - it('should call v3/technical-records/letter', fakeAsync(() => { - const technicalRecord = mockVehicleTechnicalRecord('hgv') as TechRecordType<'get'>; - service.generateLetter$(technicalRecord, 'test', 123, {}).subscribe(); - - const req = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records/letter/HGV/${technicalRecord.createdTimestamp}`); - expect(req.request.method).toBe('POST'); - expect(req.request.body).toHaveProperty('vtmUsername'); - expect(req.request.body).toHaveProperty('letterType'); - expect(req.request.body).toHaveProperty('paragraphId'); - expect(req.request.body).toHaveProperty('recipientEmailAddress'); - })); - }); - - describe('generatePlate', () => { - it('should call v3/technical-records/plate', fakeAsync(() => { - const technicalRecord = mockVehicleTechnicalRecord('hgv') as TechRecordType<'get'>; - service.generatePlate$(technicalRecord, 'reason', {}).subscribe(); - - const req = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records/plate/HGV/${technicalRecord.createdTimestamp}`); - expect(req.request.method).toBe('POST'); - expect(req.request.body).toHaveProperty('vtmUsername'); - expect(req.request.body).toHaveProperty('reasonForCreation'); - expect(req.request.body).toHaveProperty('recipientEmailAddress'); - })); - }); - - describe('promoteTechnicalRecord', () => { - it('should call v3/technical-records/plate', fakeAsync(() => { - const technicalRecord = mockVehicleTechnicalRecord('hgv') as TechRecordType<'get'>; - service.promoteTechnicalRecord$(technicalRecord.systemNumber, technicalRecord.createdTimestamp, 'reason').subscribe(); - - const req = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records/promote/HGV/${technicalRecord.createdTimestamp}`); - expect(req.request.method).toBe('PATCH'); - expect(req.request.body).toHaveProperty('reasonForPromoting'); - })); - }); - - describe('amendVrm', () => { - it('should call v3/technical-records/updateVrm', fakeAsync(() => { - const technicalRecord = mockVehicleTechnicalRecord('hgv') as TechRecordType<'get'>; - service.amendVrm$('new vrm', false, technicalRecord.systemNumber, technicalRecord.createdTimestamp).subscribe(); - - const req = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records/updateVrm/HGV/${technicalRecord.createdTimestamp}`); - expect(req.request.method).toBe('PATCH'); - expect(req.request.body).toHaveProperty('newVrm'); - expect(req.request.body).toHaveProperty('isCherishedTransfer'); - })); - }); - - describe('getRecordV3', () => { - it('should call v3/technical-records/plate/HGV', fakeAsync(() => { - const technicalRecord = mockVehicleTechnicalRecord('hgv') as TechRecordType<'get'>; - service.getRecordV3$(technicalRecord.systemNumber, technicalRecord.createdTimestamp).subscribe(); - - const req = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records/HGV/${technicalRecord.createdTimestamp}`); - expect(req.request.method).toBe('GET'); - })); - }); - - describe('getBySystemNumber', () => { - it('should call service.search$', () => { - const technicalRecord = mockVehicleTechnicalRecord('hgv') as TechRecordType<'get'>; - const spy = jest.spyOn(service, 'search$').mockReturnValue(of()); - service.getBySystemNumber$(technicalRecord.systemNumber).subscribe(); - expect(spy).toHaveBeenCalled(); - }); - }); - - describe('searchBy', () => { - it('should call store.dispatch', fakeAsync(() => { - const spy = jest.spyOn(store, 'dispatch'); - service.searchBy(SEARCH_TYPES.ALL, 'term'); - expect(spy).toHaveBeenCalledWith(fetchSearchResult({ searchBy: SEARCH_TYPES.ALL, term: 'term' })); - })); - }); - - describe('search$', () => { - it('should call v3/technical-records/search', fakeAsync(() => { - service.search$(SEARCH_TYPES.ALL, 'term').subscribe(); - - const req = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records/search/term?searchCriteria=${SEARCH_TYPES.ALL}`); - expect(req.request.method).toBe('GET'); - })); - }); - }); + let service: TechnicalRecordHttpService; + let httpClient: HttpTestingController; + let store: MockStore; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule, RouterTestingModule], + providers: [TechnicalRecordHttpService, provideMockStore({ initialState: initialAppState })], + }); + httpClient = TestBed.inject(HttpTestingController); + service = TestBed.inject(TechnicalRecordHttpService); + store = TestBed.inject(MockStore); + }); + + afterEach(() => { + // After every test, assert that there are no more pending requests. + httpClient.verify(); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + describe('API', () => { + describe('createVehicleRecord', () => { + it('should call post with the correct URL, body and response type', fakeAsync(() => { + const expectedVehicle = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testvin', + primaryVrm: 'vrm1', + techRecord_reasonForCreation: 'test', + } as unknown as TechRecordType<'put'>; + + service.createVehicleRecord$(expectedVehicle).subscribe(); + + const request = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records`); + + expect(request.request.method).toBe('POST'); + expect(request.request.body).toEqual(expectedVehicle); + + request.flush(expectedVehicle); + })); + + it('should return an array with the newly created vehicle record', () => { + const expectedVehicle = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testvin', + primaryVrm: 'vrm1', + techRecord_reasonForCreation: 'test', + } as unknown as TechRecordType<'put'>; + + service + .createVehicleRecord$(expectedVehicle) + .pipe(first()) + .subscribe((response) => { + expect(response).toEqual(expectedVehicle); + }); + + const request = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records`); + request.flush(expectedVehicle); + }); + }); + + describe('updateTechRecords', () => { + it('should return a new tech record and updated status code', fakeAsync(() => { + const systemNumber = '123456'; + const createdTimestamp = '2022'; + const expectedVehicle = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testvin', + primaryVrm: 'vrm1', + techRecord_reasonForCreation: 'test', + secondaryVrms: undefined, + } as TechRecordType<'get'>; + service + .updateTechRecords$(systemNumber, createdTimestamp, expectedVehicle as TechRecordType<'put'>) + .subscribe(); + + // Check for correct requests: should have made one request to the PUT URL + const req = httpClient.expectOne( + `${environment.VTM_API_URI}/v3/technical-records/${systemNumber}/${createdTimestamp}` + ); + expect(req.request.method).toBe('PATCH'); + + // should format the vrms for the update payload + expect(req.request.body).toHaveProperty('primaryVrm'); + expect(req.request.body).toHaveProperty('secondaryVrms'); + })); + }); + + describe('archiveTechRecord', () => { + it('should return a new tech record with status archived', fakeAsync(() => { + service.archiveTechnicalRecord$('foo', 'bar', 'foobar').subscribe(); + + const req = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records/archive/foo/bar`); + expect(req.request.method).toBe('PATCH'); + expect(req.request.body).toHaveProperty('reasonForArchiving'); + })); + }); + + describe('generateLetter', () => { + it('should call v3/technical-records/letter', fakeAsync(() => { + const technicalRecord = mockVehicleTechnicalRecord('hgv') as TechRecordType<'get'>; + service.generateLetter$(technicalRecord, 'test', 123, {}).subscribe(); + + const req = httpClient.expectOne( + `${environment.VTM_API_URI}/v3/technical-records/letter/HGV/${technicalRecord.createdTimestamp}` + ); + expect(req.request.method).toBe('POST'); + expect(req.request.body).toHaveProperty('vtmUsername'); + expect(req.request.body).toHaveProperty('letterType'); + expect(req.request.body).toHaveProperty('paragraphId'); + expect(req.request.body).toHaveProperty('recipientEmailAddress'); + })); + }); + + describe('generatePlate', () => { + it('should call v3/technical-records/plate', fakeAsync(() => { + const technicalRecord = mockVehicleTechnicalRecord('hgv') as TechRecordType<'get'>; + service.generatePlate$(technicalRecord, 'reason', {}).subscribe(); + + const req = httpClient.expectOne( + `${environment.VTM_API_URI}/v3/technical-records/plate/HGV/${technicalRecord.createdTimestamp}` + ); + expect(req.request.method).toBe('POST'); + expect(req.request.body).toHaveProperty('vtmUsername'); + expect(req.request.body).toHaveProperty('reasonForCreation'); + expect(req.request.body).toHaveProperty('recipientEmailAddress'); + })); + }); + + describe('promoteTechnicalRecord', () => { + it('should call v3/technical-records/plate', fakeAsync(() => { + const technicalRecord = mockVehicleTechnicalRecord('hgv') as TechRecordType<'get'>; + service + .promoteTechnicalRecord$(technicalRecord.systemNumber, technicalRecord.createdTimestamp, 'reason') + .subscribe(); + + const req = httpClient.expectOne( + `${environment.VTM_API_URI}/v3/technical-records/promote/HGV/${technicalRecord.createdTimestamp}` + ); + expect(req.request.method).toBe('PATCH'); + expect(req.request.body).toHaveProperty('reasonForPromoting'); + })); + }); + + describe('amendVrm', () => { + it('should call v3/technical-records/updateVrm', fakeAsync(() => { + const technicalRecord = mockVehicleTechnicalRecord('hgv') as TechRecordType<'get'>; + service.amendVrm$('new vrm', false, technicalRecord.systemNumber, technicalRecord.createdTimestamp).subscribe(); + + const req = httpClient.expectOne( + `${environment.VTM_API_URI}/v3/technical-records/updateVrm/HGV/${technicalRecord.createdTimestamp}` + ); + expect(req.request.method).toBe('PATCH'); + expect(req.request.body).toHaveProperty('newVrm'); + expect(req.request.body).toHaveProperty('isCherishedTransfer'); + })); + }); + + describe('getRecordV3', () => { + it('should call v3/technical-records/plate/HGV', fakeAsync(() => { + const technicalRecord = mockVehicleTechnicalRecord('hgv') as TechRecordType<'get'>; + service.getRecordV3$(technicalRecord.systemNumber, technicalRecord.createdTimestamp).subscribe(); + + const req = httpClient.expectOne( + `${environment.VTM_API_URI}/v3/technical-records/HGV/${technicalRecord.createdTimestamp}` + ); + expect(req.request.method).toBe('GET'); + })); + }); + + describe('getBySystemNumber', () => { + it('should call service.search$', () => { + const technicalRecord = mockVehicleTechnicalRecord('hgv') as TechRecordType<'get'>; + const spy = jest.spyOn(service, 'search$').mockReturnValue(of()); + service.getBySystemNumber$(technicalRecord.systemNumber).subscribe(); + expect(spy).toHaveBeenCalled(); + }); + }); + + describe('searchBy', () => { + it('should call store.dispatch', fakeAsync(() => { + const spy = jest.spyOn(store, 'dispatch'); + service.searchBy(SEARCH_TYPES.ALL, 'term'); + expect(spy).toHaveBeenCalledWith(fetchSearchResult({ searchBy: SEARCH_TYPES.ALL, term: 'term' })); + })); + }); + + describe('search$', () => { + it('should call v3/technical-records/search', fakeAsync(() => { + service.search$(SEARCH_TYPES.ALL, 'term').subscribe(); + + const req = httpClient.expectOne( + `${environment.VTM_API_URI}/v3/technical-records/search/term?searchCriteria=${SEARCH_TYPES.ALL}` + ); + expect(req.request.method).toBe('GET'); + })); + }); + }); }); diff --git a/src/app/services/technical-record-http/technical-record-http.service.ts b/src/app/services/technical-record-http/technical-record-http.service.ts index 5e295a3426..f764d1d2a9 100644 --- a/src/app/services/technical-record-http/technical-record-http.service.ts +++ b/src/app/services/technical-record-http/technical-record-http.service.ts @@ -12,139 +12,158 @@ import { environment } from '../../../environments/environment'; @Injectable({ providedIn: 'root' }) export class TechnicalRecordHttpService { - constructor(private http: HttpClient, private store: Store) { } - - search$(type: SEARCH_TYPES, term: string): Observable { - const queryStr = `${term}?searchCriteria=${type}`; - const url = `${environment.VTM_API_URI}/v3/technical-records/search/${queryStr}`; - - return this.http.get(url, { responseType: 'json' }); - } - - searchBy(type: SEARCH_TYPES | undefined, term: string): void { - this.store.dispatch(fetchSearchResult({ searchBy: type, term })); - } - - getBySystemNumber$(systemNumber: string): Observable { - return this.search$(SEARCH_TYPES.SYSTEM_NUMBER, systemNumber); - } - - getRecordV3$(systemNumber: string, createdTimestamp: string): Observable> { - const url = `${environment.VTM_API_URI}/v3/technical-records/${systemNumber}/${createdTimestamp}`; - - return this.http.get>(url, { responseType: 'json' }); - } - - createVehicleRecord$(newVehicleRecord: V3TechRecordModel): Observable> { - const recordCopy: TechRecordType<'put'> = cloneDeep(newVehicleRecord) as TechRecordType<'put'>; - - const body = { - ...recordCopy, - }; - - return this.http.post>(`${environment.VTM_API_URI}/v3/technical-records`, body); - } - - updateTechRecords$(systemNumber: string, createdTimestamp: string, techRecord: TechRecordType<'put'>): Observable> { - const url = `${environment.VTM_API_URI}/v3/technical-records/${systemNumber}/${createdTimestamp}`; - - return this.http.patch>(url, techRecord, { responseType: 'json' }); - } - - amendVrm$( - newVrm: string, - cherishedTransfer: boolean, - systemNumber: string, - createdTimestamp: string, - thirdMark?: string, - ): Observable> { - const url = `${environment.VTM_API_URI}/v3/technical-records/updateVrm/${systemNumber}/${createdTimestamp}`; - const body = { - newVrm, - isCherishedTransfer: cherishedTransfer, - thirdMark: thirdMark ?? undefined, - }; - return this.http.patch>(url, body, { responseType: 'json' }); - } - - amendVin$( - newVin: string, - systemNumber: string, - createdTimestamp: string, - ): Observable> { - const url = `${environment.VTM_API_URI}/v3/technical-records/updateVin/${systemNumber}/${createdTimestamp}`; - const body = { - newVin, - }; - return this.http.patch>(url, body, { responseType: 'json' }); - } - - archiveTechnicalRecord$(systemNumber: string, createdTimestamp: string, reasonForArchiving: string): Observable> { - const url = `${environment.VTM_API_URI}/v3/technical-records/archive/${systemNumber}/${createdTimestamp}`; - - const body = { reasonForArchiving }; - - return this.http.patch>(url, body, { responseType: 'json' }); - } - - promoteTechnicalRecord$(systemNumber: string, createdTimestamp: string, reasonForPromoting: string): Observable> { - const url = `${environment.VTM_API_URI}/v3/technical-records/promote/${systemNumber}/${createdTimestamp}`; - - const body = { reasonForPromoting }; - - return this.http.patch>(url, body, { responseType: 'json' }); - } - - generatePlate$(vehicleRecord: TechRecordType<'get'>, reason: string, user: { name?: string; email?: string }): Observable { - const url = `${environment.VTM_API_URI}/v3/technical-records/plate/${vehicleRecord.systemNumber}/${vehicleRecord.createdTimestamp}`; - - const body = { - reasonForCreation: reason, - vtmUsername: user.name, - recipientEmailAddress: (vehicleRecord)?.techRecord_applicantDetails_emailAddress ?? user.email, - }; - - return this.http.post(url, body, { responseType: 'json' }); - } - - generateLetter$( - vehicleRecord: TechRecordType<'get'>, - letterType: string, - paragraphId: number, - user: { name?: string; email?: string }, - ): Observable { - const url = `${environment.VTM_API_URI}/v3/technical-records/letter/${vehicleRecord.systemNumber}/${vehicleRecord.createdTimestamp}`; - - const body = { - vtmUsername: user.name, - letterType, - paragraphId, - recipientEmailAddress: vehicleRecord.techRecord_applicantDetails_emailAddress - ? (vehicleRecord).techRecord_applicantDetails_emailAddress - : user.email, - }; - - return this.http.post(url, body, { responseType: 'text' }); - } - - unarchiveTechnicalRecord$( - systemNumber: string, - createdTimestamp: string, - reasonForUnarchiving: string, - status: string, - ): Observable> { - const url = `${environment.VTM_API_URI}/v3/technical-records/unarchive/${systemNumber}/${createdTimestamp}`; - - const body = { reasonForUnarchiving, status }; - - return this.http.post>(url, body, { responseType: 'json' }); - } - - generateADRCertificate$(systemNumber: string, createdTimestamp: string, certificateType: string): Observable<{ message: string, id: string }> { - const url = `${environment.VTM_API_URI}/v3/technical-records/adrCertificate/${systemNumber}/${createdTimestamp}`; - - const body = { certificateType }; - - return this.http.post<{ message: string, id: string }>(url, body, { responseType: 'json' }); - } + constructor( + private http: HttpClient, + private store: Store + ) {} + + search$(type: SEARCH_TYPES, term: string): Observable { + const queryStr = `${term}?searchCriteria=${type}`; + const url = `${environment.VTM_API_URI}/v3/technical-records/search/${queryStr}`; + + return this.http.get(url, { responseType: 'json' }); + } + + searchBy(type: SEARCH_TYPES | undefined, term: string): void { + this.store.dispatch(fetchSearchResult({ searchBy: type, term })); + } + + getBySystemNumber$(systemNumber: string): Observable { + return this.search$(SEARCH_TYPES.SYSTEM_NUMBER, systemNumber); + } + + getRecordV3$(systemNumber: string, createdTimestamp: string): Observable> { + const url = `${environment.VTM_API_URI}/v3/technical-records/${systemNumber}/${createdTimestamp}`; + + return this.http.get>(url, { responseType: 'json' }); + } + + createVehicleRecord$(newVehicleRecord: V3TechRecordModel): Observable> { + const recordCopy: TechRecordType<'put'> = cloneDeep(newVehicleRecord) as TechRecordType<'put'>; + + const body = { + ...recordCopy, + }; + + return this.http.post>(`${environment.VTM_API_URI}/v3/technical-records`, body); + } + + updateTechRecords$( + systemNumber: string, + createdTimestamp: string, + techRecord: TechRecordType<'put'> + ): Observable> { + const url = `${environment.VTM_API_URI}/v3/technical-records/${systemNumber}/${createdTimestamp}`; + + return this.http.patch>(url, techRecord, { responseType: 'json' }); + } + + amendVrm$( + newVrm: string, + cherishedTransfer: boolean, + systemNumber: string, + createdTimestamp: string, + thirdMark?: string + ): Observable> { + const url = `${environment.VTM_API_URI}/v3/technical-records/updateVrm/${systemNumber}/${createdTimestamp}`; + const body = { + newVrm, + isCherishedTransfer: cherishedTransfer, + thirdMark: thirdMark ?? undefined, + }; + return this.http.patch>(url, body, { responseType: 'json' }); + } + + amendVin$(newVin: string, systemNumber: string, createdTimestamp: string): Observable> { + const url = `${environment.VTM_API_URI}/v3/technical-records/updateVin/${systemNumber}/${createdTimestamp}`; + const body = { + newVin, + }; + return this.http.patch>(url, body, { responseType: 'json' }); + } + + archiveTechnicalRecord$( + systemNumber: string, + createdTimestamp: string, + reasonForArchiving: string + ): Observable> { + const url = `${environment.VTM_API_URI}/v3/technical-records/archive/${systemNumber}/${createdTimestamp}`; + + const body = { reasonForArchiving }; + + return this.http.patch>(url, body, { responseType: 'json' }); + } + + promoteTechnicalRecord$( + systemNumber: string, + createdTimestamp: string, + reasonForPromoting: string + ): Observable> { + const url = `${environment.VTM_API_URI}/v3/technical-records/promote/${systemNumber}/${createdTimestamp}`; + + const body = { reasonForPromoting }; + + return this.http.patch>(url, body, { responseType: 'json' }); + } + + generatePlate$( + vehicleRecord: TechRecordType<'get'>, + reason: string, + user: { name?: string; email?: string } + ): Observable { + const url = `${environment.VTM_API_URI}/v3/technical-records/plate/${vehicleRecord.systemNumber}/${vehicleRecord.createdTimestamp}`; + + const body = { + reasonForCreation: reason, + vtmUsername: user.name, + recipientEmailAddress: vehicleRecord?.techRecord_applicantDetails_emailAddress ?? user.email, + }; + + return this.http.post(url, body, { responseType: 'json' }); + } + + generateLetter$( + vehicleRecord: TechRecordType<'get'>, + letterType: string, + paragraphId: number, + user: { name?: string; email?: string } + ): Observable { + const url = `${environment.VTM_API_URI}/v3/technical-records/letter/${vehicleRecord.systemNumber}/${vehicleRecord.createdTimestamp}`; + + const body = { + vtmUsername: user.name, + letterType, + paragraphId, + recipientEmailAddress: vehicleRecord.techRecord_applicantDetails_emailAddress + ? vehicleRecord.techRecord_applicantDetails_emailAddress + : user.email, + }; + + return this.http.post(url, body, { responseType: 'text' }); + } + + unarchiveTechnicalRecord$( + systemNumber: string, + createdTimestamp: string, + reasonForUnarchiving: string, + status: string + ): Observable> { + const url = `${environment.VTM_API_URI}/v3/technical-records/unarchive/${systemNumber}/${createdTimestamp}`; + + const body = { reasonForUnarchiving, status }; + + return this.http.post>(url, body, { responseType: 'json' }); + } + + generateADRCertificate$( + systemNumber: string, + createdTimestamp: string, + certificateType: string + ): Observable<{ message: string; id: string }> { + const url = `${environment.VTM_API_URI}/v3/technical-records/adrCertificate/${systemNumber}/${createdTimestamp}`; + + const body = { certificateType }; + + return this.http.post<{ message: string; id: string }>(url, body, { responseType: 'json' }); + } } diff --git a/src/app/services/technical-record/technical-record.service.spec.ts b/src/app/services/technical-record/technical-record.service.spec.ts index 5729050d04..6ee91d17a8 100644 --- a/src/app/services/technical-record/technical-record.service.spec.ts +++ b/src/app/services/technical-record/technical-record.service.spec.ts @@ -7,9 +7,9 @@ import { EUVehicleCategory } from '@dvsa/cvs-type-definitions/types/v3/tech-reco import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; import { - TechRecordGETHGV, - TechRecordGETPSV, - TechRecordGETTRL, + TechRecordGETHGV, + TechRecordGETPSV, + TechRecordGETTRL, } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb-vehicle-type'; import { mockVehicleTechnicalRecord } from '@mocks/mock-vehicle-technical-record.mock'; import { ReferenceDataResourceType, ReferenceDataTyreLoadIndex } from '@models/reference-data.model'; @@ -19,760 +19,822 @@ import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { TechnicalRecordHttpService } from '@services/technical-record-http/technical-record-http.service'; import { State, initialAppState } from '@store/index'; import { updateEditingTechRecord } from '@store/technical-records'; -import { - EmptyError, - firstValueFrom, from, of, -} from 'rxjs'; +import { EmptyError, firstValueFrom, from, of } from 'rxjs'; import { environment } from '../../../environments/environment'; import { TechnicalRecordService } from './technical-record.service'; import FitmentCodeEnum = AxleTyreProperties.FitmentCodeEnum; describe('TechnicalRecordService', () => { - let service: TechnicalRecordService; - let httpClient: HttpTestingController; - let store: MockStore; - let techRecordHttpService: TechnicalRecordHttpService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule], - providers: [ - TechnicalRecordService, - provideMockStore({ initialState: initialAppState }), - ], - }); - httpClient = TestBed.inject(HttpTestingController); - service = TestBed.inject(TechnicalRecordService); - store = TestBed.inject(MockStore); - techRecordHttpService = TestBed.inject(TechnicalRecordHttpService); - }); - - afterEach(() => { - // After every test, assert that there are no more pending requests. - httpClient.verify(); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('isUnique', () => { - it('should validate the search term to be unique when no matching results are returned (Test Case 1)', () => { - const searchParams = { searchTerm: '12345', type: 'vin' }; - const mockData = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel; - - service.isUnique(searchParams.searchTerm, SEARCH_TYPES.VIN).subscribe((response) => { - expect(response).toBe(true); - }); - - // Check for correct requests: should have made one request to search from expected URL - const req = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records/search/${searchParams.searchTerm}?searchCriteria=vin`); - expect(req.request.method).toBe('GET'); - - // Provide each request with a mock response - req.flush(mockData); - }); - - it('should validate the search term to be unique when no matching results are returned (Test Case 2)', () => { - const searchParams = { searchTerm: 'A_VIN', type: 'vin' }; - const mockData = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel; - - service.isUnique(searchParams.searchTerm, SEARCH_TYPES.VIN).subscribe((response) => { - expect(response).toBe(true); - }); - - // Check for correct requests: should have made one request to search from expected URL - const req = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records/search/${searchParams.searchTerm}?searchCriteria=vin`); - expect(req.request.method).toBe('GET'); - - // Provide each request with a mock response - req.flush(mockData); - }); - - it('should validate the search term to be non unique when matching results are returned and are current or provisional', () => { - const searchParams = { searchTerm: 'A_VIN', type: 'vin' }; - const mockData = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel; - - service.isUnique(searchParams.searchTerm, SEARCH_TYPES.VIN).subscribe((response) => { - expect(response).toBe(false); - }); - - // Check for correct requests: should have made one request to search from expected URL - const req = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records/search/${searchParams.searchTerm}?searchCriteria=vin`); - expect(req.request.method).toBe('GET'); - - // Provide each request with a mock response - req.flush(mockData); - }); - - it('should validate the search term to be non unique when vrm is used as a primary', () => { - const searchParams = { searchTerm: 'KP01 ABC', type: 'vrm' }; - const mockData = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel; - - service.isUnique(searchParams.searchTerm, SEARCH_TYPES.VRM).subscribe((response) => { - expect(response).toBe(false); - }); - - // Check for correct requests: should have made one request to search from expected URL - const req = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records/search/${searchParams.searchTerm}?searchCriteria=primaryVrm`); - expect(req.request.method).toBe('GET'); - - // Provide each request with a mock response - req.flush(mockData); - }); - - it('should validate the search term to be unique when vrm is not used as a primary', () => { - const searchParams = { searchTerm: '12345', type: 'vrm' }; - const mockData = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel; - - service.isUnique(searchParams.searchTerm, SEARCH_TYPES.VRM).subscribe((response) => { - expect(response).toBe(true); - }); - - // Check for correct requests: should have made one request to search from expected URL - const req = httpClient.expectOne(`${environment.VTM_API_URI}/v3/technical-records/search/${searchParams.searchTerm}?searchCriteria=primaryVrm`); - expect(req.request.method).toBe('GET'); - - // Provide each request with a mock response - req.flush(mockData); - }); - }); - - describe('getVehicleMakeAndModel', () => { - it('should return an empty string if there is no make and model', () => { - const record = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as unknown as TechRecordType<'put'>; - expect(service.getMakeAndModel(record)).toBe(''); - }); - it('for a PSV returns the chassis make and model', () => { - const record: V3TechRecordModel = { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_vehicleType: VehicleTypes.PSV, - techRecord_chassisMake: 'test chassis make', - techRecord_chassisModel: 'chassis model', - } as unknown as V3TechRecordModel; - expect(service.getMakeAndModel(record)).toBe('test chassis make - chassis model'); - }); - it('for a any other type returns make and model', () => { - const record: V3TechRecordModel = { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_vehicleType: VehicleTypes.HGV, - techRecord_make: 'make', - techRecord_model: 'model', - } as unknown as V3TechRecordModel; - expect(service.getMakeAndModel(record)).toBe('make - model'); - }); - }); - - describe('business logic methods', () => { - describe('updateEditingTechRecord', () => { - it(`should patch the missing information for the technical + let service: TechnicalRecordService; + let httpClient: HttpTestingController; + let store: MockStore; + let techRecordHttpService: TechnicalRecordHttpService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule, RouterTestingModule], + providers: [TechnicalRecordService, provideMockStore({ initialState: initialAppState })], + }); + httpClient = TestBed.inject(HttpTestingController); + service = TestBed.inject(TechnicalRecordService); + store = TestBed.inject(MockStore); + techRecordHttpService = TestBed.inject(TechnicalRecordHttpService); + }); + + afterEach(() => { + // After every test, assert that there are no more pending requests. + httpClient.verify(); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + describe('isUnique', () => { + it('should validate the search term to be unique when no matching results are returned (Test Case 1)', () => { + const searchParams = { searchTerm: '12345', type: 'vin' }; + const mockData = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel; + + service.isUnique(searchParams.searchTerm, SEARCH_TYPES.VIN).subscribe((response) => { + expect(response).toBe(true); + }); + + // Check for correct requests: should have made one request to search from expected URL + const req = httpClient.expectOne( + `${environment.VTM_API_URI}/v3/technical-records/search/${searchParams.searchTerm}?searchCriteria=vin` + ); + expect(req.request.method).toBe('GET'); + + // Provide each request with a mock response + req.flush(mockData); + }); + + it('should validate the search term to be unique when no matching results are returned (Test Case 2)', () => { + const searchParams = { searchTerm: 'A_VIN', type: 'vin' }; + const mockData = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel; + + service.isUnique(searchParams.searchTerm, SEARCH_TYPES.VIN).subscribe((response) => { + expect(response).toBe(true); + }); + + // Check for correct requests: should have made one request to search from expected URL + const req = httpClient.expectOne( + `${environment.VTM_API_URI}/v3/technical-records/search/${searchParams.searchTerm}?searchCriteria=vin` + ); + expect(req.request.method).toBe('GET'); + + // Provide each request with a mock response + req.flush(mockData); + }); + + it('should validate the search term to be non unique when matching results are returned and are current or provisional', () => { + const searchParams = { searchTerm: 'A_VIN', type: 'vin' }; + const mockData = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel; + + service.isUnique(searchParams.searchTerm, SEARCH_TYPES.VIN).subscribe((response) => { + expect(response).toBe(false); + }); + + // Check for correct requests: should have made one request to search from expected URL + const req = httpClient.expectOne( + `${environment.VTM_API_URI}/v3/technical-records/search/${searchParams.searchTerm}?searchCriteria=vin` + ); + expect(req.request.method).toBe('GET'); + + // Provide each request with a mock response + req.flush(mockData); + }); + + it('should validate the search term to be non unique when vrm is used as a primary', () => { + const searchParams = { searchTerm: 'KP01 ABC', type: 'vrm' }; + const mockData = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel; + + service.isUnique(searchParams.searchTerm, SEARCH_TYPES.VRM).subscribe((response) => { + expect(response).toBe(false); + }); + + // Check for correct requests: should have made one request to search from expected URL + const req = httpClient.expectOne( + `${environment.VTM_API_URI}/v3/technical-records/search/${searchParams.searchTerm}?searchCriteria=primaryVrm` + ); + expect(req.request.method).toBe('GET'); + + // Provide each request with a mock response + req.flush(mockData); + }); + + it('should validate the search term to be unique when vrm is not used as a primary', () => { + const searchParams = { searchTerm: '12345', type: 'vrm' }; + const mockData = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel; + + service.isUnique(searchParams.searchTerm, SEARCH_TYPES.VRM).subscribe((response) => { + expect(response).toBe(true); + }); + + // Check for correct requests: should have made one request to search from expected URL + const req = httpClient.expectOne( + `${environment.VTM_API_URI}/v3/technical-records/search/${searchParams.searchTerm}?searchCriteria=primaryVrm` + ); + expect(req.request.method).toBe('GET'); + + // Provide each request with a mock response + req.flush(mockData); + }); + }); + + describe('getVehicleMakeAndModel', () => { + it('should return an empty string if there is no make and model', () => { + const record = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + } as unknown as TechRecordType<'put'>; + expect(service.getMakeAndModel(record)).toBe(''); + }); + it('for a PSV returns the chassis make and model', () => { + const record: V3TechRecordModel = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_vehicleType: VehicleTypes.PSV, + techRecord_chassisMake: 'test chassis make', + techRecord_chassisModel: 'chassis model', + } as unknown as V3TechRecordModel; + expect(service.getMakeAndModel(record)).toBe('test chassis make - chassis model'); + }); + it('for a any other type returns make and model', () => { + const record: V3TechRecordModel = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_vehicleType: VehicleTypes.HGV, + techRecord_make: 'make', + techRecord_model: 'model', + } as unknown as V3TechRecordModel; + expect(service.getMakeAndModel(record)).toBe('make - model'); + }); + }); + + describe('business logic methods', () => { + describe('updateEditingTechRecord', () => { + it(`should patch the missing information for the technical record and dispatch the action to update the editing vehicle record with the full vehicle record`, () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const mockVehicleRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as unknown as TechRecordType<'put'>; - - service.updateEditingTechRecord(mockVehicleRecord); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(updateEditingTechRecord({ vehicleTechRecord: mockVehicleRecord })); - }); - - it(`should patch from the selected record if the editing is + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const mockVehicleRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + } as unknown as TechRecordType<'put'>; + + service.updateEditingTechRecord(mockVehicleRecord); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith(updateEditingTechRecord({ vehicleTechRecord: mockVehicleRecord })); + }); + + it(`should patch from the selected record if the editing is not defined and dispatch the action to update the editing vehicle record with the full vehicle record`, () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const mockVehicleRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as unknown as TechRecordType<'put'>; - - service.updateEditingTechRecord(mockVehicleRecord); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(updateEditingTechRecord({ vehicleTechRecord: mockVehicleRecord })); - }); - - it('should update the number of axles based on the axles array', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const mockVehicleRecord = mockVehicleTechnicalRecord('trl'); - mockVehicleRecord.techRecord_noOfAxles = 0; - mockVehicleRecord.techRecord_axles = [{}, {}]; - - service.updateEditingTechRecord(mockVehicleRecord as TechRecordType<'put'>); - - expect(dispatchSpy).toHaveBeenCalledWith( - updateEditingTechRecord({ - vehicleTechRecord: { ...mockVehicleRecord, techRecord_axles: [{}, {}], techRecord_noOfAxles: 2 } as TechRecordType<'put'>, - }), - ); - }); - - it('override the editable tech record and dispatch the action to update the editing vehicle record with the full vehicle record', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const mockVehicleRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as unknown as TechRecordType<'put'>; - - const mockEditableVehicleRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'a random vin' } as unknown as TechRecordType<'put'>; - - service.updateEditingTechRecord(mockVehicleRecord); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).not.toHaveBeenCalledWith(updateEditingTechRecord({ vehicleTechRecord: mockEditableVehicleRecord })); - expect(dispatchSpy).toHaveBeenCalledWith(updateEditingTechRecord({ vehicleTechRecord: mockVehicleRecord })); - }); - - it('should throw an error if there is more than one tech record', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const mockVehicleRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as unknown as TechRecordType<'put'>; - service.updateEditingTechRecord(mockVehicleRecord); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(updateEditingTechRecord({ vehicleTechRecord: mockVehicleRecord })); - }); - }); - }); - - describe('getMakeAndModel', () => { - it('should should return the make and model', () => { - expect(service.getMakeAndModel({ techRecord_make: 'Test', techRecord_model: 'Car' } as V3TechRecordModel)).toBe('Test - Car'); - }); - - it('should return an empty string when the current record has no values for make and model', () => { - expect(service.getMakeAndModel({ techRecord_make: undefined, techRecord_model: undefined } as V3TechRecordModel)).toBe(''); - }); - }); - - describe('haveAxlesChanged', () => { - it('should return true if a property of the hgv gross axle has changed', () => { - const vehicleType = VehicleTypes.HGV; - const changes = { techRecord_grossDesignWeight: 1, techRecord_grossEecWeight: 2, techRecord_grossGbWeight: 3 } as Partial; - const spy = jest.spyOn(service, 'hasHgvGrossAxleChanged'); - const result = service.haveAxlesChanged(vehicleType, changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(true); - }); - - it('should return false if no properties of the hgv gross axle have changed', () => { - const vehicleType = VehicleTypes.HGV; - const changes = {} as Partial; - const spy = jest.spyOn(service, 'hasHgvGrossAxleChanged'); - const result = service.haveAxlesChanged(vehicleType, changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(false); - }); - - it('should return true if a property of the psv gross axle has changed', () => { - const vehicleType = VehicleTypes.PSV; - const changes = { - techRecord_grossKerbWeight: 1, techRecord_grossLadenWeight: 1, techRecord_grossDesignWeight: 1, techRecord_grossGbWeight: 1, - } as Partial; - - const spy = jest.spyOn(service, 'hasPsvGrossAxleChanged'); - const result = service.haveAxlesChanged(vehicleType, changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(true); - }); - - it('should return false if no properties of the psv gross axle have changed', () => { - const vehicleType = VehicleTypes.PSV; - const changes = {} as Partial; - const spy = jest.spyOn(service, 'hasPsvGrossAxleChanged'); - const result = service.haveAxlesChanged(vehicleType, changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(false); - }); - - it('should return true if a property of the trl gross axle has changed', () => { - const vehicleType = VehicleTypes.TRL; - const changes = { techRecord_grossDesignWeight: 1, techRecord_grossEecWeight: 2, techRecord_grossGbWeight: 3 } as Partial; - const spy = jest.spyOn(service, 'hasTrlGrossAxleChanged'); - const result = service.haveAxlesChanged(vehicleType, changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(true); - }); - - it('should return false if no properties of the trl gross axle have changed', () => { - const vehicleType = VehicleTypes.TRL; - const changes = {} as Partial; - const spy = jest.spyOn(service, 'hasTrlGrossAxleChanged'); - const result = service.haveAxlesChanged(vehicleType, changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(false); - }); - - it('should return true if a property of the max train axle has changed', () => { - const vehicleType = VehicleTypes.HGV; - const changes = { - techRecord_maxTrainDesignWeight: 5, - techRecord_maxTrainEecWeight: 3, - techRecord_maxTrainGbWeight: 3, - } as Partial; - - const spy = jest.spyOn(service, 'hasMaxTrainAxleChanged'); - const result = service.haveAxlesChanged(vehicleType, changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(true); - }); - it('should return true if a property of the hgv train axle has changed', () => { - const vehicleType = VehicleTypes.HGV; - const changes = { techRecord_trainDesignWeight: 1, techRecord_trainEecWeight: 2, techRecord_trainGbWeight: 3 } as Partial; - const spy = jest.spyOn(service, 'hasHgvTrainAxleChanged'); - const result = service.haveAxlesChanged(vehicleType, changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(true); - }); - - it('should return false if no properties of the hgv train axle have changed', () => { - const vehicleType = VehicleTypes.HGV; - const changes = {} as Partial; - const spy = jest.spyOn(service, 'hasHgvTrainAxleChanged'); - const result = service.haveAxlesChanged(vehicleType, changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(false); - }); - - it('should return true if a property of the psv train axle has changed', () => { - const vehicleType = VehicleTypes.PSV; - const changes = { techRecord_trainDesignWeight: 1, techRecord_trainEecWeight: 2, techRecord_trainGbWeight: 3 } as Partial; - const spy = jest.spyOn(service, 'hasPsvTrainAxleChanged'); - const result = service.haveAxlesChanged(vehicleType, changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(true); - }); - - it('should return false if no properties of the psv train axle have changed', () => { - const vehicleType = VehicleTypes.PSV; - const changes = {} as Partial; - const spy = jest.spyOn(service, 'hasPsvTrainAxleChanged'); - const result = service.haveAxlesChanged(vehicleType, changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(false); - }); - }); - - describe('hasPsvTrainAxleChanged', () => { - it('should return true if a property of the psv train axle has changed', () => { - const changes = { techRecord_trainDesignWeight: 1, techRecord_maxTrainGbWeight: 2 } as Partial; - const spy = jest.spyOn(service, 'hasPsvTrainAxleChanged'); - const result = service.hasPsvTrainAxleChanged(changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(true); - }); - - it('should return false if no properties of the psv train axle have changed', () => { - const changes = {} as Partial; - const spy = jest.spyOn(service, 'hasPsvTrainAxleChanged'); - const result = service.hasPsvTrainAxleChanged(changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(false); - }); - }); - - describe('hasHgvTrainAxleChanged', () => { - it('should return true if a property of the hgv train axle has changed', () => { - const changes = { techRecord_trainDesignWeight: 1, techRecord_maxTrainGbWeight: 2 } as Partial; - const spy = jest.spyOn(service, 'hasHgvTrainAxleChanged'); - const result = service.hasHgvTrainAxleChanged(changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(true); - }); - - it('should return false if no properties of the hgv train axle have changed', () => { - const changes = {} as Partial; - const spy = jest.spyOn(service, 'hasHgvTrainAxleChanged'); - const result = service.hasHgvTrainAxleChanged(changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(false); - }); - }); - - describe('hasTrlGrossAxleChanged', () => { - it('should return true if a property of the trl gross axle has changed', () => { - const changes = { techRecord_grossDesignWeight: 1, techRecord_grossEecWeight: 2, techRecord_grossGbWeight: 3 } as Partial; - const spy = jest.spyOn(service, 'hasTrlGrossAxleChanged'); - const result = service.hasTrlGrossAxleChanged(changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(true); - }); - - it('should return false if no properties of the trl gross axle have changed', () => { - const changes = {} as Partial; - const spy = jest.spyOn(service, 'hasTrlGrossAxleChanged'); - const result = service.hasTrlGrossAxleChanged(changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(false); - }); - }); - - describe('hasHgvGrossAxleChanged', () => { - it('should return true if a property of the hgv gross axle has changed', () => { - const changes = { techRecord_grossDesignWeight: 1, techRecord_grossEecWeight: 2, techRecord_grossGbWeight: 3 } as Partial; - const spy = jest.spyOn(service, 'hasHgvGrossAxleChanged'); - const result = service.hasHgvGrossAxleChanged(changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(true); - }); - - it('should return false if no properties of the hgv gross axle have changed', () => { - const changes = {} as Partial; - const spy = jest.spyOn(service, 'hasHgvGrossAxleChanged'); - const result = service.hasHgvGrossAxleChanged(changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(false); - }); - }); - - describe('hasMaxTrainAxleChanged', () => { - it('should return true if a property of the max train axle has changed', () => { - const changes = { techRecord_trainDesignWeight: 1, techRecord_maxTrainGbWeight: 2 } as Partial; - const spy = jest.spyOn(service, 'hasMaxTrainAxleChanged'); - const result = service.hasMaxTrainAxleChanged(changes); expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(true); - }); - - it('should return false if no properties of the max train axle have changed', () => { - const changes = {} as Partial; - const spy = jest.spyOn(service, 'hasMaxTrainAxleChanged'); - const result = service.hasMaxTrainAxleChanged(changes); expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(false); - }); - }); - - describe('hasPsvGrossAxleChanged', () => { - it('should return true if a property of the psv gross axle has changed', () => { - const changes = { techRecord_grossDesignWeight: 1, techRecord_grossEecWeight: 2, techRecord_grossGbWeight: 3 } as Partial; - const spy = jest.spyOn(service, 'hasPsvGrossAxleChanged'); - const result = service.hasPsvGrossAxleChanged(changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(true); - }); - - it('should return false if no properties of the psv gross axle have changed', () => { - const changes = {} as Partial; - const spy = jest.spyOn(service, 'hasPsvGrossAxleChanged'); - const result = service.hasPsvGrossAxleChanged(changes); - expect(spy).toHaveBeenCalledWith(changes); - expect(result).toBe(false); - }); - }); - - describe('getAxleFittingWeightValueFromLoadIndex', () => { - const loadIndex = '100'; - const loadIndexArray: ReferenceDataTyreLoadIndex[] = [{ - resourceType: ReferenceDataResourceType.Tyres, resourceKey: loadIndex, loadIndex: '825', - }]; - it('should return double the loadIndex value passed in if fitment code is set to single', () => { - const fitmentCodeType = FitmentCodeEnum.Single; - const result = service.getAxleFittingWeightValueFromLoadIndex(loadIndex, fitmentCodeType, loadIndexArray); - expect(result).toBe(1650); - }); - it('should return quadruple the loadIndex value passed in if fitment code is set to single', () => { - const fitmentCodeType = FitmentCodeEnum.Double; - const result = service.getAxleFittingWeightValueFromLoadIndex(loadIndex, fitmentCodeType, loadIndexArray); - expect(result).toBe(3300); - }); - }); - - describe('getVehicleTypeWithSmallTrl', () => { - it('should return small trl when the vehicle is a TRL and has an EU vehicle category of o1 or o2', () => { - const smallTrl1 = { - techRecord_vehicleType: VehicleTypes.TRL, - techRecord_euVehicleCategory: EUVehicleCategory.O1, - } as unknown as V3TechRecordModel; - - const smallTrl2 = { - techRecord_vehicleType: VehicleTypes.TRL, - techRecord_euVehicleCategory: EUVehicleCategory.O2, - } as unknown as V3TechRecordModel; - - expect(service.getVehicleTypeWithSmallTrl(smallTrl1)).toEqual(VehicleTypes.SMALL_TRL); - expect(service.getVehicleTypeWithSmallTrl(smallTrl2)).toEqual(VehicleTypes.SMALL_TRL); - }); - - it('should return the regular vehicle type when the vehicle is not a TRL', () => { - const hgv = { - techRecord_vehicleType: VehicleTypes.HGV, - } as unknown as V3TechRecordModel; - - expect(service.getVehicleTypeWithSmallTrl(hgv)).toEqual(VehicleTypes.HGV); - }); - - it('should return TRL when the vehicle is a TRL and has an EU vehicle category which is neither o1 or o2', () => { - const trl = { - techRecord_vehicleType: VehicleTypes.TRL, - techRecord_euVehicleCategory: EUVehicleCategory.O3, - } as unknown as V3TechRecordModel; - - expect(service.getVehicleTypeWithSmallTrl(trl)).toEqual(VehicleTypes.TRL); - }); - }); - - describe('generateEditingVehicleTechnicalRecordFromVehicleType', () => { - it('should dispatch the createVehicle action with the provided vehicle type', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.generateEditingVehicleTechnicalRecordFromVehicleType(VehicleTypes.CAR); - expect(dispatchSpy).toHaveBeenCalledWith({ - techRecord_vehicleType: 'car', - type: '[Technical Record Service] createVehicle', - }); - }); - }); - - describe('validateVinForUpdate', () => { - it('should return an async validator which displays an appropriate error message when no new VIN is provided', async () => { - const vin = 'vin'; - const control = new FormControl('vin'); - const isUniqueSpy = jest.spyOn(service, 'isUnique') - .mockReturnValue(of(false)); - - const validator = service.validateVinForUpdate(vin); - await expect(firstValueFrom(from(validator(control)))) - .resolves.toEqual({ - validateVin: { - message: 'You must provide a new VIN', - }, - }); - - expect(isUniqueSpy).toHaveBeenCalledWith(control.value, SEARCH_TYPES.VIN); - }); - - it('should return an async validator which returns null when the VIN provided is unique', async () => { - const vin = 'vin'; - const control = new FormControl('new vin'); - const isUniqueSpy = jest.spyOn(service, 'isUnique') - .mockReturnValue(of(true)); - - const validator = service.validateVinForUpdate(vin); - await expect(firstValueFrom(from(validator(control)))).resolves.toBeNull(); - expect(isUniqueSpy).toHaveBeenCalledWith(control.value, SEARCH_TYPES.VIN); - }); - - it('should return an async validator which returns an error message when the VIN is different, but is in use', async () => { - const vin = 'vin'; - const control = new FormControl('new vin'); - const isUniqueSpy = jest.spyOn(service, 'isUnique') - .mockReturnValue(of(false)); - - const validator = service.validateVinForUpdate(vin); - await expect(firstValueFrom(from(validator(control)))) - .resolves.toEqual({ - validateVin: { message: 'This VIN already exists, if you continue it will be associated with two vehicles' }, - }); - - expect(isUniqueSpy).toHaveBeenCalledWith(control.value, SEARCH_TYPES.VIN); - }); - }); - - describe('validateVrmDoesNotExist', () => { - beforeEach(() => { - jest.spyOn(techRecordHttpService, 'search$').mockReturnValue(of([])); - }); - - it('should emit empty if the control has a falsy value', async () => { - const previousVrm = 'previous vrm'; - const control = new FormControl(null); - const checkVrmNotActiveSpy = jest.spyOn(service, 'checkVrmNotActive'); - - const validator = service.validateVrmDoesNotExist(previousVrm); - await expect(firstValueFrom(from(validator(control)))) - .rejects.toEqual(new EmptyError()); - - expect(checkVrmNotActiveSpy).toHaveBeenCalledTimes(0); - }); - - it('should return the result of checkVrm not active when the value of the provide control is truthy', async () => { - const previousVrm = 'previous vrm'; - const control = new FormControl('truthy value'); - const checkVrmNotActiveSpy = jest.spyOn(service, 'checkVrmNotActive'); - - const validator = service.validateVrmDoesNotExist(previousVrm); - await expect(firstValueFrom(from(validator(control)))) - .resolves.toBeDefined(); - - expect(checkVrmNotActiveSpy).toHaveBeenCalledTimes(1); - }); - }); - - describe('validateVrmForCherishedTransfer', () => { - beforeEach(() => { - jest.spyOn(techRecordHttpService, 'search$').mockReturnValue(of([])); - }); - - it('should return empty is the value of the control is falsy', async () => { - const control = new FormControl(null); - const searchSpy = jest.spyOn(techRecordHttpService, 'search$'); - const checkVrmNotActiveSpy = jest.spyOn(service, 'checkVrmNotActive'); - - const validator = service.validateVrmForCherishedTransfer(); - await expect(firstValueFrom(from(validator(control)))) - .rejects.toEqual(new EmptyError()); - - expect(searchSpy).toHaveBeenCalledTimes(0); - expect(checkVrmNotActiveSpy).toHaveBeenCalledTimes(0); - }); - - it('should return the result of checkVrmNotActive when the control root has no third mark', async () => { - const form = new FormGroup({ - thirdMark: new FormControl(null), - previousVrm: new FormControl('previous vrm'), - control: new FormControl('current vrm'), - }); - - const searchSpy = jest.spyOn(techRecordHttpService, 'search$'); - const checkVrmNotActiveSpy = jest.spyOn(service, 'checkVrmNotActive'); - - const validator = service.validateVrmForCherishedTransfer(); - await expect(firstValueFrom(from(validator(form.controls.control)))) - .resolves.toBeDefined(); - - expect(searchSpy).toHaveBeenCalledTimes(1); - expect(checkVrmNotActiveSpy).toHaveBeenCalledTimes(1); - }); - - it('should return null when a thirdMark is provided, and a current record exists with the previous VRM', async () => { - const form = new FormGroup({ - thirdMark: new FormControl('third mark'), - previousVrm: new FormControl('previous vrm'), - control: new FormControl('current vrm'), - }); - - const checkVrmNotActiveSpy = jest.spyOn(service, 'checkVrmNotActive'); - const searchSpy = jest.spyOn(techRecordHttpService, 'search$') - .mockReturnValue(of([ - { - primaryVrm: 'previous vrm', - techRecord_statusCode: StatusCodes.CURRENT, - } as TechRecordSearchSchema, - ])); - - const validator = service.validateVrmForCherishedTransfer(); - await expect(firstValueFrom(from(validator(form.controls.control)))) - .resolves.toBeNull(); - - expect(searchSpy).toHaveBeenCalledTimes(1); - expect(checkVrmNotActiveSpy).toHaveBeenCalledTimes(0); - }); - - it('should return an appropriate error message if there is a third mark, but the previous vrm does not belong to a current record', async () => { - const form = new FormGroup({ - thirdMark: new FormControl('third mark'), - previousVrm: new FormControl('previous vrm'), - control: new FormControl('current vrm'), - }); - - const checkVrmNotActiveSpy = jest.spyOn(service, 'checkVrmNotActive'); - const searchSpy = jest.spyOn(techRecordHttpService, 'search$') - .mockReturnValue(of([ - { - primaryVrm: 'previous vrm', - techRecord_statusCode: StatusCodes.PROVISIONAL, - } as TechRecordSearchSchema, - ])); - - const validator = service.validateVrmForCherishedTransfer(); - await expect(firstValueFrom(from(validator(form.controls.control)))) - .resolves.toEqual({ - validateVrm: { - message: 'This VRM does not exist on a current record', - }, - }); - - expect(searchSpy).toHaveBeenCalledTimes(1); - expect(checkVrmNotActiveSpy).toHaveBeenCalledTimes(0); - }); - }); - - describe('clearEditingTechRecord', () => { - it('should dispatch the updateEditingTechRecordCancel action', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.clearEditingTechRecord(); - expect(dispatchSpy).toHaveBeenCalledWith({ - type: '[Technical Record Service] updateEditingTechRecordCancel', - }); - }); - }); - - describe('clearSectionTemplateStates', () => { - it('should dispatch the clearAllSectionStates action', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.clearSectionTemplateStates(); - expect(dispatchSpy).toHaveBeenCalledWith({ - type: '[Technical Record Service] clearAllSectionState', - }); - }); - }); - - describe('checkVrmNotActive', () => { - beforeEach(() => { - jest.spyOn(techRecordHttpService, 'search$').mockReturnValue(of([])); - }); - - it('should not display an appropriate error message when the provided VRM is the same as the current', async () => { - const vrm = 'vrm'; - const control = new FormControl(vrm); - const spy = jest.spyOn(techRecordHttpService, 'search$'); - - await expect(firstValueFrom(service.checkVrmNotActive(control, vrm))) - .resolves - .toEqual({ validateVrm: { message: 'You must provide a new VRM' } }); - - expect(spy).toHaveBeenCalledWith(SEARCH_TYPES.VRM, vrm); - }); - - it('should determine if the VRM is being used by a current tech record, and display an appropriate message', async () => { - const vrm = 'vrm'; - const control = new FormControl('new vrm'); - const spy = jest.spyOn(techRecordHttpService, 'search$') - .mockReturnValue(of([ - { - primaryVrm: 'new vrm', - vin: 'vin', - techRecord_statusCode: StatusCodes.CURRENT, - } as unknown as TechRecordSearchSchema, - ])); - - await expect(firstValueFrom(service.checkVrmNotActive(control, vrm))) - .resolves - .toEqual({ - validateVrm: { - message: `A current technical record already exists for + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const mockVehicleRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + } as unknown as TechRecordType<'put'>; + + service.updateEditingTechRecord(mockVehicleRecord); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith(updateEditingTechRecord({ vehicleTechRecord: mockVehicleRecord })); + }); + + it('should update the number of axles based on the axles array', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const mockVehicleRecord = mockVehicleTechnicalRecord('trl'); + mockVehicleRecord.techRecord_noOfAxles = 0; + mockVehicleRecord.techRecord_axles = [{}, {}]; + + service.updateEditingTechRecord(mockVehicleRecord as TechRecordType<'put'>); + + expect(dispatchSpy).toHaveBeenCalledWith( + updateEditingTechRecord({ + vehicleTechRecord: { + ...mockVehicleRecord, + techRecord_axles: [{}, {}], + techRecord_noOfAxles: 2, + } as TechRecordType<'put'>, + }) + ); + }); + + it('override the editable tech record and dispatch the action to update the editing vehicle record with the full vehicle record', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const mockVehicleRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + } as unknown as TechRecordType<'put'>; + + const mockEditableVehicleRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'a random vin', + } as unknown as TechRecordType<'put'>; + + service.updateEditingTechRecord(mockVehicleRecord); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).not.toHaveBeenCalledWith( + updateEditingTechRecord({ vehicleTechRecord: mockEditableVehicleRecord }) + ); + expect(dispatchSpy).toHaveBeenCalledWith(updateEditingTechRecord({ vehicleTechRecord: mockVehicleRecord })); + }); + + it('should throw an error if there is more than one tech record', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const mockVehicleRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + } as unknown as TechRecordType<'put'>; + service.updateEditingTechRecord(mockVehicleRecord); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith(updateEditingTechRecord({ vehicleTechRecord: mockVehicleRecord })); + }); + }); + }); + + describe('getMakeAndModel', () => { + it('should should return the make and model', () => { + expect(service.getMakeAndModel({ techRecord_make: 'Test', techRecord_model: 'Car' } as V3TechRecordModel)).toBe( + 'Test - Car' + ); + }); + + it('should return an empty string when the current record has no values for make and model', () => { + expect( + service.getMakeAndModel({ techRecord_make: undefined, techRecord_model: undefined } as V3TechRecordModel) + ).toBe(''); + }); + }); + + describe('haveAxlesChanged', () => { + it('should return true if a property of the hgv gross axle has changed', () => { + const vehicleType = VehicleTypes.HGV; + const changes = { + techRecord_grossDesignWeight: 1, + techRecord_grossEecWeight: 2, + techRecord_grossGbWeight: 3, + } as Partial; + const spy = jest.spyOn(service, 'hasHgvGrossAxleChanged'); + const result = service.haveAxlesChanged(vehicleType, changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(true); + }); + + it('should return false if no properties of the hgv gross axle have changed', () => { + const vehicleType = VehicleTypes.HGV; + const changes = {} as Partial; + const spy = jest.spyOn(service, 'hasHgvGrossAxleChanged'); + const result = service.haveAxlesChanged(vehicleType, changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(false); + }); + + it('should return true if a property of the psv gross axle has changed', () => { + const vehicleType = VehicleTypes.PSV; + const changes = { + techRecord_grossKerbWeight: 1, + techRecord_grossLadenWeight: 1, + techRecord_grossDesignWeight: 1, + techRecord_grossGbWeight: 1, + } as Partial; + + const spy = jest.spyOn(service, 'hasPsvGrossAxleChanged'); + const result = service.haveAxlesChanged(vehicleType, changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(true); + }); + + it('should return false if no properties of the psv gross axle have changed', () => { + const vehicleType = VehicleTypes.PSV; + const changes = {} as Partial; + const spy = jest.spyOn(service, 'hasPsvGrossAxleChanged'); + const result = service.haveAxlesChanged(vehicleType, changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(false); + }); + + it('should return true if a property of the trl gross axle has changed', () => { + const vehicleType = VehicleTypes.TRL; + const changes = { + techRecord_grossDesignWeight: 1, + techRecord_grossEecWeight: 2, + techRecord_grossGbWeight: 3, + } as Partial; + const spy = jest.spyOn(service, 'hasTrlGrossAxleChanged'); + const result = service.haveAxlesChanged(vehicleType, changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(true); + }); + + it('should return false if no properties of the trl gross axle have changed', () => { + const vehicleType = VehicleTypes.TRL; + const changes = {} as Partial; + const spy = jest.spyOn(service, 'hasTrlGrossAxleChanged'); + const result = service.haveAxlesChanged(vehicleType, changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(false); + }); + + it('should return true if a property of the max train axle has changed', () => { + const vehicleType = VehicleTypes.HGV; + const changes = { + techRecord_maxTrainDesignWeight: 5, + techRecord_maxTrainEecWeight: 3, + techRecord_maxTrainGbWeight: 3, + } as Partial; + + const spy = jest.spyOn(service, 'hasMaxTrainAxleChanged'); + const result = service.haveAxlesChanged(vehicleType, changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(true); + }); + it('should return true if a property of the hgv train axle has changed', () => { + const vehicleType = VehicleTypes.HGV; + const changes = { + techRecord_trainDesignWeight: 1, + techRecord_trainEecWeight: 2, + techRecord_trainGbWeight: 3, + } as Partial; + const spy = jest.spyOn(service, 'hasHgvTrainAxleChanged'); + const result = service.haveAxlesChanged(vehicleType, changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(true); + }); + + it('should return false if no properties of the hgv train axle have changed', () => { + const vehicleType = VehicleTypes.HGV; + const changes = {} as Partial; + const spy = jest.spyOn(service, 'hasHgvTrainAxleChanged'); + const result = service.haveAxlesChanged(vehicleType, changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(false); + }); + + it('should return true if a property of the psv train axle has changed', () => { + const vehicleType = VehicleTypes.PSV; + const changes = { + techRecord_trainDesignWeight: 1, + techRecord_trainEecWeight: 2, + techRecord_trainGbWeight: 3, + } as Partial; + const spy = jest.spyOn(service, 'hasPsvTrainAxleChanged'); + const result = service.haveAxlesChanged(vehicleType, changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(true); + }); + + it('should return false if no properties of the psv train axle have changed', () => { + const vehicleType = VehicleTypes.PSV; + const changes = {} as Partial; + const spy = jest.spyOn(service, 'hasPsvTrainAxleChanged'); + const result = service.haveAxlesChanged(vehicleType, changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(false); + }); + }); + + describe('hasPsvTrainAxleChanged', () => { + it('should return true if a property of the psv train axle has changed', () => { + const changes = { techRecord_trainDesignWeight: 1, techRecord_maxTrainGbWeight: 2 } as Partial; + const spy = jest.spyOn(service, 'hasPsvTrainAxleChanged'); + const result = service.hasPsvTrainAxleChanged(changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(true); + }); + + it('should return false if no properties of the psv train axle have changed', () => { + const changes = {} as Partial; + const spy = jest.spyOn(service, 'hasPsvTrainAxleChanged'); + const result = service.hasPsvTrainAxleChanged(changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(false); + }); + }); + + describe('hasHgvTrainAxleChanged', () => { + it('should return true if a property of the hgv train axle has changed', () => { + const changes = { techRecord_trainDesignWeight: 1, techRecord_maxTrainGbWeight: 2 } as Partial; + const spy = jest.spyOn(service, 'hasHgvTrainAxleChanged'); + const result = service.hasHgvTrainAxleChanged(changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(true); + }); + + it('should return false if no properties of the hgv train axle have changed', () => { + const changes = {} as Partial; + const spy = jest.spyOn(service, 'hasHgvTrainAxleChanged'); + const result = service.hasHgvTrainAxleChanged(changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(false); + }); + }); + + describe('hasTrlGrossAxleChanged', () => { + it('should return true if a property of the trl gross axle has changed', () => { + const changes = { + techRecord_grossDesignWeight: 1, + techRecord_grossEecWeight: 2, + techRecord_grossGbWeight: 3, + } as Partial; + const spy = jest.spyOn(service, 'hasTrlGrossAxleChanged'); + const result = service.hasTrlGrossAxleChanged(changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(true); + }); + + it('should return false if no properties of the trl gross axle have changed', () => { + const changes = {} as Partial; + const spy = jest.spyOn(service, 'hasTrlGrossAxleChanged'); + const result = service.hasTrlGrossAxleChanged(changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(false); + }); + }); + + describe('hasHgvGrossAxleChanged', () => { + it('should return true if a property of the hgv gross axle has changed', () => { + const changes = { + techRecord_grossDesignWeight: 1, + techRecord_grossEecWeight: 2, + techRecord_grossGbWeight: 3, + } as Partial; + const spy = jest.spyOn(service, 'hasHgvGrossAxleChanged'); + const result = service.hasHgvGrossAxleChanged(changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(true); + }); + + it('should return false if no properties of the hgv gross axle have changed', () => { + const changes = {} as Partial; + const spy = jest.spyOn(service, 'hasHgvGrossAxleChanged'); + const result = service.hasHgvGrossAxleChanged(changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(false); + }); + }); + + describe('hasMaxTrainAxleChanged', () => { + it('should return true if a property of the max train axle has changed', () => { + const changes = { techRecord_trainDesignWeight: 1, techRecord_maxTrainGbWeight: 2 } as Partial; + const spy = jest.spyOn(service, 'hasMaxTrainAxleChanged'); + const result = service.hasMaxTrainAxleChanged(changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(true); + }); + + it('should return false if no properties of the max train axle have changed', () => { + const changes = {} as Partial; + const spy = jest.spyOn(service, 'hasMaxTrainAxleChanged'); + const result = service.hasMaxTrainAxleChanged(changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(false); + }); + }); + + describe('hasPsvGrossAxleChanged', () => { + it('should return true if a property of the psv gross axle has changed', () => { + const changes = { + techRecord_grossDesignWeight: 1, + techRecord_grossEecWeight: 2, + techRecord_grossGbWeight: 3, + } as Partial; + const spy = jest.spyOn(service, 'hasPsvGrossAxleChanged'); + const result = service.hasPsvGrossAxleChanged(changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(true); + }); + + it('should return false if no properties of the psv gross axle have changed', () => { + const changes = {} as Partial; + const spy = jest.spyOn(service, 'hasPsvGrossAxleChanged'); + const result = service.hasPsvGrossAxleChanged(changes); + expect(spy).toHaveBeenCalledWith(changes); + expect(result).toBe(false); + }); + }); + + describe('getAxleFittingWeightValueFromLoadIndex', () => { + const loadIndex = '100'; + const loadIndexArray: ReferenceDataTyreLoadIndex[] = [ + { + resourceType: ReferenceDataResourceType.Tyres, + resourceKey: loadIndex, + loadIndex: '825', + }, + ]; + it('should return double the loadIndex value passed in if fitment code is set to single', () => { + const fitmentCodeType = FitmentCodeEnum.Single; + const result = service.getAxleFittingWeightValueFromLoadIndex(loadIndex, fitmentCodeType, loadIndexArray); + expect(result).toBe(1650); + }); + it('should return quadruple the loadIndex value passed in if fitment code is set to single', () => { + const fitmentCodeType = FitmentCodeEnum.Double; + const result = service.getAxleFittingWeightValueFromLoadIndex(loadIndex, fitmentCodeType, loadIndexArray); + expect(result).toBe(3300); + }); + }); + + describe('getVehicleTypeWithSmallTrl', () => { + it('should return small trl when the vehicle is a TRL and has an EU vehicle category of o1 or o2', () => { + const smallTrl1 = { + techRecord_vehicleType: VehicleTypes.TRL, + techRecord_euVehicleCategory: EUVehicleCategory.O1, + } as unknown as V3TechRecordModel; + + const smallTrl2 = { + techRecord_vehicleType: VehicleTypes.TRL, + techRecord_euVehicleCategory: EUVehicleCategory.O2, + } as unknown as V3TechRecordModel; + + expect(service.getVehicleTypeWithSmallTrl(smallTrl1)).toEqual(VehicleTypes.SMALL_TRL); + expect(service.getVehicleTypeWithSmallTrl(smallTrl2)).toEqual(VehicleTypes.SMALL_TRL); + }); + + it('should return the regular vehicle type when the vehicle is not a TRL', () => { + const hgv = { + techRecord_vehicleType: VehicleTypes.HGV, + } as unknown as V3TechRecordModel; + + expect(service.getVehicleTypeWithSmallTrl(hgv)).toEqual(VehicleTypes.HGV); + }); + + it('should return TRL when the vehicle is a TRL and has an EU vehicle category which is neither o1 or o2', () => { + const trl = { + techRecord_vehicleType: VehicleTypes.TRL, + techRecord_euVehicleCategory: EUVehicleCategory.O3, + } as unknown as V3TechRecordModel; + + expect(service.getVehicleTypeWithSmallTrl(trl)).toEqual(VehicleTypes.TRL); + }); + }); + + describe('generateEditingVehicleTechnicalRecordFromVehicleType', () => { + it('should dispatch the createVehicle action with the provided vehicle type', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.generateEditingVehicleTechnicalRecordFromVehicleType(VehicleTypes.CAR); + expect(dispatchSpy).toHaveBeenCalledWith({ + techRecord_vehicleType: 'car', + type: '[Technical Record Service] createVehicle', + }); + }); + }); + + describe('validateVinForUpdate', () => { + it('should return an async validator which displays an appropriate error message when no new VIN is provided', async () => { + const vin = 'vin'; + const control = new FormControl('vin'); + const isUniqueSpy = jest.spyOn(service, 'isUnique').mockReturnValue(of(false)); + + const validator = service.validateVinForUpdate(vin); + await expect(firstValueFrom(from(validator(control)))).resolves.toEqual({ + validateVin: { + message: 'You must provide a new VIN', + }, + }); + + expect(isUniqueSpy).toHaveBeenCalledWith(control.value, SEARCH_TYPES.VIN); + }); + + it('should return an async validator which returns null when the VIN provided is unique', async () => { + const vin = 'vin'; + const control = new FormControl('new vin'); + const isUniqueSpy = jest.spyOn(service, 'isUnique').mockReturnValue(of(true)); + + const validator = service.validateVinForUpdate(vin); + await expect(firstValueFrom(from(validator(control)))).resolves.toBeNull(); + expect(isUniqueSpy).toHaveBeenCalledWith(control.value, SEARCH_TYPES.VIN); + }); + + it('should return an async validator which returns an error message when the VIN is different, but is in use', async () => { + const vin = 'vin'; + const control = new FormControl('new vin'); + const isUniqueSpy = jest.spyOn(service, 'isUnique').mockReturnValue(of(false)); + + const validator = service.validateVinForUpdate(vin); + await expect(firstValueFrom(from(validator(control)))).resolves.toEqual({ + validateVin: { message: 'This VIN already exists, if you continue it will be associated with two vehicles' }, + }); + + expect(isUniqueSpy).toHaveBeenCalledWith(control.value, SEARCH_TYPES.VIN); + }); + }); + + describe('validateVrmDoesNotExist', () => { + beforeEach(() => { + jest.spyOn(techRecordHttpService, 'search$').mockReturnValue(of([])); + }); + + it('should emit empty if the control has a falsy value', async () => { + const previousVrm = 'previous vrm'; + const control = new FormControl(null); + const checkVrmNotActiveSpy = jest.spyOn(service, 'checkVrmNotActive'); + + const validator = service.validateVrmDoesNotExist(previousVrm); + await expect(firstValueFrom(from(validator(control)))).rejects.toEqual(new EmptyError()); + + expect(checkVrmNotActiveSpy).toHaveBeenCalledTimes(0); + }); + + it('should return the result of checkVrm not active when the value of the provide control is truthy', async () => { + const previousVrm = 'previous vrm'; + const control = new FormControl('truthy value'); + const checkVrmNotActiveSpy = jest.spyOn(service, 'checkVrmNotActive'); + + const validator = service.validateVrmDoesNotExist(previousVrm); + await expect(firstValueFrom(from(validator(control)))).resolves.toBeDefined(); + + expect(checkVrmNotActiveSpy).toHaveBeenCalledTimes(1); + }); + }); + + describe('validateVrmForCherishedTransfer', () => { + beforeEach(() => { + jest.spyOn(techRecordHttpService, 'search$').mockReturnValue(of([])); + }); + + it('should return empty is the value of the control is falsy', async () => { + const control = new FormControl(null); + const searchSpy = jest.spyOn(techRecordHttpService, 'search$'); + const checkVrmNotActiveSpy = jest.spyOn(service, 'checkVrmNotActive'); + + const validator = service.validateVrmForCherishedTransfer(); + await expect(firstValueFrom(from(validator(control)))).rejects.toEqual(new EmptyError()); + + expect(searchSpy).toHaveBeenCalledTimes(0); + expect(checkVrmNotActiveSpy).toHaveBeenCalledTimes(0); + }); + + it('should return the result of checkVrmNotActive when the control root has no third mark', async () => { + const form = new FormGroup({ + thirdMark: new FormControl(null), + previousVrm: new FormControl('previous vrm'), + control: new FormControl('current vrm'), + }); + + const searchSpy = jest.spyOn(techRecordHttpService, 'search$'); + const checkVrmNotActiveSpy = jest.spyOn(service, 'checkVrmNotActive'); + + const validator = service.validateVrmForCherishedTransfer(); + await expect(firstValueFrom(from(validator(form.controls.control)))).resolves.toBeDefined(); + + expect(searchSpy).toHaveBeenCalledTimes(1); + expect(checkVrmNotActiveSpy).toHaveBeenCalledTimes(1); + }); + + it('should return null when a thirdMark is provided, and a current record exists with the previous VRM', async () => { + const form = new FormGroup({ + thirdMark: new FormControl('third mark'), + previousVrm: new FormControl('previous vrm'), + control: new FormControl('current vrm'), + }); + + const checkVrmNotActiveSpy = jest.spyOn(service, 'checkVrmNotActive'); + const searchSpy = jest.spyOn(techRecordHttpService, 'search$').mockReturnValue( + of([ + { + primaryVrm: 'previous vrm', + techRecord_statusCode: StatusCodes.CURRENT, + } as TechRecordSearchSchema, + ]) + ); + + const validator = service.validateVrmForCherishedTransfer(); + await expect(firstValueFrom(from(validator(form.controls.control)))).resolves.toBeNull(); + + expect(searchSpy).toHaveBeenCalledTimes(1); + expect(checkVrmNotActiveSpy).toHaveBeenCalledTimes(0); + }); + + it('should return an appropriate error message if there is a third mark, but the previous vrm does not belong to a current record', async () => { + const form = new FormGroup({ + thirdMark: new FormControl('third mark'), + previousVrm: new FormControl('previous vrm'), + control: new FormControl('current vrm'), + }); + + const checkVrmNotActiveSpy = jest.spyOn(service, 'checkVrmNotActive'); + const searchSpy = jest.spyOn(techRecordHttpService, 'search$').mockReturnValue( + of([ + { + primaryVrm: 'previous vrm', + techRecord_statusCode: StatusCodes.PROVISIONAL, + } as TechRecordSearchSchema, + ]) + ); + + const validator = service.validateVrmForCherishedTransfer(); + await expect(firstValueFrom(from(validator(form.controls.control)))).resolves.toEqual({ + validateVrm: { + message: 'This VRM does not exist on a current record', + }, + }); + + expect(searchSpy).toHaveBeenCalledTimes(1); + expect(checkVrmNotActiveSpy).toHaveBeenCalledTimes(0); + }); + }); + + describe('clearEditingTechRecord', () => { + it('should dispatch the updateEditingTechRecordCancel action', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.clearEditingTechRecord(); + expect(dispatchSpy).toHaveBeenCalledWith({ + type: '[Technical Record Service] updateEditingTechRecordCancel', + }); + }); + }); + + describe('clearSectionTemplateStates', () => { + it('should dispatch the clearAllSectionStates action', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.clearSectionTemplateStates(); + expect(dispatchSpy).toHaveBeenCalledWith({ + type: '[Technical Record Service] clearAllSectionState', + }); + }); + }); + + describe('checkVrmNotActive', () => { + beforeEach(() => { + jest.spyOn(techRecordHttpService, 'search$').mockReturnValue(of([])); + }); + + it('should not display an appropriate error message when the provided VRM is the same as the current', async () => { + const vrm = 'vrm'; + const control = new FormControl(vrm); + const spy = jest.spyOn(techRecordHttpService, 'search$'); + + await expect(firstValueFrom(service.checkVrmNotActive(control, vrm))).resolves.toEqual({ + validateVrm: { message: 'You must provide a new VRM' }, + }); + + expect(spy).toHaveBeenCalledWith(SEARCH_TYPES.VRM, vrm); + }); + + it('should determine if the VRM is being used by a current tech record, and display an appropriate message', async () => { + const vrm = 'vrm'; + const control = new FormControl('new vrm'); + const spy = jest.spyOn(techRecordHttpService, 'search$').mockReturnValue( + of([ + { + primaryVrm: 'new vrm', + vin: 'vin', + techRecord_statusCode: StatusCodes.CURRENT, + } as unknown as TechRecordSearchSchema, + ]) + ); + + await expect(firstValueFrom(service.checkVrmNotActive(control, vrm))).resolves.toEqual({ + validateVrm: { + message: `A current technical record already exists for new vrm with the VIN number vin. Please fill in the third mark field`, - }, - }); - - expect(spy).toHaveBeenCalledWith(SEARCH_TYPES.VRM, 'new vrm'); - }); - - it('should determine if the VRM is being used by a provisional tech record, and display an appropriate message', async () => { - const vrm = 'vrm'; - const control = new FormControl('new vrm'); - const spy = jest.spyOn(techRecordHttpService, 'search$') - .mockReturnValue(of([ - { - primaryVrm: 'new vrm', - vin: 'vin', - techRecord_statusCode: StatusCodes.PROVISIONAL, - } as unknown as TechRecordSearchSchema, - ])); - - await expect(firstValueFrom(service.checkVrmNotActive(control, vrm))) - .resolves - .toEqual({ - validateVrm: { - message: 'This VRM already exists on a provisional record with the VIN: vin', - }, - }); - - expect(spy).toHaveBeenCalledWith(SEARCH_TYPES.VRM, 'new vrm'); - }); - - it('should return null when the VRM is not being used by a current or provisional record', async () => { - const vrm = 'vrm'; - const control = new FormControl('new vrm'); - const spy = jest.spyOn(techRecordHttpService, 'search$').mockReturnValue(of([])); - - await expect(firstValueFrom(service.checkVrmNotActive(control, vrm))) - .resolves - .toBeNull(); - - expect(spy).toHaveBeenCalledWith(SEARCH_TYPES.VRM, 'new vrm'); - }); - }); + }, + }); + + expect(spy).toHaveBeenCalledWith(SEARCH_TYPES.VRM, 'new vrm'); + }); + + it('should determine if the VRM is being used by a provisional tech record, and display an appropriate message', async () => { + const vrm = 'vrm'; + const control = new FormControl('new vrm'); + const spy = jest.spyOn(techRecordHttpService, 'search$').mockReturnValue( + of([ + { + primaryVrm: 'new vrm', + vin: 'vin', + techRecord_statusCode: StatusCodes.PROVISIONAL, + } as unknown as TechRecordSearchSchema, + ]) + ); + + await expect(firstValueFrom(service.checkVrmNotActive(control, vrm))).resolves.toEqual({ + validateVrm: { + message: 'This VRM already exists on a provisional record with the VIN: vin', + }, + }); + + expect(spy).toHaveBeenCalledWith(SEARCH_TYPES.VRM, 'new vrm'); + }); + + it('should return null when the VRM is not being used by a current or provisional record', async () => { + const vrm = 'vrm'; + const control = new FormControl('new vrm'); + const spy = jest.spyOn(techRecordHttpService, 'search$').mockReturnValue(of([])); + + await expect(firstValueFrom(service.checkVrmNotActive(control, vrm))).resolves.toBeNull(); + + expect(spy).toHaveBeenCalledWith(SEARCH_TYPES.VRM, 'new vrm'); + }); + }); }); diff --git a/src/app/services/technical-record/technical-record.service.ts b/src/app/services/technical-record/technical-record.service.ts index b5320a752a..c956482078 100644 --- a/src/app/services/technical-record/technical-record.service.ts +++ b/src/app/services/technical-record/technical-record.service.ts @@ -5,329 +5,386 @@ import { AxleTyreProperties } from '@api/vehicle'; import { EUVehicleCategory } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/euVehicleCategory.enum.js'; import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; -import { TechRecordGETHGV, TechRecordGETPSV, TechRecordGETTRL } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb-vehicle-type'; +import { + TechRecordGETHGV, + TechRecordGETPSV, + TechRecordGETTRL, +} from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb-vehicle-type'; import { ReferenceDataTyreLoadIndex } from '@models/reference-data.model'; import { SEARCH_TYPES } from '@models/search-types-enum'; import { - StatusCodes, - TechRecordModel, - V3TechRecordModel, - VehicleTechRecordModel, - VehicleTypes, + StatusCodes, + TechRecordModel, + V3TechRecordModel, + VehicleTechRecordModel, + VehicleTypes, } from '@models/vehicle-tech-record.model'; import { Store, select } from '@ngrx/store'; import { RouterService } from '@services/router/router.service'; import { TechnicalRecordHttpService } from '@services/technical-record-http/technical-record-http.service'; import { - selectTechRecordSearchResults, - selectTechRecordSearchResultsBySystemNumber, + selectTechRecordSearchResults, + selectTechRecordSearchResultsBySystemNumber, } from '@store/tech-record-search/selector/tech-record-search.selector'; import { - clearAllSectionStates, - createVehicle, - selectSectionState, - selectTechRecord, - selectTechRecordHistory, - techRecord, - updateEditingTechRecord, - updateEditingTechRecordCancel, + clearAllSectionStates, + createVehicle, + selectSectionState, + selectTechRecord, + selectTechRecordHistory, + techRecord, + updateEditingTechRecord, + updateEditingTechRecordCancel, } from '@store/technical-records'; import { cloneDeep } from 'lodash'; import { - Observable, catchError, combineLatest, debounceTime, filter, map, of, switchMap, take, tap, throwError, + Observable, + catchError, + combineLatest, + debounceTime, + filter, + map, + of, + switchMap, + take, + tap, + throwError, } from 'rxjs'; import FitmentCodeEnum = AxleTyreProperties.FitmentCodeEnum; @Injectable({ providedIn: 'root' }) export class TechnicalRecordService { - constructor(private store: Store, private techRecordHttpService: TechnicalRecordHttpService, private routerService: RouterService) { } - - getVehicleTypeWithSmallTrl(technicalRecord: V3TechRecordModel): VehicleTypes { - return technicalRecord.techRecord_vehicleType === VehicleTypes.TRL - && (technicalRecord.techRecord_euVehicleCategory === EUVehicleCategory.O1 - || technicalRecord.techRecord_euVehicleCategory === EUVehicleCategory.O2) - ? (VehicleTypes.SMALL_TRL as VehicleTypes) - : (technicalRecord.techRecord_vehicleType as VehicleTypes); - } - - getAxleFittingWeightValueFromLoadIndex( - loadIndexValue: string, - fitmentCodeType: FitmentCodeEnum | null | undefined, - loadIndex: ReferenceDataTyreLoadIndex[] | null, - ): number | undefined { - let factor = 4; - if (fitmentCodeType === 'single') { - factor = 2; - } - const axleLoadIndex = loadIndex?.find((resource) => resource.resourceKey === loadIndexValue); - return axleLoadIndex?.loadIndex ? +axleLoadIndex.loadIndex * factor : undefined; - } - - isUnique(valueToCheck: string, searchType: SEARCH_TYPES): Observable { - return this.techRecordHttpService.search$(searchType, valueToCheck).pipe( - map((searchResults) => { - if (searchResults.every((result) => result.techRecord_statusCode === StatusCodes.ARCHIVED)) { - return true; - } - - if (searchType === SEARCH_TYPES.VRM) { - return !searchResults.some((result) => result.primaryVrm === valueToCheck); - } - - return false; - }), - catchError((error: HttpErrorResponse) => { - return (error.status === 404 && of(true)) || throwError(() => error); - }), - ); - } - get techRecordHistory$(): Observable { - return this.store.pipe(select(selectTechRecordHistory)); - } - - get techRecord$(): Observable { - return combineLatest([ - this.store.pipe(select(selectTechRecord)), - this.store.pipe(select(techRecord)), - this.routerService.getRouteDataProperty$('isEditing'), - ]).pipe( - tap(([technicalRecord, nonEditingTechRecord, isEditing]) => { - if (isEditing && !technicalRecord && nonEditingTechRecord) { - this.updateEditingTechRecord(nonEditingTechRecord as TechRecordType<'put'>); - } - }), - map(([technicalRecord, nonEditingTechRecord, isEditing]) => (isEditing && !technicalRecord ? nonEditingTechRecord : technicalRecord)), - ); - } - - updateEditingTechRecord(record: TechRecordType<'put'>): void { - if ( - record.techRecord_vehicleType === 'psv' - || record.techRecord_vehicleType === 'hgv' - || (record.techRecord_vehicleType === 'trl' && record.techRecord_euVehicleCategory !== 'o1' && record.techRecord_euVehicleCategory !== 'o2') - ) { - record.techRecord_noOfAxles = record.techRecord_axles && record.techRecord_axles.length > 0 ? record.techRecord_axles?.length : null; - } - this.store.dispatch(updateEditingTechRecord({ vehicleTechRecord: record })); - } - - /** - * A function to filter the correct tech record, this has a hierarchy which is CURRENT -> PROVISIONAL -> ARCHIVED. - * @param record This is a VehicleTechRecordModel passed in from the parent component - * @returns returns the tech record of correct hierarchy precedence or if none exists returns undefined - */ - static filterTechRecordByStatusCode(record: VehicleTechRecordModel): TechRecordModel | undefined { - return ( - record.techRecord.find((foundRecord) => foundRecord.statusCode === StatusCodes.CURRENT) - ?? record.techRecord.find((foundRecord) => foundRecord.statusCode === StatusCodes.PROVISIONAL) - ?? record.techRecord.find((foundRecord) => foundRecord.statusCode === StatusCodes.ARCHIVED) - ); - } - - generateEditingVehicleTechnicalRecordFromVehicleType(vehicleType: VehicleTypes): void { - this.store.dispatch(createVehicle({ techRecord_vehicleType: vehicleType })); - } - - clearReasonForCreation(): void { - this.techRecord$ - .pipe( - map((data) => cloneDeep(data)), - take(1), - ) - .subscribe((data) => { - if (data) { - data.techRecord_reasonForCreation = ''; - this.updateEditingTechRecord(data as TechRecordType<'put'>); - } - }); - } - - validateVinForUpdate(originalVin?: string): AsyncValidatorFn { - return (control: AbstractControl): Observable => { - return of(control.value).pipe( - filter((value: string) => !!value), - debounceTime(1000), - take(1), - switchMap((value) => { - return this.isUnique(value, SEARCH_TYPES.VIN).pipe( - map((result) => { - if (control.value === originalVin) { - return { validateVin: { message: 'You must provide a new VIN' } }; - } - return result ? null : { validateVin: { message: 'This VIN already exists, if you continue it will be associated with two vehicles' } }; - }), - catchError(() => of(null)), - ); - }), - ); - }; - } - - validateVrmDoesNotExist(previousVrm: string): AsyncValidatorFn { - return (control: AbstractControl): Observable => { - return of(control).pipe( - filter((errorControl: AbstractControl) => !!errorControl.value), - take(1), - switchMap((vrmControl) => { - return this.checkVrmNotActive(vrmControl, previousVrm); - }), - ); - }; - } - - validateVrmForCherishedTransfer(): AsyncValidatorFn { - return (control: AbstractControl): Observable => { - return of(control).pipe( - filter((errorControl: AbstractControl) => !!errorControl.value), - take(1), - switchMap((vrmControl) => { - const thirdMark = vrmControl.root.get('thirdMark')?.value; - const previousVrm = vrmControl.root.get('previousVrm')?.value; - if (thirdMark) { - const vrmNotNew = previousVrm === vrmControl.value; - if (vrmNotNew) return of({ validateVrm: { message: 'You must provide a new VRM' } }); - return this.techRecordHttpService.search$(SEARCH_TYPES.VRM, vrmControl.value).pipe( - map((results) => { - if (results.some((result) => result.techRecord_statusCode === StatusCodes.CURRENT)) { - return null; - } - return { validateVrm: { message: 'This VRM does not exist on a current record' } }; - }), - catchError((err: HttpErrorResponse) => { - return ( - (err.status === 404 && of({ validateVrm: { message: 'This VRM does not exist on a current record' } })) || throwError(() => err) - ); - }), - ); - } - return this.checkVrmNotActive(control, previousVrm); - }), - ); - }; - } - - clearEditingTechRecord() { - this.store.dispatch(updateEditingTechRecordCancel()); - } - - get searchResults$(): Observable { - return this.store.pipe(select(selectTechRecordSearchResults)); - } - - get searchResultsWithUniqueSystemNumbers$(): Observable { - return this.store.pipe(select(selectTechRecordSearchResultsBySystemNumber)); - } - get techRecordStatus$(): Observable { - return this.techRecord$.pipe(map((technicalRecord) => technicalRecord?.techRecord_statusCode as StatusCodes | undefined)); - } - - get sectionStates$(): Observable<(string | number)[] | undefined> { - return this.store.pipe(select(selectSectionState)); - } - - getMakeAndModel(technicalRecord: V3TechRecordModel): string { - if ( - technicalRecord.techRecord_vehicleType === 'car' - || technicalRecord.techRecord_vehicleType === 'motorcycle' - || technicalRecord.techRecord_vehicleType === 'lgv' - ) { - return ''; - } - - const make = (technicalRecord?.techRecord_vehicleType === 'psv' - ? technicalRecord.techRecord_chassisMake - : technicalRecord.techRecord_make) ?? ''; - - const model = (technicalRecord.techRecord_vehicleType === 'psv' - ? technicalRecord.techRecord_chassisModel - : technicalRecord.techRecord_model) ?? ''; - - if (!make || !model) { - return make || model; - } - - return `${make} - ${model}`; - } - - clearSectionTemplateStates() { - this.store.dispatch(clearAllSectionStates()); - } - - checkVrmNotActive(control: AbstractControl, previousVrm: string) { - return this.techRecordHttpService.search$(SEARCH_TYPES.VRM, control.value).pipe( - map((results) => { - const currentRecord = results.filter((result) => result.techRecord_statusCode === StatusCodes.CURRENT); - const provisionalRecord = results.filter((result) => result.techRecord_statusCode === StatusCodes.PROVISIONAL); - - if (control.value === previousVrm) { - return { validateVrm: { message: 'You must provide a new VRM' } }; - } - if (currentRecord.length > 0) { - const value = control.value as string; - return { - validateVrm: { - message: `A current technical record already exists for + constructor( + private store: Store, + private techRecordHttpService: TechnicalRecordHttpService, + private routerService: RouterService + ) {} + + getVehicleTypeWithSmallTrl(technicalRecord: V3TechRecordModel): VehicleTypes { + return technicalRecord.techRecord_vehicleType === VehicleTypes.TRL && + (technicalRecord.techRecord_euVehicleCategory === EUVehicleCategory.O1 || + technicalRecord.techRecord_euVehicleCategory === EUVehicleCategory.O2) + ? (VehicleTypes.SMALL_TRL as VehicleTypes) + : (technicalRecord.techRecord_vehicleType as VehicleTypes); + } + + getAxleFittingWeightValueFromLoadIndex( + loadIndexValue: string, + fitmentCodeType: FitmentCodeEnum | null | undefined, + loadIndex: ReferenceDataTyreLoadIndex[] | null + ): number | undefined { + let factor = 4; + if (fitmentCodeType === 'single') { + factor = 2; + } + const axleLoadIndex = loadIndex?.find((resource) => resource.resourceKey === loadIndexValue); + return axleLoadIndex?.loadIndex ? +axleLoadIndex.loadIndex * factor : undefined; + } + + isUnique(valueToCheck: string, searchType: SEARCH_TYPES): Observable { + return this.techRecordHttpService.search$(searchType, valueToCheck).pipe( + map((searchResults) => { + if (searchResults.every((result) => result.techRecord_statusCode === StatusCodes.ARCHIVED)) { + return true; + } + + if (searchType === SEARCH_TYPES.VRM) { + return !searchResults.some((result) => result.primaryVrm === valueToCheck); + } + + return false; + }), + catchError((error: HttpErrorResponse) => { + return (error.status === 404 && of(true)) || throwError(() => error); + }) + ); + } + get techRecordHistory$(): Observable { + return this.store.pipe(select(selectTechRecordHistory)); + } + + get techRecord$(): Observable { + return combineLatest([ + this.store.pipe(select(selectTechRecord)), + this.store.pipe(select(techRecord)), + this.routerService.getRouteDataProperty$('isEditing'), + ]).pipe( + tap(([technicalRecord, nonEditingTechRecord, isEditing]) => { + if (isEditing && !technicalRecord && nonEditingTechRecord) { + this.updateEditingTechRecord(nonEditingTechRecord as TechRecordType<'put'>); + } + }), + map(([technicalRecord, nonEditingTechRecord, isEditing]) => + isEditing && !technicalRecord ? nonEditingTechRecord : technicalRecord + ) + ); + } + + updateEditingTechRecord(record: TechRecordType<'put'>): void { + if ( + record.techRecord_vehicleType === 'psv' || + record.techRecord_vehicleType === 'hgv' || + (record.techRecord_vehicleType === 'trl' && + record.techRecord_euVehicleCategory !== 'o1' && + record.techRecord_euVehicleCategory !== 'o2') + ) { + record.techRecord_noOfAxles = + record.techRecord_axles && record.techRecord_axles.length > 0 ? record.techRecord_axles?.length : null; + } + this.store.dispatch(updateEditingTechRecord({ vehicleTechRecord: record })); + } + + /** + * A function to filter the correct tech record, this has a hierarchy which is CURRENT -> PROVISIONAL -> ARCHIVED. + * @param record This is a VehicleTechRecordModel passed in from the parent component + * @returns returns the tech record of correct hierarchy precedence or if none exists returns undefined + */ + static filterTechRecordByStatusCode(record: VehicleTechRecordModel): TechRecordModel | undefined { + return ( + record.techRecord.find((foundRecord) => foundRecord.statusCode === StatusCodes.CURRENT) ?? + record.techRecord.find((foundRecord) => foundRecord.statusCode === StatusCodes.PROVISIONAL) ?? + record.techRecord.find((foundRecord) => foundRecord.statusCode === StatusCodes.ARCHIVED) + ); + } + + generateEditingVehicleTechnicalRecordFromVehicleType(vehicleType: VehicleTypes): void { + this.store.dispatch(createVehicle({ techRecord_vehicleType: vehicleType })); + } + + clearReasonForCreation(): void { + this.techRecord$ + .pipe( + map((data) => cloneDeep(data)), + take(1) + ) + .subscribe((data) => { + if (data) { + data.techRecord_reasonForCreation = ''; + this.updateEditingTechRecord(data as TechRecordType<'put'>); + } + }); + } + + validateVinForUpdate(originalVin?: string): AsyncValidatorFn { + return (control: AbstractControl): Observable => { + return of(control.value).pipe( + filter((value: string) => !!value), + debounceTime(1000), + take(1), + switchMap((value) => { + return this.isUnique(value, SEARCH_TYPES.VIN).pipe( + map((result) => { + if (control.value === originalVin) { + return { validateVin: { message: 'You must provide a new VIN' } }; + } + return result + ? null + : { + validateVin: { + message: 'This VIN already exists, if you continue it will be associated with two vehicles', + }, + }; + }), + catchError(() => of(null)) + ); + }) + ); + }; + } + + validateVrmDoesNotExist(previousVrm: string): AsyncValidatorFn { + return (control: AbstractControl): Observable => { + return of(control).pipe( + filter((errorControl: AbstractControl) => !!errorControl.value), + take(1), + switchMap((vrmControl) => { + return this.checkVrmNotActive(vrmControl, previousVrm); + }) + ); + }; + } + + validateVrmForCherishedTransfer(): AsyncValidatorFn { + return (control: AbstractControl): Observable => { + return of(control).pipe( + filter((errorControl: AbstractControl) => !!errorControl.value), + take(1), + switchMap((vrmControl) => { + const thirdMark = vrmControl.root.get('thirdMark')?.value; + const previousVrm = vrmControl.root.get('previousVrm')?.value; + if (thirdMark) { + const vrmNotNew = previousVrm === vrmControl.value; + if (vrmNotNew) return of({ validateVrm: { message: 'You must provide a new VRM' } }); + return this.techRecordHttpService.search$(SEARCH_TYPES.VRM, vrmControl.value).pipe( + map((results) => { + if (results.some((result) => result.techRecord_statusCode === StatusCodes.CURRENT)) { + return null; + } + return { validateVrm: { message: 'This VRM does not exist on a current record' } }; + }), + catchError((err: HttpErrorResponse) => { + return ( + (err.status === 404 && + of({ validateVrm: { message: 'This VRM does not exist on a current record' } })) || + throwError(() => err) + ); + }) + ); + } + return this.checkVrmNotActive(control, previousVrm); + }) + ); + }; + } + + clearEditingTechRecord() { + this.store.dispatch(updateEditingTechRecordCancel()); + } + + get searchResults$(): Observable { + return this.store.pipe(select(selectTechRecordSearchResults)); + } + + get searchResultsWithUniqueSystemNumbers$(): Observable { + return this.store.pipe(select(selectTechRecordSearchResultsBySystemNumber)); + } + get techRecordStatus$(): Observable { + return this.techRecord$.pipe( + map((technicalRecord) => technicalRecord?.techRecord_statusCode as StatusCodes | undefined) + ); + } + + get sectionStates$(): Observable<(string | number)[] | undefined> { + return this.store.pipe(select(selectSectionState)); + } + + getMakeAndModel(technicalRecord: V3TechRecordModel): string { + if ( + technicalRecord.techRecord_vehicleType === 'car' || + technicalRecord.techRecord_vehicleType === 'motorcycle' || + technicalRecord.techRecord_vehicleType === 'lgv' + ) { + return ''; + } + + const make = + (technicalRecord?.techRecord_vehicleType === 'psv' + ? technicalRecord.techRecord_chassisMake + : technicalRecord.techRecord_make) ?? ''; + + const model = + (technicalRecord.techRecord_vehicleType === 'psv' + ? technicalRecord.techRecord_chassisModel + : technicalRecord.techRecord_model) ?? ''; + + if (!make || !model) { + return make || model; + } + + return `${make} - ${model}`; + } + + clearSectionTemplateStates() { + this.store.dispatch(clearAllSectionStates()); + } + + checkVrmNotActive(control: AbstractControl, previousVrm: string) { + return this.techRecordHttpService.search$(SEARCH_TYPES.VRM, control.value).pipe( + map((results) => { + const currentRecord = results.filter((result) => result.techRecord_statusCode === StatusCodes.CURRENT); + const provisionalRecord = results.filter((result) => result.techRecord_statusCode === StatusCodes.PROVISIONAL); + + if (control.value === previousVrm) { + return { validateVrm: { message: 'You must provide a new VRM' } }; + } + if (currentRecord.length > 0) { + const value = control.value as string; + return { + validateVrm: { + message: `A current technical record already exists for ${value} with the VIN number ${currentRecord[0].vin}. Please fill in the third mark field`, - }, - }; - } - if (provisionalRecord.length > 0) { - return { validateVrm: { message: `This VRM already exists on a provisional record with the VIN: ${provisionalRecord[0].vin}` } }; - } - return null; - }), - catchError((err: HttpErrorResponse) => { - return (err.status === 404 && of(null)) || throwError(() => err); - }), - ); - } - - hasPsvGrossAxleChanged(changes: Partial): boolean { - return [ - changes.techRecord_grossKerbWeight, - changes.techRecord_grossDesignWeight, - changes.techRecord_grossLadenWeight, - changes.techRecord_grossGbWeight, - ].some(Boolean); - } - - hasHgvGrossAxleChanged(changes: Partial): boolean { - return [changes.techRecord_grossEecWeight, changes.techRecord_grossDesignWeight, changes.techRecord_grossGbWeight].some(Boolean); - } - - hasTrlGrossAxleChanged(changes: Partial): boolean { - return [changes.techRecord_grossEecWeight, changes.techRecord_grossDesignWeight, changes.techRecord_grossGbWeight].some(Boolean); - } - - hasHgvTrainAxleChanged(changes: Partial): boolean { - return [changes.techRecord_trainDesignWeight, changes.techRecord_trainGbWeight, changes.techRecord_trainEecWeight].some(Boolean); - } - - hasPsvTrainAxleChanged(changes: Partial): boolean { - return [changes.techRecord_trainDesignWeight, changes.techRecord_maxTrainGbWeight].some(Boolean); - } - - hasMaxTrainAxleChanged(changes: Partial): boolean { - return [ - changes.techRecord_maxTrainDesignWeight, - changes.techRecord_maxTrainEecWeight, - changes.techRecord_maxTrainGbWeight, - ].some(Boolean); - } - - haveAxlesChanged(vehicleType: VehicleTypes, changes: Partial>) { - if (vehicleType === 'psv' - && (this.hasPsvGrossAxleChanged(changes as Partial) - || this.hasPsvTrainAxleChanged(changes as Partial))) return true; - - if (vehicleType === 'hgv' - && (this.hasHgvTrainAxleChanged(changes as Partial) - || this.hasMaxTrainAxleChanged(changes as Partial) - || this.hasHgvGrossAxleChanged(changes as Partial))) return true; - - if (vehicleType === 'trl' && this.hasTrlGrossAxleChanged(changes as Partial)) return true; - - return false; - } + }, + }; + } + if (provisionalRecord.length > 0) { + return { + validateVrm: { + message: `This VRM already exists on a provisional record with the VIN: ${provisionalRecord[0].vin}`, + }, + }; + } + return null; + }), + catchError((err: HttpErrorResponse) => { + return (err.status === 404 && of(null)) || throwError(() => err); + }) + ); + } + + hasPsvGrossAxleChanged(changes: Partial): boolean { + return [ + changes.techRecord_grossKerbWeight, + changes.techRecord_grossDesignWeight, + changes.techRecord_grossLadenWeight, + changes.techRecord_grossGbWeight, + ].some(Boolean); + } + + hasHgvGrossAxleChanged(changes: Partial): boolean { + return [ + changes.techRecord_grossEecWeight, + changes.techRecord_grossDesignWeight, + changes.techRecord_grossGbWeight, + ].some(Boolean); + } + + hasTrlGrossAxleChanged(changes: Partial): boolean { + return [ + changes.techRecord_grossEecWeight, + changes.techRecord_grossDesignWeight, + changes.techRecord_grossGbWeight, + ].some(Boolean); + } + + hasHgvTrainAxleChanged(changes: Partial): boolean { + return [ + changes.techRecord_trainDesignWeight, + changes.techRecord_trainGbWeight, + changes.techRecord_trainEecWeight, + ].some(Boolean); + } + + hasPsvTrainAxleChanged(changes: Partial): boolean { + return [changes.techRecord_trainDesignWeight, changes.techRecord_maxTrainGbWeight].some(Boolean); + } + + hasMaxTrainAxleChanged(changes: Partial): boolean { + return [ + changes.techRecord_maxTrainDesignWeight, + changes.techRecord_maxTrainEecWeight, + changes.techRecord_maxTrainGbWeight, + ].some(Boolean); + } + + haveAxlesChanged(vehicleType: VehicleTypes, changes: Partial>) { + if ( + vehicleType === 'psv' && + (this.hasPsvGrossAxleChanged(changes as Partial) || + this.hasPsvTrainAxleChanged(changes as Partial)) + ) + return true; + + if ( + vehicleType === 'hgv' && + (this.hasHgvTrainAxleChanged(changes as Partial) || + this.hasMaxTrainAxleChanged(changes as Partial) || + this.hasHgvGrossAxleChanged(changes as Partial)) + ) + return true; + + if (vehicleType === 'trl' && this.hasTrlGrossAxleChanged(changes as Partial)) return true; + + return false; + } } diff --git a/src/app/services/test-records/test-records.service.spec.ts b/src/app/services/test-records/test-records.service.spec.ts index c17d7adb29..32be4c6a84 100644 --- a/src/app/services/test-records/test-records.service.spec.ts +++ b/src/app/services/test-records/test-records.service.spec.ts @@ -1,182 +1,199 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { TestBed } from '@angular/core/testing'; -import { DefaultService as CreateTestResultsService, GetTestResultsService, UpdateTestResultsService } from '@api/test-results'; +import { + DefaultService as CreateTestResultsService, + GetTestResultsService, + UpdateTestResultsService, +} from '@api/test-results'; import { TestResultModel } from '@models/test-results/test-result.model'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { State, initialAppState } from '@store/.'; import { - createTestResult, fetchTestResults, fetchTestResultsBySystemNumber, toEditOrNotToEdit, updateTestResult, + createTestResult, + fetchTestResults, + fetchTestResultsBySystemNumber, + toEditOrNotToEdit, + updateTestResult, } from '@store/test-records'; import { mockTestResult } from '../../../mocks/mock-test-result'; import { TestRecordsService } from './test-records.service'; describe('TestRecordsService', () => { - let service: TestRecordsService; - let httpTestingController: HttpTestingController; - let store: MockStore; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - TestRecordsService, - provideMockStore({ initialState: initialAppState }), - GetTestResultsService, - UpdateTestResultsService, - CreateTestResultsService, - ], - }); - - httpTestingController = TestBed.inject(HttpTestingController); - service = TestBed.inject(TestRecordsService); - store = TestBed.inject(MockStore); - }); - - afterEach(() => { - // After every test, assert that there are no more pending requests. - httpTestingController.verify(); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('API', () => { - describe('fetchTestResultbyServiceId', () => { - it('should throw error when systemNumber is empty', (done) => { - service.fetchTestResultbySystemNumber('').subscribe({ - error: (e) => { - expect(e.message).toBe('systemNumber is required'); - done(); - }, - }); - }); - - it('should add query params to url', () => { - const now = new Date('2022-01-01T00:00:00.000Z'); - service - .fetchTestResultbySystemNumber('SystemNumber', { - status: 'submited', - fromDateTime: now, - toDateTime: now, - testResultId: 'TEST_RESULT_ID', - version: '1', - }) - .subscribe({ next: () => { } }); - - // Check for correct requests: should have made one request to POST search from expected URL - const req = httpTestingController.expectOne( - // eslint-disable-next-line max-len - 'https://url/api/v1/test-results/SystemNumber?status=submited&fromDateTime=2022-01-01T00:00:00.000Z&toDateTime=2022-01-01T00:00:00.000Z&testResultId=TEST_RESULT_ID&version=1', - ); - expect(req.request.method).toBe('GET'); - - // Provide each request with a mock response - req.flush([]); - }); - - it('should get a single test result', () => { - const systemNumber = 'SYS0001'; - const mockData = mockTestResult(); - service.fetchTestResultbySystemNumber(systemNumber).subscribe((response) => { - expect(response).toEqual(mockData); - }); - - // Check for correct requests: should have made one request to POST search from expected URL - const req = httpTestingController.expectOne('https://url/api/v1/test-results/SYS0001'); - expect(req.request.method).toBe('GET'); - - // Provide each request with a mock response - req.flush(mockData); - }); - }); - }); - - describe('TestRecordsService.prototype.loadTestResults.name', () => { - it('should dispatch fetchTestResults action', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.loadTestResults(); - expect(dispatchSpy).toHaveBeenCalledWith(fetchTestResults()); - }); - }); - - describe('TestRecordsService.prototype.loadTestResultBySystemNumber.name', () => { - it('should dispatch fetchTestResultsBySystemNumber action', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - const systemNumber = 'SYS0001'; - service.loadTestResultBySystemNumber(systemNumber); - expect(dispatchSpy).toHaveBeenCalledWith(fetchTestResultsBySystemNumber({ systemNumber })); - }); - }); - - describe('TestRecordsService.prototype.updateTestResult.name', () => { - it('should dispatch updateTestResultState action', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.updateTestResult({} as TestResultModel); - expect(dispatchSpy).toHaveBeenCalledWith(updateTestResult({ value: {} as TestResultModel })); - }); - }); - - describe('TestRecordsService.prototype.createTestResult.name', () => { - it('should dispatch createTestResult action', () => { - const dispatchSpy = jest.spyOn(store, 'dispatch'); - service.createTestResult({} as TestResultModel); - expect(dispatchSpy).toHaveBeenCalledWith(createTestResult({ value: {} as TestResultModel })); - }); - }); - - describe('getTestTypeGroup', () => { - it('should get the correct testTypeGroup', () => { - expect(TestRecordsService.getTestTypeGroup('1')).toBe('testTypesGroup1'); - }); - - it('should return undefined if the testTypeGroup is not supported', () => { - expect(TestRecordsService.getTestTypeGroup('foo')).toBeUndefined(); - }); - }); - - describe('isTestTypeGroupEditable$', () => { - beforeEach(() => { - store.resetSelectors(); - }); - - it('should return true if the test type id is in a valid test type group and the test type group is in the master template', (done) => { - store.overrideSelector(toEditOrNotToEdit, { vehicleType: 'psv', testTypes: [{ testTypeId: '1' }] } as TestResultModel); - service.isTestTypeGroupEditable$.subscribe((isValid) => { - expect(isValid).toBe(true); - done(); - }); - }); - - it('should return false if the test type id is not in a test type gorup', (done) => { - store.overrideSelector(toEditOrNotToEdit, { vehicleType: 'psv', testTypes: [{ testTypeId: 'foo' }] } as TestResultModel); - service.isTestTypeGroupEditable$.subscribe((isValid) => { - expect(isValid).toBe(false); - done(); - }); - }); - - it('should return false if the test type group is not in the master template', (done) => { - store.overrideSelector(toEditOrNotToEdit, { vehicleType: 'psv', testTypes: [{ testTypeId: 'foo' }] } as TestResultModel); - service.isTestTypeGroupEditable$.subscribe((isValid) => { - expect(isValid).toBe(false); - done(); - }); - }); - - it('should return false if the testResult is undefined', (done) => { - store.overrideSelector(toEditOrNotToEdit, undefined); - service.isTestTypeGroupEditable$.subscribe((isValid) => { - expect(isValid).toBe(false); - done(); - }); - }); - }); - - describe('postTestResult', () => { - it('should call the service', () => { - service['createTestResultsService'].testResultsPost = jest.fn().mockReturnValue('foo'); - expect(service.postTestResult({} as TestResultModel)).toBe('foo'); - }); - }); + let service: TestRecordsService; + let httpTestingController: HttpTestingController; + let store: MockStore; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + TestRecordsService, + provideMockStore({ initialState: initialAppState }), + GetTestResultsService, + UpdateTestResultsService, + CreateTestResultsService, + ], + }); + + httpTestingController = TestBed.inject(HttpTestingController); + service = TestBed.inject(TestRecordsService); + store = TestBed.inject(MockStore); + }); + + afterEach(() => { + // After every test, assert that there are no more pending requests. + httpTestingController.verify(); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + describe('API', () => { + describe('fetchTestResultbyServiceId', () => { + it('should throw error when systemNumber is empty', (done) => { + service.fetchTestResultbySystemNumber('').subscribe({ + error: (e) => { + expect(e.message).toBe('systemNumber is required'); + done(); + }, + }); + }); + + it('should add query params to url', () => { + const now = new Date('2022-01-01T00:00:00.000Z'); + service + .fetchTestResultbySystemNumber('SystemNumber', { + status: 'submited', + fromDateTime: now, + toDateTime: now, + testResultId: 'TEST_RESULT_ID', + version: '1', + }) + .subscribe({ next: () => {} }); + + // Check for correct requests: should have made one request to POST search from expected URL + const req = httpTestingController.expectOne( + // eslint-disable-next-line max-len + 'https://url/api/v1/test-results/SystemNumber?status=submited&fromDateTime=2022-01-01T00:00:00.000Z&toDateTime=2022-01-01T00:00:00.000Z&testResultId=TEST_RESULT_ID&version=1' + ); + expect(req.request.method).toBe('GET'); + + // Provide each request with a mock response + req.flush([]); + }); + + it('should get a single test result', () => { + const systemNumber = 'SYS0001'; + const mockData = mockTestResult(); + service.fetchTestResultbySystemNumber(systemNumber).subscribe((response) => { + expect(response).toEqual(mockData); + }); + + // Check for correct requests: should have made one request to POST search from expected URL + const req = httpTestingController.expectOne('https://url/api/v1/test-results/SYS0001'); + expect(req.request.method).toBe('GET'); + + // Provide each request with a mock response + req.flush(mockData); + }); + }); + }); + + describe('TestRecordsService.prototype.loadTestResults.name', () => { + it('should dispatch fetchTestResults action', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.loadTestResults(); + expect(dispatchSpy).toHaveBeenCalledWith(fetchTestResults()); + }); + }); + + describe('TestRecordsService.prototype.loadTestResultBySystemNumber.name', () => { + it('should dispatch fetchTestResultsBySystemNumber action', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + const systemNumber = 'SYS0001'; + service.loadTestResultBySystemNumber(systemNumber); + expect(dispatchSpy).toHaveBeenCalledWith(fetchTestResultsBySystemNumber({ systemNumber })); + }); + }); + + describe('TestRecordsService.prototype.updateTestResult.name', () => { + it('should dispatch updateTestResultState action', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.updateTestResult({} as TestResultModel); + expect(dispatchSpy).toHaveBeenCalledWith(updateTestResult({ value: {} as TestResultModel })); + }); + }); + + describe('TestRecordsService.prototype.createTestResult.name', () => { + it('should dispatch createTestResult action', () => { + const dispatchSpy = jest.spyOn(store, 'dispatch'); + service.createTestResult({} as TestResultModel); + expect(dispatchSpy).toHaveBeenCalledWith(createTestResult({ value: {} as TestResultModel })); + }); + }); + + describe('getTestTypeGroup', () => { + it('should get the correct testTypeGroup', () => { + expect(TestRecordsService.getTestTypeGroup('1')).toBe('testTypesGroup1'); + }); + + it('should return undefined if the testTypeGroup is not supported', () => { + expect(TestRecordsService.getTestTypeGroup('foo')).toBeUndefined(); + }); + }); + + describe('isTestTypeGroupEditable$', () => { + beforeEach(() => { + store.resetSelectors(); + }); + + it('should return true if the test type id is in a valid test type group and the test type group is in the master template', (done) => { + store.overrideSelector(toEditOrNotToEdit, { + vehicleType: 'psv', + testTypes: [{ testTypeId: '1' }], + } as TestResultModel); + service.isTestTypeGroupEditable$.subscribe((isValid) => { + expect(isValid).toBe(true); + done(); + }); + }); + + it('should return false if the test type id is not in a test type gorup', (done) => { + store.overrideSelector(toEditOrNotToEdit, { + vehicleType: 'psv', + testTypes: [{ testTypeId: 'foo' }], + } as TestResultModel); + service.isTestTypeGroupEditable$.subscribe((isValid) => { + expect(isValid).toBe(false); + done(); + }); + }); + + it('should return false if the test type group is not in the master template', (done) => { + store.overrideSelector(toEditOrNotToEdit, { + vehicleType: 'psv', + testTypes: [{ testTypeId: 'foo' }], + } as TestResultModel); + service.isTestTypeGroupEditable$.subscribe((isValid) => { + expect(isValid).toBe(false); + done(); + }); + }); + + it('should return false if the testResult is undefined', (done) => { + store.overrideSelector(toEditOrNotToEdit, undefined); + service.isTestTypeGroupEditable$.subscribe((isValid) => { + expect(isValid).toBe(false); + done(); + }); + }); + }); + + describe('postTestResult', () => { + it('should call the service', () => { + service['createTestResultsService'].testResultsPost = jest.fn().mockReturnValue('foo'); + expect(service.postTestResult({} as TestResultModel)).toBe('foo'); + }); + }); }); diff --git a/src/app/services/test-records/test-records.service.ts b/src/app/services/test-records/test-records.service.ts index db5e2afe17..db0d0ca0ec 100644 --- a/src/app/services/test-records/test-records.service.ts +++ b/src/app/services/test-records/test-records.service.ts @@ -1,6 +1,9 @@ import { Injectable } from '@angular/core'; import { - CompleteTestResults, DefaultService as CreateTestResultsService, GetTestResultsService, UpdateTestResultsService, + CompleteTestResults, + DefaultService as CreateTestResultsService, + GetTestResultsService, + UpdateTestResultsService, } from '@api/test-results'; import { TEST_TYPES, TEST_TYPES_GROUP1_SPEC_TEST, TEST_TYPES_GROUP5_SPEC_TEST } from '@forms/models/testTypeId.enum'; import { FormNode } from '@forms/services/dynamic-form.types'; @@ -11,231 +14,235 @@ import { TestResultModel } from '@models/test-results/test-result.model'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { Store, select } from '@ngrx/store'; import { - TestResultsState, - cancelEditingTestResult, - cleanTestResult, - contingencyTestTypeSelected, - createTestResult, - editingTestResult, - fetchTestResults, - fetchTestResultsBySystemNumber, - isTestTypeKeySame, - sectionTemplates, - selectAllTestResults, - selectAmendedDefectData, - selectDefectData, - selectedAmendedTestResultState, - selectedTestResultState, - testResultInEdit, - testTypeIdChanged, - toEditOrNotToEdit, - updateEditingTestResult, - updateTestResult, - updateTestResultFailed, + TestResultsState, + cancelEditingTestResult, + cleanTestResult, + contingencyTestTypeSelected, + createTestResult, + editingTestResult, + fetchTestResults, + fetchTestResultsBySystemNumber, + isTestTypeKeySame, + sectionTemplates, + selectAllTestResults, + selectAmendedDefectData, + selectDefectData, + selectedAmendedTestResultState, + selectedTestResultState, + testResultInEdit, + testTypeIdChanged, + toEditOrNotToEdit, + updateEditingTestResult, + updateTestResult, + updateTestResultFailed, } from '@store/test-records'; import cloneDeep from 'lodash.clonedeep'; import { Observable, take, throwError } from 'rxjs'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class TestRecordsService { - constructor( - private store: Store, - private updateTestResultsService: UpdateTestResultsService, - private getTestResultService: GetTestResultsService, - private createTestResultsService: CreateTestResultsService, - ) {} - - fetchTestResultbySystemNumber( - systemNumber: string, - queryparams: { - status?: string; - fromDateTime?: Date; - toDateTime?: Date; - testResultId?: string; - version?: string; - } = {}, - ): Observable> { - if (!systemNumber) { - return throwError(() => new Error('systemNumber is required')); - } - - const { - status, fromDateTime, toDateTime, testResultId, version, - } = queryparams; - return this.getTestResultService.testResultsSystemNumberGet(systemNumber, status, fromDateTime, toDateTime, testResultId, version) as Observable< - Array - >; - } - - loadTestResults(): void { - this.store.dispatch(fetchTestResults()); - } - - loadTestResultBySystemNumber(systemNumber: string): void { - this.store.dispatch(fetchTestResultsBySystemNumber({ systemNumber })); - } - - get testResult$() { - return this.store.pipe(select(selectedTestResultState)); - } - - get editingTestResult$() { - return this.store.pipe(select(testResultInEdit)); - } - - get testRecords$() { - return this.store.pipe(select(selectAllTestResults)); - } - - get defectData$() { - return this.store.pipe(select(selectDefectData)); - } - - get amendedTestResult$() { - return this.store.pipe(select(selectedAmendedTestResultState)); - } - - get amendedDefectData$() { - return this.store.pipe(select(selectAmendedDefectData)); - } - - get sectionTemplates$() { - return this.store.pipe(select(sectionTemplates)); - } - - saveTestResult( - systemNumber: string, - user: { name: string; id?: string; userEmail?: string }, - body: TestResultModel, - observe?: 'body', - reportProgress?: boolean, - ): Observable { - const { name, id, userEmail } = user; - const tr = cloneDeep(body); - delete tr.testHistory; - return this.updateTestResultsService.testResultsSystemNumberPut( - { msUserDetails: { msOid: id, msUser: name, msEmailAddress: userEmail }, testResult: tr } as CompleteTestResults, - systemNumber, - observe, - reportProgress, - ) as Observable; - } - - updateTestResult(value: TestResultModel): void { - this.store.dispatch(updateTestResult({ value })); - } - - postTestResult(body: TestResultModel) { - return this.createTestResultsService.testResultsPost(body as CompleteTestResults, 'response', false); - } - - createTestResult(value: TestResultModel): void { - this.store.dispatch(createTestResult({ value })); - } - - cleanTestResult() { - return this.store.dispatch(cleanTestResult()); - } - - prepareTestResultForAmendment(testResults: TestResultModel[], testResult: TestResultModel): TestResultModel { - const lastIvaOrMsvaTest = testResults.find((test) => { - const testType = test?.testTypes[0]; - const testTypeId = testType?.testTypeId ?? ''; - const isIVAorMSVATest = TEST_TYPES_GROUP1_SPEC_TEST.includes(testTypeId) || TEST_TYPES_GROUP5_SPEC_TEST.includes(testTypeId); - - return isIVAorMSVATest; - }); - - if (!lastIvaOrMsvaTest) { - return testResult; - } - - // If certificateNumber is falsy, then use the last IVA or MSVA test certificate number - testResult.testTypes[0].certificateNumber ??= lastIvaOrMsvaTest.testTypes[0].certificateNumber; - - return testResult; - } - - static getTestTypeGroup(testTypeId: string): string | undefined { - // eslint-disable-next-line no-restricted-syntax - for (const groupName in TEST_TYPES) { - if (TEST_TYPES[groupName as keyof typeof TEST_TYPES].includes(testTypeId)) { - return groupName; - } - } - return undefined; - } - - editingTestResult(testResult: TestResultModel): void { - this.store.dispatch(editingTestResult({ testTypeId: testResult.testTypes[0].testTypeId })); - } - - cancelEditingTestResult(): void { - this.store.dispatch(cancelEditingTestResult()); - } - - updateEditingTestResult(testResult: TestResultModel): void { - this.store.dispatch(updateEditingTestResult({ testResult })); - } - - get isSameTestTypeId$(): Observable { - return this.store.pipe(select(isTestTypeKeySame('testTypeId'))); - } - - testTypeChange(testTypeId: string) { - this.store.dispatch(testTypeIdChanged({ testTypeId })); - } - - get isTestTypeGroupEditable$() { - return this.store.pipe(select(toEditOrNotToEdit), this.canHandleTestType(masterTpl)); - } - - get canCreate$() { - return this.store.pipe(select(toEditOrNotToEdit), this.canHandleTestType(contingencyTestTemplates)); - } - - private canHandleTestType(templateMap: Record>>) { - return function handleTestType(source: Observable): Observable { - const handle = (testResult: TestResultModel | undefined): boolean => { - if (!testResult) { - return false; - } - - const { vehicleType } = testResult; - const testTypeId = testResult.testTypes && testResult.testTypes[0].testTypeId; - const testTypeGroup = TestRecordsService.getTestTypeGroup(testTypeId); - const vehicleTpl = vehicleType && templateMap[`${vehicleType}`]; - - return !!testTypeGroup && !!vehicleTpl && Object.prototype.hasOwnProperty.call(vehicleTpl, testTypeGroup); - }; - - return new Observable((subscriber) => { - source.subscribe({ - next: (val) => { - subscriber.next(handle(val as unknown as TestResultModel)); - }, - error: (e) => subscriber.error(e), - complete: () => subscriber.complete(), - }); - }); - }; - } - - contingencyTestTypeSelected(testType: string) { - this.store.dispatch(contingencyTestTypeSelected({ testType })); - } - - cancelTest(reason: string): void { - this.store.pipe(select(testResultInEdit), take(1)).subscribe((testResult) => { - if (!testResult) { - return this.store.dispatch(updateTestResultFailed({ errors: [{ error: 'No selected test result.' }] })); - } - - const cancelledTest = { ...testResult, testStatus: TestResultStatus.CANCELLED, reasonForCancellation: reason }; - - this.store.dispatch(updateTestResult({ value: cancelledTest })); - }); - } + constructor( + private store: Store, + private updateTestResultsService: UpdateTestResultsService, + private getTestResultService: GetTestResultsService, + private createTestResultsService: CreateTestResultsService + ) {} + + fetchTestResultbySystemNumber( + systemNumber: string, + queryparams: { + status?: string; + fromDateTime?: Date; + toDateTime?: Date; + testResultId?: string; + version?: string; + } = {} + ): Observable> { + if (!systemNumber) { + return throwError(() => new Error('systemNumber is required')); + } + + const { status, fromDateTime, toDateTime, testResultId, version } = queryparams; + return this.getTestResultService.testResultsSystemNumberGet( + systemNumber, + status, + fromDateTime, + toDateTime, + testResultId, + version + ) as Observable>; + } + + loadTestResults(): void { + this.store.dispatch(fetchTestResults()); + } + + loadTestResultBySystemNumber(systemNumber: string): void { + this.store.dispatch(fetchTestResultsBySystemNumber({ systemNumber })); + } + + get testResult$() { + return this.store.pipe(select(selectedTestResultState)); + } + + get editingTestResult$() { + return this.store.pipe(select(testResultInEdit)); + } + + get testRecords$() { + return this.store.pipe(select(selectAllTestResults)); + } + + get defectData$() { + return this.store.pipe(select(selectDefectData)); + } + + get amendedTestResult$() { + return this.store.pipe(select(selectedAmendedTestResultState)); + } + + get amendedDefectData$() { + return this.store.pipe(select(selectAmendedDefectData)); + } + + get sectionTemplates$() { + return this.store.pipe(select(sectionTemplates)); + } + + saveTestResult( + systemNumber: string, + user: { name: string; id?: string; userEmail?: string }, + body: TestResultModel, + observe?: 'body', + reportProgress?: boolean + ): Observable { + const { name, id, userEmail } = user; + const tr = cloneDeep(body); + delete tr.testHistory; + return this.updateTestResultsService.testResultsSystemNumberPut( + { msUserDetails: { msOid: id, msUser: name, msEmailAddress: userEmail }, testResult: tr } as CompleteTestResults, + systemNumber, + observe, + reportProgress + ) as Observable; + } + + updateTestResult(value: TestResultModel): void { + this.store.dispatch(updateTestResult({ value })); + } + + postTestResult(body: TestResultModel) { + return this.createTestResultsService.testResultsPost(body as CompleteTestResults, 'response', false); + } + + createTestResult(value: TestResultModel): void { + this.store.dispatch(createTestResult({ value })); + } + + cleanTestResult() { + return this.store.dispatch(cleanTestResult()); + } + + prepareTestResultForAmendment(testResults: TestResultModel[], testResult: TestResultModel): TestResultModel { + const lastIvaOrMsvaTest = testResults.find((test) => { + const testType = test?.testTypes[0]; + const testTypeId = testType?.testTypeId ?? ''; + const isIVAorMSVATest = + TEST_TYPES_GROUP1_SPEC_TEST.includes(testTypeId) || TEST_TYPES_GROUP5_SPEC_TEST.includes(testTypeId); + + return isIVAorMSVATest; + }); + + if (!lastIvaOrMsvaTest) { + return testResult; + } + + // If certificateNumber is falsy, then use the last IVA or MSVA test certificate number + testResult.testTypes[0].certificateNumber ??= lastIvaOrMsvaTest.testTypes[0].certificateNumber; + + return testResult; + } + + static getTestTypeGroup(testTypeId: string): string | undefined { + // eslint-disable-next-line no-restricted-syntax + for (const groupName in TEST_TYPES) { + if (TEST_TYPES[groupName as keyof typeof TEST_TYPES].includes(testTypeId)) { + return groupName; + } + } + return undefined; + } + + editingTestResult(testResult: TestResultModel): void { + this.store.dispatch(editingTestResult({ testTypeId: testResult.testTypes[0].testTypeId })); + } + + cancelEditingTestResult(): void { + this.store.dispatch(cancelEditingTestResult()); + } + + updateEditingTestResult(testResult: TestResultModel): void { + this.store.dispatch(updateEditingTestResult({ testResult })); + } + + get isSameTestTypeId$(): Observable { + return this.store.pipe(select(isTestTypeKeySame('testTypeId'))); + } + + testTypeChange(testTypeId: string) { + this.store.dispatch(testTypeIdChanged({ testTypeId })); + } + + get isTestTypeGroupEditable$() { + return this.store.pipe(select(toEditOrNotToEdit), this.canHandleTestType(masterTpl)); + } + + get canCreate$() { + return this.store.pipe(select(toEditOrNotToEdit), this.canHandleTestType(contingencyTestTemplates)); + } + + private canHandleTestType(templateMap: Record>>) { + return function handleTestType(source: Observable): Observable { + const handle = (testResult: TestResultModel | undefined): boolean => { + if (!testResult) { + return false; + } + + const { vehicleType } = testResult; + const testTypeId = testResult.testTypes && testResult.testTypes[0].testTypeId; + const testTypeGroup = TestRecordsService.getTestTypeGroup(testTypeId); + const vehicleTpl = vehicleType && templateMap[`${vehicleType}`]; + + return !!testTypeGroup && !!vehicleTpl && Object.prototype.hasOwnProperty.call(vehicleTpl, testTypeGroup); + }; + + return new Observable((subscriber) => { + source.subscribe({ + next: (val) => { + subscriber.next(handle(val as unknown as TestResultModel)); + }, + error: (e) => subscriber.error(e), + complete: () => subscriber.complete(), + }); + }); + }; + } + + contingencyTestTypeSelected(testType: string) { + this.store.dispatch(contingencyTestTypeSelected({ testType })); + } + + cancelTest(reason: string): void { + this.store.pipe(select(testResultInEdit), take(1)).subscribe((testResult) => { + if (!testResult) { + return this.store.dispatch(updateTestResultFailed({ errors: [{ error: 'No selected test result.' }] })); + } + + const cancelledTest = { ...testResult, testStatus: TestResultStatus.CANCELLED, reasonForCancellation: reason }; + + this.store.dispatch(updateTestResult({ value: cancelledTest })); + }); + } } diff --git a/src/app/services/test-stations/test-stations.service.spec.ts b/src/app/services/test-stations/test-stations.service.spec.ts index 72187c6869..9633c01bf4 100644 --- a/src/app/services/test-stations/test-stations.service.spec.ts +++ b/src/app/services/test-stations/test-stations.service.spec.ts @@ -7,93 +7,93 @@ import { initialAppState } from '../../store'; import { TestStationsService } from './test-stations.service'; describe('TestStationsService', () => { - let service: TestStationsService; - let httpTestingController: HttpTestingController; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [TestStationsService, provideMockStore({ initialState: initialAppState })], - }); - - httpTestingController = TestBed.inject(HttpTestingController); - service = TestBed.inject(TestStationsService); - }); - - afterEach(() => { - // After every test, assert that there are no more pending requests. - httpTestingController.verify(); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('fetchTestStations', () => { - it('should get an array of matching results', () => { - const expectedResult = [{ testStationName: 'Some Name' } as TestStation]; - service.fetchTestStations().subscribe((response) => expect(response).toEqual(expectedResult)); - - // Check for correct requests: should have made one request to search from expected URL - const req = httpTestingController.expectOne(`${environment.VTM_API_URI}/test-stations/`); - expect(req.request.method).toBe('GET'); - - // Provide each request with a mock response - req.flush(expectedResult); - }); - - it('should handle errors', (done) => { - service.fetchTestStations().subscribe({ - next: () => {}, - error: (e) => { - expect(e.error).toBe('Deliberate 500 error'); - expect(e.status).toBe(500); - expect(e.statusText).toBe('Server Error'); - done(); - }, - }); - - // Check for correct requests: should have made one request to search from expected URL - const req = httpTestingController.expectOne(`${environment.VTM_API_URI}/test-stations/`); - expect(req.request.method).toBe('GET'); - - // Respond with mock error - req.flush('Deliberate 500 error', { status: 500, statusText: 'Server Error' }); - }); - }); - - describe('fetchTestStation', () => { - it('should get a matching result', () => { - const expectedId = 'some ID'; - const expectedResult = { testStationName: 'Some Name' } as TestStation; - service.fetchTestStation(expectedId).subscribe((response) => expect(response).toEqual(expectedResult)); - - // Check for correct requests: should have made one request to search from expected URL - const req = httpTestingController.expectOne(`${environment.VTM_API_URI}/test-stations/${expectedId}`); - expect(req.request.method).toBe('GET'); - - // Provide each request with a mock response - req.flush(expectedResult); - }); - - it('should handle errors', (done) => { - const expectedId = 'some ID'; - service.fetchTestStation(expectedId).subscribe({ - next: () => {}, - error: (e) => { - expect(e.error).toBe('Deliberate 500 error'); - expect(e.status).toBe(500); - expect(e.statusText).toBe('Server Error'); - done(); - }, - }); - - // Check for correct requests: should have made one request to search from expected URL - const req = httpTestingController.expectOne(`${environment.VTM_API_URI}/test-stations/${expectedId}`); - expect(req.request.method).toBe('GET'); - - // Respond with mock error - req.flush('Deliberate 500 error', { status: 500, statusText: 'Server Error' }); - }); - }); + let service: TestStationsService; + let httpTestingController: HttpTestingController; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [TestStationsService, provideMockStore({ initialState: initialAppState })], + }); + + httpTestingController = TestBed.inject(HttpTestingController); + service = TestBed.inject(TestStationsService); + }); + + afterEach(() => { + // After every test, assert that there are no more pending requests. + httpTestingController.verify(); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + describe('fetchTestStations', () => { + it('should get an array of matching results', () => { + const expectedResult = [{ testStationName: 'Some Name' } as TestStation]; + service.fetchTestStations().subscribe((response) => expect(response).toEqual(expectedResult)); + + // Check for correct requests: should have made one request to search from expected URL + const req = httpTestingController.expectOne(`${environment.VTM_API_URI}/test-stations/`); + expect(req.request.method).toBe('GET'); + + // Provide each request with a mock response + req.flush(expectedResult); + }); + + it('should handle errors', (done) => { + service.fetchTestStations().subscribe({ + next: () => {}, + error: (e) => { + expect(e.error).toBe('Deliberate 500 error'); + expect(e.status).toBe(500); + expect(e.statusText).toBe('Server Error'); + done(); + }, + }); + + // Check for correct requests: should have made one request to search from expected URL + const req = httpTestingController.expectOne(`${environment.VTM_API_URI}/test-stations/`); + expect(req.request.method).toBe('GET'); + + // Respond with mock error + req.flush('Deliberate 500 error', { status: 500, statusText: 'Server Error' }); + }); + }); + + describe('fetchTestStation', () => { + it('should get a matching result', () => { + const expectedId = 'some ID'; + const expectedResult = { testStationName: 'Some Name' } as TestStation; + service.fetchTestStation(expectedId).subscribe((response) => expect(response).toEqual(expectedResult)); + + // Check for correct requests: should have made one request to search from expected URL + const req = httpTestingController.expectOne(`${environment.VTM_API_URI}/test-stations/${expectedId}`); + expect(req.request.method).toBe('GET'); + + // Provide each request with a mock response + req.flush(expectedResult); + }); + + it('should handle errors', (done) => { + const expectedId = 'some ID'; + service.fetchTestStation(expectedId).subscribe({ + next: () => {}, + error: (e) => { + expect(e.error).toBe('Deliberate 500 error'); + expect(e.status).toBe(500); + expect(e.statusText).toBe('Server Error'); + done(); + }, + }); + + // Check for correct requests: should have made one request to search from expected URL + const req = httpTestingController.expectOne(`${environment.VTM_API_URI}/test-stations/${expectedId}`); + expect(req.request.method).toBe('GET'); + + // Respond with mock error + req.flush('Deliberate 500 error', { status: 500, statusText: 'Server Error' }); + }); + }); }); diff --git a/src/app/services/test-stations/test-stations.service.ts b/src/app/services/test-stations/test-stations.service.ts index f6ba2b6e14..6790bf1696 100644 --- a/src/app/services/test-stations/test-stations.service.ts +++ b/src/app/services/test-stations/test-stations.service.ts @@ -3,33 +3,37 @@ import { Injectable } from '@angular/core'; import { MultiOptions } from '@forms/models/options.model'; import { TestStation } from '@models/test-stations/test-station.model'; import { Store } from '@ngrx/store'; -import { testStations, TestStationsState } from '@store/test-stations'; -import { map, Observable } from 'rxjs'; +import { TestStationsState, testStations } from '@store/test-stations'; +import { Observable, map } from 'rxjs'; import { environment } from '../../../environments/environment'; @Injectable({ providedIn: 'root' }) export class TestStationsService { - private url = `${environment.VTM_API_URI}/test-stations/`; + private url = `${environment.VTM_API_URI}/test-stations/`; - constructor(private http: HttpClient, private store: Store) {} + constructor( + private http: HttpClient, + private store: Store + ) {} - fetchTestStations(): Observable> { - return this.http.get>(this.url, { responseType: 'json' }); - } + fetchTestStations(): Observable> { + return this.http.get>(this.url, { responseType: 'json' }); + } - fetchTestStation(id: string): Observable { - return this.http.get(this.url + id, { responseType: 'json' }); - } + fetchTestStation(id: string): Observable { + return this.http.get(this.url + id, { responseType: 'json' }); + } - getTestStationsOptions(): Observable { - return this.store.select(testStations).pipe( - map((allTestStations) => - allTestStations - .sort((a, b) => a.testStationName.localeCompare(b.testStationName)) - .map((testStation) => { - const label = `${testStation.testStationName} - ${testStation.testStationPNumber}`; - return { value: testStation.testStationPNumber, label }; - })), - ); - } + getTestStationsOptions(): Observable { + return this.store.select(testStations).pipe( + map((allTestStations) => + allTestStations + .sort((a, b) => a.testStationName.localeCompare(b.testStationName)) + .map((testStation) => { + const label = `${testStation.testStationName} - ${testStation.testStationPNumber}`; + return { value: testStation.testStationPNumber, label }; + }) + ) + ); + } } diff --git a/src/app/services/test-types/test-types.service.spec.ts b/src/app/services/test-types/test-types.service.spec.ts index 9f48602472..b6c6174589 100644 --- a/src/app/services/test-types/test-types.service.spec.ts +++ b/src/app/services/test-types/test-types.service.spec.ts @@ -5,18 +5,18 @@ import { initialAppState } from '@store/.'; import { TestTypesService } from './test-types.service'; describe('TestTypesService', () => { - let service: TestTypesService; + let service: TestTypesService; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [TestTypesService, provideMockStore({ initialState: initialAppState })], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [TestTypesService, provideMockStore({ initialState: initialAppState })], + }); - service = TestBed.inject(TestTypesService); - }); + service = TestBed.inject(TestTypesService); + }); - it('should be created', () => { - expect(service).toBeTruthy(); - }); + it('should be created', () => { + expect(service).toBeTruthy(); + }); }); diff --git a/src/app/services/test-types/test-types.service.ts b/src/app/services/test-types/test-types.service.ts index 3bef6041ac..ae9586e44c 100644 --- a/src/app/services/test-types/test-types.service.ts +++ b/src/app/services/test-types/test-types.service.ts @@ -1,8 +1,6 @@ import { HttpClient } from '@angular/common/http'; import { Inject, Injectable, Optional } from '@angular/core'; -import { - BASE_PATH, Configuration, TestTypesService as TestTypesApiService, TestTypesTaxonomy, -} from '@api/test-types'; +import { BASE_PATH, Configuration, TestTypesService as TestTypesApiService, TestTypesTaxonomy } from '@api/test-types'; import { Store } from '@ngrx/store'; import { State } from '@store/.'; import { testTypeIdChanged } from '@store/test-records'; @@ -11,27 +9,27 @@ import { selectTestTypesByVehicleType } from '@store/test-types/selectors/test-t import { Observable } from 'rxjs'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class TestTypesService extends TestTypesApiService { - constructor( - httpClient: HttpClient, - @Optional() @Inject(BASE_PATH) basePath: string, - @Optional() configuration: Configuration, - private store: Store, - ) { - super(httpClient, basePath, configuration); - } + constructor( + httpClient: HttpClient, + @Optional() @Inject(BASE_PATH) basePath: string, + @Optional() configuration: Configuration, + private store: Store + ) { + super(httpClient, basePath, configuration); + } - get selectAllTestTypes$(): Observable { - return this.store.select(selectTestTypesByVehicleType); - } + get selectAllTestTypes$(): Observable { + return this.store.select(selectTestTypesByVehicleType); + } - fetchTestTypes(): void { - this.store.dispatch(fetchTestTypes()); - } + fetchTestTypes(): void { + this.store.dispatch(fetchTestTypes()); + } - testTypeIdChanged(testTypeId: string): void { - this.store.dispatch(testTypeIdChanged({ testTypeId })); - } + testTypeIdChanged(testTypeId: string): void { + this.store.dispatch(testTypeIdChanged({ testTypeId })); + } } diff --git a/src/app/services/user-service/user-service.spec.ts b/src/app/services/user-service/user-service.spec.ts index 463c826cdd..7005e38f5a 100644 --- a/src/app/services/user-service/user-service.spec.ts +++ b/src/app/services/user-service/user-service.spec.ts @@ -9,77 +9,80 @@ import { UserServiceState } from '../../store/user/user-service.reducer'; import { UserService } from './user-service'; jest.mock('jwt-decode', () => ({ - jwtDecode: () => ({ roles: ['12345'] }), + jwtDecode: () => ({ roles: ['12345'] }), })); describe('User-Service', () => { - let service: UserService; + let service: UserService; - let mockStore: Store<{ userservice: UserServiceState }>; - let mockBroadcast: MsalBroadcastService; - let mockMsal: MsalService; + let mockStore: Store<{ userservice: UserServiceState }>; + let mockBroadcast: MsalBroadcastService; + let mockMsal: MsalService; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [AppModule, RouterTestingModule], - providers: [Store, MsalService, MsalBroadcastService], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [AppModule, RouterTestingModule], + providers: [Store, MsalService, MsalBroadcastService], + }); - mockStore = TestBed.inject(Store); - mockBroadcast = TestBed.inject(MsalBroadcastService); - mockMsal = TestBed.inject(MsalService); + mockStore = TestBed.inject(Store); + mockBroadcast = TestBed.inject(MsalBroadcastService); + mockMsal = TestBed.inject(MsalService); - service = new UserService(mockStore, mockBroadcast, mockMsal); - }); + service = new UserService(mockStore, mockBroadcast, mockMsal); + }); - it('should create the user service', () => { - expect(service).toBeTruthy(); - }); + it('should create the user service', () => { + expect(service).toBeTruthy(); + }); - describe('User getters', () => { - const user = { - name: 'name', userEmail: 'name@mail.com', oid: '123', accessToken: '12345', - }; + describe('User getters', () => { + const user = { + name: 'name', + userEmail: 'name@mail.com', + oid: '123', + accessToken: '12345', + }; - beforeEach(() => { - service.logIn(user); - }); + beforeEach(() => { + service.logIn(user); + }); - it('should get the userEmail', (done) => { - service.userEmail$.pipe(take(1)).subscribe((data) => { - expect(data).toEqual(user.userEmail); - done(); - }); - }); + it('should get the userEmail', (done) => { + service.userEmail$.pipe(take(1)).subscribe((data) => { + expect(data).toEqual(user.userEmail); + done(); + }); + }); - it('should get the name', (done) => { - service.name$.pipe(take(1)).subscribe((data) => { - expect(data).toEqual(user.name); - done(); - }); - }); + it('should get the name', (done) => { + service.name$.pipe(take(1)).subscribe((data) => { + expect(data).toEqual(user.name); + done(); + }); + }); - it('should get the id', (done) => { - service.id$.pipe(take(1)).subscribe((data) => { - expect(data).toEqual(user.oid); - done(); - }); - }); + it('should get the id', (done) => { + service.id$.pipe(take(1)).subscribe((data) => { + expect(data).toEqual(user.oid); + done(); + }); + }); - it('should get the roles', (done) => { - service.roles$.pipe(take(1)).subscribe((data) => { - expect(data).toEqual([user.accessToken]); - done(); - }); - }); - }); + it('should get the roles', (done) => { + service.roles$.pipe(take(1)).subscribe((data) => { + expect(data).toEqual([user.accessToken]); + done(); + }); + }); + }); - it('should logout', () => { - const dispatchSpy = jest.spyOn(mockStore, 'dispatch'); - const MsalSpy = jest.spyOn(mockMsal, 'logout').mockImplementation(() => of()); - service.logOut(); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(Logout()); - expect(MsalSpy).toHaveBeenCalledTimes(1); - }); + it('should logout', () => { + const dispatchSpy = jest.spyOn(mockStore, 'dispatch'); + const MsalSpy = jest.spyOn(mockMsal, 'logout').mockImplementation(() => of()); + service.logOut(); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith(Logout()); + expect(MsalSpy).toHaveBeenCalledTimes(1); + }); }); diff --git a/src/app/services/user-service/user-service.ts b/src/app/services/user-service/user-service.ts index 4d70d859f5..82cdbc5a31 100644 --- a/src/app/services/user-service/user-service.ts +++ b/src/app/services/user-service/user-service.ts @@ -10,74 +10,89 @@ import * as UserServiceState from '../../store/user/user-service.reducer'; @Injectable({ providedIn: 'root' }) export class UserService implements OnDestroy { - private readonly destroying$ = new Subject(); + private readonly destroying$ = new Subject(); - constructor(private store: Store, private msalBroadcastService: MsalBroadcastService, private msal: MsalService) { - this.msalBroadcastService.msalSubject$ - .pipe( - filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_SUCCESS), - takeUntil(this.destroying$), - ) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - .subscribe((result: any) => { - const { - payload: { - account: { - name, - idTokenClaims: { oid, preferred_username, email }, - }, - accessToken, - }, - } = result; - const userEmail = email || preferred_username; - this.logIn({ - name, userEmail, oid, accessToken, - }); - }); - } + constructor( + private store: Store, + private msalBroadcastService: MsalBroadcastService, + private msal: MsalService + ) { + this.msalBroadcastService.msalSubject$ + .pipe( + filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_SUCCESS), + takeUntil(this.destroying$) + ) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .subscribe((result: any) => { + const { + payload: { + account: { + name, + idTokenClaims: { oid, preferred_username, email }, + }, + accessToken, + }, + } = result; + const userEmail = email || preferred_username; + this.logIn({ + name, + userEmail, + oid, + accessToken, + }); + }); + } - ngOnDestroy(): void { - this.destroying$.next(); - this.destroying$.complete(); - } + ngOnDestroy(): void { + this.destroying$.next(); + this.destroying$.complete(); + } - logIn({ - name, userEmail, oid, accessToken, - }: { name: string; userEmail: string; oid: string; accessToken: string }): void { - window.localStorage.setItem('accessToken', accessToken); - const decodedJWT = jwtDecode(accessToken); - const { roles } = decodedJWT as { roles: string[] }; - this.store.dispatch(UserServiceActions.Login({ - name, userEmail, oid, roles, - })); - } + logIn({ + name, + userEmail, + oid, + accessToken, + }: { name: string; userEmail: string; oid: string; accessToken: string }): void { + window.localStorage.setItem('accessToken', accessToken); + const decodedJWT = jwtDecode(accessToken); + const { roles } = decodedJWT as { roles: string[] }; + this.store.dispatch( + UserServiceActions.Login({ + name, + userEmail, + oid, + roles, + }) + ); + } - get name$(): Observable { - return this.store.pipe(select(UserServiceState.name)); - } + get name$(): Observable { + return this.store.pipe(select(UserServiceState.name)); + } - get userEmail$(): Observable { - return this.store.pipe(select(UserServiceState.userEmail)); - } + get userEmail$(): Observable { + return this.store.pipe(select(UserServiceState.userEmail)); + } - get id$(): Observable { - return this.store.pipe(select(UserServiceState.id)); - } + get id$(): Observable { + return this.store.pipe(select(UserServiceState.id)); + } - get roles$(): Observable { - return this.store.pipe(select(UserServiceState.roles)); - } + get roles$(): Observable { + return this.store.pipe(select(UserServiceState.roles)); + } - logOut(): void { - this.store.dispatch(UserServiceActions.Logout()); - this.msal.logout(); - } + logOut(): void { + this.store.dispatch(UserServiceActions.Logout()); + this.msal.logout(); + } - get inProgress$(): Observable { - return this.msalBroadcastService.inProgress$; - } + get inProgress$(): Observable { + return this.msalBroadcastService.inProgress$; + } - get user$(): Observable { - return this.store.pipe(select(UserServiceState.user)); - } + get user$(): Observable { + return this.store.pipe(select(UserServiceState.user)); + } } diff --git a/src/app/shared/components/accordion-control/accordion-control.component.spec.ts b/src/app/shared/components/accordion-control/accordion-control.component.spec.ts index d4cb6e4dac..981a1f2c20 100644 --- a/src/app/shared/components/accordion-control/accordion-control.component.spec.ts +++ b/src/app/shared/components/accordion-control/accordion-control.component.spec.ts @@ -7,41 +7,41 @@ import { AccordionComponent } from '../accordion/accordion.component'; import { AccordionControlComponent } from './accordion-control.component'; @Component({ - selector: 'app-host', - template: ` + selector: 'app-host', + template: `
Details
`, }) -class HostComponent { } +class HostComponent {} describe('AccordionControlComponent', () => { - let component: AccordionControlComponent; - let fixture: ComponentFixture; + let component: AccordionControlComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AccordionControlComponent, HostComponent, AccordionComponent], - providers: [provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AccordionControlComponent, HostComponent, AccordionComponent], + providers: [provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + }); - beforeEach(async () => { - fixture = TestBed.createComponent(HostComponent); - component = fixture.debugElement.query(By.directive(AccordionControlComponent)).componentInstance; - fixture.detectChanges(); - await fixture.whenRenderingDone(); - }); + beforeEach(async () => { + fixture = TestBed.createComponent(HostComponent); + component = fixture.debugElement.query(By.directive(AccordionControlComponent)).componentInstance; + fixture.detectChanges(); + await fixture.whenRenderingDone(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it('should open and close child accordions', () => { - expect(component.accordions?.length).toBe(1); - expect(component.accordions?.get(0)?.isExpanded).toBeFalsy(); - component.toggle(); - expect(component.accordions?.get(0)?.isExpanded).toBeTruthy(); - component.toggle(); - expect(component.accordions?.get(0)?.isExpanded).toBeFalsy(); - }); + it('should open and close child accordions', () => { + expect(component.accordions?.length).toBe(1); + expect(component.accordions?.get(0)?.isExpanded).toBeFalsy(); + component.toggle(); + expect(component.accordions?.get(0)?.isExpanded).toBeTruthy(); + component.toggle(); + expect(component.accordions?.get(0)?.isExpanded).toBeFalsy(); + }); }); diff --git a/src/app/shared/components/accordion-control/accordion-control.component.ts b/src/app/shared/components/accordion-control/accordion-control.component.ts index 79920d5017..8bf0e776da 100644 --- a/src/app/shared/components/accordion-control/accordion-control.component.ts +++ b/src/app/shared/components/accordion-control/accordion-control.component.ts @@ -1,35 +1,46 @@ import { - ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChildren, Input, QueryList, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ContentChildren, + Input, + QueryList, } from '@angular/core'; import { AccordionComponent } from '../accordion/accordion.component'; @Component({ - selector: 'app-accordion-control', - templateUrl: './accordion-control.component.html', - styleUrls: ['accordion-control.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-accordion-control', + templateUrl: './accordion-control.component.html', + styleUrls: ['accordion-control.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class AccordionControlComponent { - private accordionsList?: QueryList; - get accordions(): QueryList | undefined { - return this.accordionsList; - } - @ContentChildren(AccordionComponent, { descendants: true, emitDistinctChangesOnly: false }) set accordions( - value: QueryList | undefined, + private accordionsList?: QueryList; + get accordions(): QueryList | undefined { + return this.accordionsList; + } + @ContentChildren(AccordionComponent, { descendants: true, emitDistinctChangesOnly: false }) set accordions( + value: QueryList | undefined + , ) { - this.accordionsList = value; - if (this.accordionsList?.length === this.sectionState?.length) { + this. + accordionsList = value; + if (this.accordionsList?.length === this.sectionState?.length) { this.isExpanded = true; } - if (this.isExpanded) { + if (this.isExpanded) { this.toggleAccordions(); } - this.expandAccordions(); - } + this; + . + expandAccordions(); +} - @Input() isExpanded = false; - @Input() layout?: string; - @Input() class = ''; +@Input() +isExpanded = false; +@Input() +layout?: string; +@Input() class = ''; @Input() sectionState: (string | number)[] | undefined | null = []; constructor(private cdr: ChangeDetectorRef) {} diff --git a/src/app/shared/components/accordion/accordion.component.spec.ts b/src/app/shared/components/accordion/accordion.component.spec.ts index b6ae536570..2acf7335c9 100644 --- a/src/app/shared/components/accordion/accordion.component.spec.ts +++ b/src/app/shared/components/accordion/accordion.component.spec.ts @@ -7,68 +7,68 @@ import { addSectionState, removeSectionState } from '@store/technical-records'; import { AccordionComponent } from './accordion.component'; @Component({ - selector: 'app-host', - template: '
Details
', + selector: 'app-host', + template: '
Details
', }) class HostComponent {} describe('AccordionComponent', () => { - let component: AccordionComponent; - let fixture: ComponentFixture; - let store: MockStore; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AccordionComponent, HostComponent], - providers: [provideMockStore({ initialState: initialAppState })], - }).compileComponents(); - store = TestBed.inject(MockStore); - }); + let component: AccordionComponent; + let fixture: ComponentFixture; + let store: MockStore; + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [AccordionComponent, HostComponent], + providers: [provideMockStore({ initialState: initialAppState })], + }).compileComponents(); + store = TestBed.inject(MockStore); + }); - beforeEach(() => { - fixture = TestBed.createComponent(HostComponent); - component = fixture.debugElement.query(By.directive(AccordionComponent)).componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(HostComponent); + component = fixture.debugElement.query(By.directive(AccordionComponent)).componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it('should render dynamic content', () => { - const content: HTMLDivElement = fixture.debugElement.query(By.css('#content')).nativeElement; - expect(content.innerHTML).toBe('Details'); - }); + it('should render dynamic content', () => { + const content: HTMLDivElement = fixture.debugElement.query(By.css('#content')).nativeElement; + expect(content.innerHTML).toBe('Details'); + }); - it('should toggle expanded value', () => { - const button: HTMLButtonElement = fixture.debugElement.query(By.css('#accordion-control-test')).nativeElement; + it('should toggle expanded value', () => { + const button: HTMLButtonElement = fixture.debugElement.query(By.css('#accordion-control-test')).nativeElement; - button.click(); - expect(component.isExpanded).toBeTruthy(); + button.click(); + expect(component.isExpanded).toBeTruthy(); - button.click(); - expect(component.isExpanded).toBeFalsy(); - }); + button.click(); + expect(component.isExpanded).toBeFalsy(); + }); - it('should set expanded value to true', () => { - const markForCheckSpy = jest.spyOn(component['cdr'], 'markForCheck'); - const dispatchSpy = jest.spyOn(store, 'dispatch'); + it('should set expanded value to true', () => { + const markForCheckSpy = jest.spyOn(component['cdr'], 'markForCheck'); + const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.open('TEST_SECTION'); - expect(component.isExpanded).toBeTruthy(); - expect(markForCheckSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(addSectionState({ section: 'TEST_SECTION' })); - }); + component.open('TEST_SECTION'); + expect(component.isExpanded).toBeTruthy(); + expect(markForCheckSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith(addSectionState({ section: 'TEST_SECTION' })); + }); - it('should set expanded value to false', () => { - const markForCheckSpy = jest.spyOn(component['cdr'], 'markForCheck'); - const dispatchSpy = jest.spyOn(store, 'dispatch'); + it('should set expanded value to false', () => { + const markForCheckSpy = jest.spyOn(component['cdr'], 'markForCheck'); + const dispatchSpy = jest.spyOn(store, 'dispatch'); - component.isExpanded = true; - component.close('TEST_SECTION'); - expect(component.isExpanded).toBeFalsy(); - expect(markForCheckSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledTimes(1); - expect(dispatchSpy).toHaveBeenCalledWith(removeSectionState({ section: 'TEST_SECTION' })); - }); + component.isExpanded = true; + component.close('TEST_SECTION'); + expect(component.isExpanded).toBeFalsy(); + expect(markForCheckSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledTimes(1); + expect(dispatchSpy).toHaveBeenCalledWith(removeSectionState({ section: 'TEST_SECTION' })); + }); }); diff --git a/src/app/shared/components/accordion/accordion.component.ts b/src/app/shared/components/accordion/accordion.component.ts index 8934cc8dad..d19cf6bd70 100644 --- a/src/app/shared/components/accordion/accordion.component.ts +++ b/src/app/shared/components/accordion/accordion.component.ts @@ -1,38 +1,37 @@ -import { - ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, -} from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input } from '@angular/core'; import { Store } from '@ngrx/store'; -import { - addSectionState, removeSectionState, -} from '@store/technical-records'; +import { addSectionState, removeSectionState } from '@store/technical-records'; @Component({ - selector: 'app-accordion[id]', - templateUrl: './accordion.component.html', - styleUrls: ['./accordion.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-accordion[id]', + templateUrl: './accordion.component.html', + styleUrls: ['./accordion.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class AccordionComponent { - @Input() title: string | undefined = ''; - @Input() id: string | number = ''; + @Input() title: string | undefined = ''; + @Input() id: string | number = ''; - @Input() isExpanded: boolean | null | undefined = false; + @Input() isExpanded: boolean | null | undefined = false; - constructor(private cdr: ChangeDetectorRef, private store: Store) {} + constructor( + private cdr: ChangeDetectorRef, + private store: Store + ) {} - get iconStyle(): string { - return `govuk-accordion-nav__chevron${(this.isExpanded ? '' : ' govuk-accordion-nav__chevron--down')}`; - } + get iconStyle(): string { + return `govuk-accordion-nav__chevron${this.isExpanded ? '' : ' govuk-accordion-nav__chevron--down'}`; + } - open(sectionName: string | number | undefined): void { - this.isExpanded = true; - this.cdr.markForCheck(); - if (sectionName) this.store.dispatch(addSectionState({ section: sectionName })); - } + open(sectionName: string | number | undefined): void { + this.isExpanded = true; + this.cdr.markForCheck(); + if (sectionName) this.store.dispatch(addSectionState({ section: sectionName })); + } - close(sectionName: string | number | undefined): void { - this.isExpanded = false; - this.cdr.markForCheck(); - if (sectionName) this.store.dispatch(removeSectionState({ section: sectionName })); - } + close(sectionName: string | number | undefined): void { + this.isExpanded = false; + this.cdr.markForCheck(); + if (sectionName) this.store.dispatch(removeSectionState({ section: sectionName })); + } } diff --git a/src/app/shared/components/banner/banner.component.spec.ts b/src/app/shared/components/banner/banner.component.spec.ts index 7b0dc68397..865c11ae07 100644 --- a/src/app/shared/components/banner/banner.component.spec.ts +++ b/src/app/shared/components/banner/banner.component.spec.ts @@ -3,22 +3,22 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { BannerComponent } from './banner.component'; describe('BannerComponent', () => { - let component: BannerComponent; - let fixture: ComponentFixture; + let component: BannerComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [BannerComponent], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BannerComponent], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(BannerComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(BannerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/shared/components/banner/banner.component.ts b/src/app/shared/components/banner/banner.component.ts index b58afe14cc..27b1063242 100644 --- a/src/app/shared/components/banner/banner.component.ts +++ b/src/app/shared/components/banner/banner.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; @Component({ - selector: 'app-banner', - templateUrl: './banner.component.html', + selector: 'app-banner', + templateUrl: './banner.component.html', }) export class BannerComponent {} diff --git a/src/app/shared/components/base-dialog/base-dialog.component.spec.ts b/src/app/shared/components/base-dialog/base-dialog.component.spec.ts index 28dbb7da27..ac5a25b311 100644 --- a/src/app/shared/components/base-dialog/base-dialog.component.spec.ts +++ b/src/app/shared/components/base-dialog/base-dialog.component.spec.ts @@ -3,22 +3,22 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { BaseDialogComponent } from './base-dialog.component'; describe('BaseDialogComponent', () => { - let component: BaseDialogComponent; - let fixture: ComponentFixture; + let component: BaseDialogComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [BaseDialogComponent], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BaseDialogComponent], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(BaseDialogComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(BaseDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/shared/components/base-dialog/base-dialog.component.ts b/src/app/shared/components/base-dialog/base-dialog.component.ts index 60b050adda..efd8502c8a 100644 --- a/src/app/shared/components/base-dialog/base-dialog.component.ts +++ b/src/app/shared/components/base-dialog/base-dialog.component.ts @@ -1,13 +1,13 @@ -import { Component, Output, EventEmitter } from '@angular/core'; +import { Component, EventEmitter, Output } from '@angular/core'; @Component({ - selector: 'app-base-dialog', - template: '', + selector: 'app-base-dialog', + template: '', }) export class BaseDialogComponent { - @Output() action = new EventEmitter(); + @Output() action = new EventEmitter(); - handleAction(action: string) { - this.action.emit(action); - } + handleAction(action: string) { + this.action.emit(action); + } } diff --git a/src/app/shared/components/button-group/button-group.component.spec.ts b/src/app/shared/components/button-group/button-group.component.spec.ts index 5aabb154dd..81fe8fd84d 100644 --- a/src/app/shared/components/button-group/button-group.component.spec.ts +++ b/src/app/shared/components/button-group/button-group.component.spec.ts @@ -2,22 +2,22 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ButtonGroupComponent } from './button-group.component'; describe('ButtonGroupComponent', () => { - let component: ButtonGroupComponent; - let fixture: ComponentFixture; + let component: ButtonGroupComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ButtonGroupComponent], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ButtonGroupComponent], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(ButtonGroupComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(ButtonGroupComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/shared/components/button-group/button-group.component.ts b/src/app/shared/components/button-group/button-group.component.ts index 0f811fb6ca..205b61296e 100644 --- a/src/app/shared/components/button-group/button-group.component.ts +++ b/src/app/shared/components/button-group/button-group.component.ts @@ -1,9 +1,9 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; @Component({ - selector: 'app-button-group', - templateUrl: './button-group.component.html', - styleUrls: ['./button-group.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-button-group', + templateUrl: './button-group.component.html', + styleUrls: ['./button-group.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class ButtonGroupComponent {} diff --git a/src/app/shared/components/button/button.component.spec.ts b/src/app/shared/components/button/button.component.spec.ts index 59bb80f3ff..413d986027 100644 --- a/src/app/shared/components/button/button.component.spec.ts +++ b/src/app/shared/components/button/button.component.spec.ts @@ -3,23 +3,23 @@ import { RouterTestingModule } from '@angular/router/testing'; import { ButtonComponent } from './button.component'; describe('ButtonComponent', () => { - let component: ButtonComponent; - let fixture: ComponentFixture; + let component: ButtonComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ButtonComponent], - imports: [RouterTestingModule], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ButtonComponent], + imports: [RouterTestingModule], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(ButtonComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(ButtonComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/shared/components/button/button.component.ts b/src/app/shared/components/button/button.component.ts index e9fb7dd06a..a890405e21 100644 --- a/src/app/shared/components/button/button.component.ts +++ b/src/app/shared/components/button/button.component.ts @@ -1,19 +1,17 @@ -import { - ChangeDetectionStrategy, Component, EventEmitter, Input, Output, -} from '@angular/core'; +import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; import { RouterLinkWithHref } from '@angular/router'; @Component({ - selector: 'app-button', - templateUrl: './button.component.html', - styleUrls: ['./button.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-button', + templateUrl: './button.component.html', + styleUrls: ['./button.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class ButtonComponent extends RouterLinkWithHref { - @Input() id?: string; - @Input() disabled = false; - @Input() type: 'link' | 'button' = 'button'; - @Input() design: '' | 'secondary' | 'warning' | 'link' = ''; + @Input() id?: string; + @Input() disabled = false; + @Input() type: 'link' | 'button' = 'button'; + @Input() design: '' | 'secondary' | 'warning' | 'link' = ''; - @Output() clicked = new EventEmitter(); + @Output() clicked = new EventEmitter(); } diff --git a/src/app/shared/components/collapsible-text/collapsible-text.component.spec.ts b/src/app/shared/components/collapsible-text/collapsible-text.component.spec.ts index 1dd3750ca8..5a58540798 100644 --- a/src/app/shared/components/collapsible-text/collapsible-text.component.spec.ts +++ b/src/app/shared/components/collapsible-text/collapsible-text.component.spec.ts @@ -2,35 +2,34 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { CollapsibleTextComponent } from './collapsible-text.component'; describe('CollapsibleTextComponent', () => { - let component: CollapsibleTextComponent; - let fixture: ComponentFixture; + let component: CollapsibleTextComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [CollapsibleTextComponent], - }) - .compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [CollapsibleTextComponent], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(CollapsibleTextComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(CollapsibleTextComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); - it('should open when open method is called', () => { - component.isCollapsed = true; - component.open(); - expect(component.isCollapsed).toBe(false); - }); + it('should open when open method is called', () => { + component.isCollapsed = true; + component.open(); + expect(component.isCollapsed).toBe(false); + }); - it('should close when close method is called', () => { - component.isCollapsed = false; - component.close(); - expect(component.isCollapsed).toBe(true); - }); + it('should close when close method is called', () => { + component.isCollapsed = false; + component.close(); + expect(component.isCollapsed).toBe(true); + }); }); diff --git a/src/app/shared/components/collapsible-text/collapsible-text.component.ts b/src/app/shared/components/collapsible-text/collapsible-text.component.ts index e39ff48585..031e696c21 100644 --- a/src/app/shared/components/collapsible-text/collapsible-text.component.ts +++ b/src/app/shared/components/collapsible-text/collapsible-text.component.ts @@ -1,21 +1,20 @@ import { Component, Input } from '@angular/core'; @Component({ - selector: 'collapsible-text', - templateUrl: './collapsible-text.component.html', - styleUrls: ['./collapsible-text.component.scss'], + selector: 'collapsible-text', + templateUrl: './collapsible-text.component.html', + styleUrls: ['./collapsible-text.component.scss'], }) export class CollapsibleTextComponent { + @Input() text = ''; + @Input() maxChars = 0; + @Input() isCollapsed = true; - @Input() text: string = ''; - @Input() maxChars: number = 0; - @Input() isCollapsed = true; + open() { + this.isCollapsed = false; + } - open() { - this.isCollapsed = false; - } - - close() { - this.isCollapsed = true; - } + close() { + this.isCollapsed = true; + } } diff --git a/src/app/shared/components/icon/icon.component.spec.ts b/src/app/shared/components/icon/icon.component.spec.ts index bc86bb27ba..2a0824d9d1 100644 --- a/src/app/shared/components/icon/icon.component.spec.ts +++ b/src/app/shared/components/icon/icon.component.spec.ts @@ -2,22 +2,22 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { IconComponent } from './icon.component'; describe('IconComponent', () => { - let component: IconComponent; - let fixture: ComponentFixture; + let component: IconComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [IconComponent], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [IconComponent], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(IconComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(IconComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/shared/components/icon/icon.component.ts b/src/app/shared/components/icon/icon.component.ts index d92d1d9f78..e50f894b56 100644 --- a/src/app/shared/components/icon/icon.component.ts +++ b/src/app/shared/components/icon/icon.component.ts @@ -1,10 +1,10 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; @Component({ - selector: 'app-icon', - templateUrl: './icon.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-icon', + templateUrl: './icon.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class IconComponent { - @Input() icon = ''; + @Input() icon = ''; } diff --git a/src/app/shared/components/input-spinner/input-spinner.component.spec.ts b/src/app/shared/components/input-spinner/input-spinner.component.spec.ts index 70f0da906d..ae3c9efa91 100644 --- a/src/app/shared/components/input-spinner/input-spinner.component.spec.ts +++ b/src/app/shared/components/input-spinner/input-spinner.component.spec.ts @@ -3,22 +3,22 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { InputSpinnerComponent } from './input-spinner.component'; describe('InputSpinnerComponent', () => { - let component: InputSpinnerComponent; - let fixture: ComponentFixture; + let component: InputSpinnerComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [InputSpinnerComponent], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [InputSpinnerComponent], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(InputSpinnerComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(InputSpinnerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/shared/components/input-spinner/input-spinner.component.ts b/src/app/shared/components/input-spinner/input-spinner.component.ts index 4aeff2257c..aa16f6e1d6 100644 --- a/src/app/shared/components/input-spinner/input-spinner.component.ts +++ b/src/app/shared/components/input-spinner/input-spinner.component.ts @@ -1,10 +1,10 @@ import { Component, Input } from '@angular/core'; @Component({ - selector: 'app-input-spinner', - templateUrl: './input-spinner.component.html', - styleUrls: ['./input-spinner.component.scss'], + selector: 'app-input-spinner', + templateUrl: './input-spinner.component.html', + styleUrls: ['./input-spinner.component.scss'], }) export class InputSpinnerComponent { - @Input() isValid = ''; + @Input() isValid = ''; } diff --git a/src/app/shared/components/number-plate/number-plate.component.spec.ts b/src/app/shared/components/number-plate/number-plate.component.spec.ts index e43ef17220..4d63f16945 100644 --- a/src/app/shared/components/number-plate/number-plate.component.spec.ts +++ b/src/app/shared/components/number-plate/number-plate.component.spec.ts @@ -3,55 +3,55 @@ import { DefaultNullOrEmpty } from '@shared/pipes/default-null-or-empty/default- import { NumberPlateComponent } from './number-plate.component'; describe('NumberPlateComponent', () => { - let component: NumberPlateComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [NumberPlateComponent, DefaultNullOrEmpty], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(NumberPlateComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should format a standard vrm', () => { - component.vrm = 'AA21AAA'; - expect(component.vrm).toBe('AA21 AAA'); - }); - - it('should not format a short vrm', () => { - component.vrm = 'A123'; - expect(component.vrm).toBe('A123'); - }); - - describe('isZNumber', () => { - it('should return true if it matches the z number format', () => { - component.vrm = '1234567Z'; - expect(component.isZNumber(component.vrm)).toBeTruthy(); - }); - - it('should return false if the Z is not present at the end', () => { - component.vrm = '12345'; - expect(component.isZNumber(component.vrm)).toBeFalsy(); - component.vrm = '1234Z5'; - expect(component.isZNumber(component.vrm)).toBeFalsy(); - }); - - it('should return false if the z number does not match the format', () => { - component.vrm = 'A12345Z'; - expect(component.isZNumber(component.vrm)).toBeFalsy(); - component.vrm = '12+%345Z'; - expect(component.isZNumber(component.vrm)).toBeFalsy(); - component.vrm = 'Z'; - expect(component.isZNumber(component.vrm)).toBeFalsy(); - }); - }); + let component: NumberPlateComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [NumberPlateComponent, DefaultNullOrEmpty], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(NumberPlateComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should format a standard vrm', () => { + component.vrm = 'AA21AAA'; + expect(component.vrm).toBe('AA21 AAA'); + }); + + it('should not format a short vrm', () => { + component.vrm = 'A123'; + expect(component.vrm).toBe('A123'); + }); + + describe('isZNumber', () => { + it('should return true if it matches the z number format', () => { + component.vrm = '1234567Z'; + expect(component.isZNumber(component.vrm)).toBeTruthy(); + }); + + it('should return false if the Z is not present at the end', () => { + component.vrm = '12345'; + expect(component.isZNumber(component.vrm)).toBeFalsy(); + component.vrm = '1234Z5'; + expect(component.isZNumber(component.vrm)).toBeFalsy(); + }); + + it('should return false if the z number does not match the format', () => { + component.vrm = 'A12345Z'; + expect(component.isZNumber(component.vrm)).toBeFalsy(); + component.vrm = '12+%345Z'; + expect(component.isZNumber(component.vrm)).toBeFalsy(); + component.vrm = 'Z'; + expect(component.isZNumber(component.vrm)).toBeFalsy(); + }); + }); }); diff --git a/src/app/shared/components/number-plate/number-plate.component.ts b/src/app/shared/components/number-plate/number-plate.component.ts index ecab16c4fa..bfd6fbc55f 100644 --- a/src/app/shared/components/number-plate/number-plate.component.ts +++ b/src/app/shared/components/number-plate/number-plate.component.ts @@ -1,28 +1,28 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; @Component({ - selector: 'app-number-plate', - templateUrl: './number-plate.component.html', - styleUrls: ['./number-plate.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-number-plate', + templateUrl: './number-plate.component.html', + styleUrls: ['./number-plate.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class NumberPlateComponent { - private vrmToDisplay: string | undefined; + private vrmToDisplay: string | undefined; - @Input() isSecondary = false; - @Input() set vrm(value: string | undefined) { - // formatting: if the number plate is long enough, add a space before the final 3 characters - if (value && value.length >= 5 && !this.isZNumber(value)) { - this.vrmToDisplay = `${value.slice(0, value.length - 3)} ${value.slice(value.length - 3)}`; - } else { - this.vrmToDisplay = value; - } - } - get vrm(): string | undefined { - return this.vrmToDisplay; - } + @Input() isSecondary = false; + @Input() set vrm(value: string | undefined) { + // formatting: if the number plate is long enough, add a space before the final 3 characters + if (value && value.length >= 5 && !this.isZNumber(value)) { + this.vrmToDisplay = `${value.slice(0, value.length - 3)} ${value.slice(value.length - 3)}`; + } else { + this.vrmToDisplay = value; + } + } + get vrm(): string | undefined { + return this.vrmToDisplay; + } - isZNumber(vrm: string): boolean { - return (/^[0-9]{7}[zZ]$/).test(vrm); - } + isZNumber(vrm: string): boolean { + return /^[0-9]{7}[zZ]$/.test(vrm); + } } diff --git a/src/app/shared/components/pagination/pagination.component.spec.ts b/src/app/shared/components/pagination/pagination.component.spec.ts index 17e1296a41..87097a9dd4 100644 --- a/src/app/shared/components/pagination/pagination.component.spec.ts +++ b/src/app/shared/components/pagination/pagination.component.spec.ts @@ -1,186 +1,201 @@ import { Component, DebugElement } from '@angular/core'; -import { - ComponentFixture, fakeAsync, TestBed, tick, waitForAsync, -} from '@angular/core/testing'; +import { ComponentFixture, TestBed, fakeAsync, tick, waitForAsync } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { ActivatedRoute, Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; -import { map, Observable } from 'rxjs'; +import { Observable, map } from 'rxjs'; import { PaginationComponent } from './pagination.component'; @Component({ - selector: 'app-host', - template: '', + selector: 'app-host', + template: '', }) class HostComponent { - tableName = 'test-pagination'; - itemsPerPage = 5; - numberOfItems = 0; - - pageQuery$: Observable; - constructor(private route: ActivatedRoute) { - this.pageQuery$ = route.queryParams.pipe(map((params) => Number.parseInt(params[`${this.tableName}-page`] ?? '1', 10))); - } + tableName = 'test-pagination'; + itemsPerPage = 5; + numberOfItems = 0; + + pageQuery$: Observable; + constructor(private route: ActivatedRoute) { + this.pageQuery$ = route.queryParams.pipe( + map((params) => Number.parseInt(params[`${this.tableName}-page`] ?? '1', 10)) + ); + } } describe('PaginationComponent', () => { - let component: PaginationComponent; - let fixture: ComponentFixture; - let hostComponent: HostComponent; - let el: DebugElement; - let router: Router; - - beforeEach(waitForAsync(async () => { - await TestBed.configureTestingModule({ - declarations: [HostComponent, PaginationComponent], - imports: [RouterTestingModule.withRoutes([{ path: '', component: PaginationComponent }])], - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HostComponent); - hostComponent = fixture.componentInstance; - component = fixture.debugElement.query(By.directive(PaginationComponent)).componentInstance; - el = fixture.debugElement; - - router = TestBed.inject(Router); - - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it.each([ - [10, 5], - [5, 10], - ])('should return an array length of %d when items per page is %d', (arrayLength: number, itemsPerPage: number) => { - hostComponent.numberOfItems = 50; - component.itemsPerPage = itemsPerPage; - fixture.detectChanges(); - expect(component.pages).toHaveLength(arrayLength); - }); - - it.each([ - [[1, 2, 3, 4, 5], 1, 50, 5], - [[2, 3, 4, 5, 6], 4, 50, 5], - [[6, 7, 8, 9, 10], 10, 50, 5], - [[4, 5, 6, 7, 8], 6, 100, 10], - [[1, 2, 3, 4], 1, 17, 5], - ])( - 'should show pages %s on page %d when number of items is %d and items per page is %d', - fakeAsync((visiblePages: Array, currentPage: number, numberOfItems: number, itemsPerPage: number) => { - hostComponent.itemsPerPage = itemsPerPage; - hostComponent.numberOfItems = numberOfItems; - - fixture.ngZone?.run(() => { - router.initialNavigation(); - router.navigate([], { queryParams: component.pageQuery(currentPage) }).catch((error) => error); - tick(); - fixture.detectChanges(); - }); - - tick(); - - expect(component.visiblePages).toEqual(visiblePages); - }), - ); - - it.each([ - { - currentPage: 1, itemsPerPage: 5, start: 0, end: 5, - }, - { - currentPage: 2, itemsPerPage: 5, start: 5, end: 10, - }, - { - currentPage: 3, itemsPerPage: 15, start: 30, end: 45, - }, - ])( - 'should emit %p', - ({ - currentPage, itemsPerPage, start, end, - }: { currentPage: number; itemsPerPage: number; start: number; end: number }, done) => { - component.paginationOptions.subscribe((opts) => { - expect(opts.currentPage).toBe(currentPage); - expect(opts.start).toBe(start); - expect(opts.end).toBe(end); - done(); - }); - - component.itemsPerPage = itemsPerPage; - component.currentPageSubject.next(currentPage); - }, - ); - - describe('nextPage', () => { - it('should go page 1 to 2', fakeAsync(() => { - hostComponent.numberOfItems = 50; - fixture.detectChanges(); - - fixture.ngZone?.run(() => { - router.initialNavigation(); - }); - - const next: HTMLLinkElement = el.query(By.css(`#${component.tableName}-next-page`)).nativeElement; - next.click(); - - tick(); - fixture.detectChanges(); - - expect(router.url).toBe(`/?${component.tableName}-page=2`); - })); - - it('should not render "next" link when already on last page', fakeAsync(() => { - hostComponent.numberOfItems = 50; - fixture.detectChanges(); - - fixture.ngZone?.run(() => { - router.initialNavigation(); - router.navigate([], { queryParams: component.pageQuery(10) }).catch((error) => error); - tick(); - fixture.detectChanges(); - }); - - const next = el.query(By.css(`#${component.tableName}-next-page`)); - - expect(next).toBeNull(); - })); - }); - - describe('prevPage', () => { - it('should go from page 4 to 3', fakeAsync(() => { - hostComponent.numberOfItems = 50; - fixture.detectChanges(); - - fixture.ngZone?.run(() => { - router.initialNavigation(); - router.navigate([], { queryParams: component.pageQuery(4) }).catch((error) => error); - tick(); - fixture.detectChanges(); - }); - - const prev: HTMLLinkElement = el.query(By.css(`#${component.tableName}-prev-page`)).nativeElement; - prev.click(); - - tick(); - fixture.detectChanges(); - - expect(router.url).toBe(`/?${component.tableName}-page=3`); - })); - - it('should not render "prev" link when already on first page', fakeAsync(() => { - hostComponent.numberOfItems = 50; - fixture.detectChanges(); - - fixture.ngZone?.run(() => { - router.initialNavigation(); - }); - - const prev = el.query(By.css(`#${component.tableName}-prev-page`)); - - expect(prev).toBeNull(); - })); - }); + let component: PaginationComponent; + let fixture: ComponentFixture; + let hostComponent: HostComponent; + let el: DebugElement; + let router: Router; + + beforeEach(waitForAsync(async () => { + await TestBed.configureTestingModule({ + declarations: [HostComponent, PaginationComponent], + imports: [RouterTestingModule.withRoutes([{ path: '', component: PaginationComponent }])], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HostComponent); + hostComponent = fixture.componentInstance; + component = fixture.debugElement.query(By.directive(PaginationComponent)).componentInstance; + el = fixture.debugElement; + + router = TestBed.inject(Router); + + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it.each([ + [10, 5], + [5, 10], + ])('should return an array length of %d when items per page is %d', (arrayLength: number, itemsPerPage: number) => { + hostComponent.numberOfItems = 50; + component.itemsPerPage = itemsPerPage; + fixture.detectChanges(); + expect(component.pages).toHaveLength(arrayLength); + }); + + it.each([ + [[1, 2, 3, 4, 5], 1, 50, 5], + [[2, 3, 4, 5, 6], 4, 50, 5], + [[6, 7, 8, 9, 10], 10, 50, 5], + [[4, 5, 6, 7, 8], 6, 100, 10], + [[1, 2, 3, 4], 1, 17, 5], + ])( + 'should show pages %s on page %d when number of items is %d and items per page is %d', + fakeAsync((visiblePages: Array, currentPage: number, numberOfItems: number, itemsPerPage: number) => { + hostComponent.itemsPerPage = itemsPerPage; + hostComponent.numberOfItems = numberOfItems; + + fixture.ngZone?.run(() => { + router.initialNavigation(); + router.navigate([], { queryParams: component.pageQuery(currentPage) }).catch((error) => error); + tick(); + fixture.detectChanges(); + }); + + tick(); + + expect(component.visiblePages).toEqual(visiblePages); + }) + ); + + it.each([ + { + currentPage: 1, + itemsPerPage: 5, + start: 0, + end: 5, + }, + { + currentPage: 2, + itemsPerPage: 5, + start: 5, + end: 10, + }, + { + currentPage: 3, + itemsPerPage: 15, + start: 30, + end: 45, + }, + ])( + 'should emit %p', + ( + { + currentPage, + itemsPerPage, + start, + end, + }: { currentPage: number; itemsPerPage: number; start: number; end: number }, + done + ) => { + component.paginationOptions.subscribe((opts) => { + expect(opts.currentPage).toBe(currentPage); + expect(opts.start).toBe(start); + expect(opts.end).toBe(end); + done(); + }); + + component.itemsPerPage = itemsPerPage; + component.currentPageSubject.next(currentPage); + } + ); + + describe('nextPage', () => { + it('should go page 1 to 2', fakeAsync(() => { + hostComponent.numberOfItems = 50; + fixture.detectChanges(); + + fixture.ngZone?.run(() => { + router.initialNavigation(); + }); + + const next: HTMLLinkElement = el.query(By.css(`#${component.tableName}-next-page`)).nativeElement; + next.click(); + + tick(); + fixture.detectChanges(); + + expect(router.url).toBe(`/?${component.tableName}-page=2`); + })); + + it('should not render "next" link when already on last page', fakeAsync(() => { + hostComponent.numberOfItems = 50; + fixture.detectChanges(); + + fixture.ngZone?.run(() => { + router.initialNavigation(); + router.navigate([], { queryParams: component.pageQuery(10) }).catch((error) => error); + tick(); + fixture.detectChanges(); + }); + + const next = el.query(By.css(`#${component.tableName}-next-page`)); + + expect(next).toBeNull(); + })); + }); + + describe('prevPage', () => { + it('should go from page 4 to 3', fakeAsync(() => { + hostComponent.numberOfItems = 50; + fixture.detectChanges(); + + fixture.ngZone?.run(() => { + router.initialNavigation(); + router.navigate([], { queryParams: component.pageQuery(4) }).catch((error) => error); + tick(); + fixture.detectChanges(); + }); + + const prev: HTMLLinkElement = el.query(By.css(`#${component.tableName}-prev-page`)).nativeElement; + prev.click(); + + tick(); + fixture.detectChanges(); + + expect(router.url).toBe(`/?${component.tableName}-page=3`); + })); + + it('should not render "prev" link when already on first page', fakeAsync(() => { + hostComponent.numberOfItems = 50; + fixture.detectChanges(); + + fixture.ngZone?.run(() => { + router.initialNavigation(); + }); + + const prev = el.query(By.css(`#${component.tableName}-prev-page`)); + + expect(prev).toBeNull(); + })); + }); }); diff --git a/src/app/shared/components/pagination/pagination.component.ts b/src/app/shared/components/pagination/pagination.component.ts index abbbf321b3..6c46be3403 100644 --- a/src/app/shared/components/pagination/pagination.component.ts +++ b/src/app/shared/components/pagination/pagination.component.ts @@ -1,96 +1,112 @@ import { - ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnDestroy, OnInit, Output, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + EventEmitter, + Input, + OnDestroy, + OnInit, + Output, } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { - ReplaySubject, Subject, map, takeUntil, -} from 'rxjs'; +import { ReplaySubject, Subject, map, takeUntil } from 'rxjs'; @Component({ - selector: 'app-pagination[tableName]', - templateUrl: './pagination.component.html', - styleUrls: ['./pagination.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-pagination[tableName]', + templateUrl: './pagination.component.html', + styleUrls: ['./pagination.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class PaginationComponent implements OnInit, OnDestroy { - @Input() tableName!: string; - @Input() numberOfItems = 0; - @Input() itemsPerPage = 5; - @Output() paginationOptions = new EventEmitter<{ currentPage: number; itemsPerPage: number; start: number; end: number }>(); + @Input() tableName!: string; + @Input() numberOfItems = 0; + @Input() itemsPerPage = 5; + @Output() paginationOptions = new EventEmitter<{ + currentPage: number; + itemsPerPage: number; + start: number; + end: number; + }>(); - currentPage = 1; - currentPageSubject = new ReplaySubject(this.currentPage); - numberOfVisiblePages = 5; - _pages?: Array; + currentPage = 1; + currentPageSubject = new ReplaySubject(this.currentPage); + numberOfVisiblePages = 5; + _pages?: Array; - private destroy$ = new Subject(); + private destroy$ = new Subject(); - constructor(private route: ActivatedRoute, private cdr: ChangeDetectorRef) {} + constructor( + private route: ActivatedRoute, + private cdr: ChangeDetectorRef + ) {} - ngOnInit(): void { - this.route.queryParams - .pipe( - takeUntil(this.destroy$), - map((params) => Number.parseInt(params[`${this.tableName}-page`] ?? '1', 10)), - ) - .subscribe({ - next: (page) => { - this.currentPageSubject.next(page); - this.cdr.markForCheck(); - }, - }); + ngOnInit(): void { + this.route.queryParams + .pipe( + takeUntil(this.destroy$), + map((params) => Number.parseInt(params[`${this.tableName}-page`] ?? '1', 10)) + ) + .subscribe({ + next: (page) => { + this.currentPageSubject.next(page); + this.cdr.markForCheck(); + }, + }); - this.currentPageSubject.pipe(takeUntil(this.destroy$)).subscribe({ - next: (page) => { - const [start, end] = [(page - 1) * this.itemsPerPage, page * this.itemsPerPage]; + this.currentPageSubject.pipe(takeUntil(this.destroy$)).subscribe({ + next: (page) => { + const [start, end] = [(page - 1) * this.itemsPerPage, page * this.itemsPerPage]; - this.currentPage = page; - this.paginationOptions.emit({ - currentPage: page, itemsPerPage: this.itemsPerPage, start, end, - }); - this.cdr.markForCheck(); - }, - }); - } + this.currentPage = page; + this.paginationOptions.emit({ + currentPage: page, + itemsPerPage: this.itemsPerPage, + start, + end, + }); + this.cdr.markForCheck(); + }, + }); + } - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } - pageQuery(page: number) { - return { [`${this.tableName}-page`]: page }; - } - nextPage() { - return this.pageQuery(this.currentPage + 1); - } - prevPage() { - return this.pageQuery(this.currentPage - 1); - } + pageQuery(page: number) { + return { [`${this.tableName}-page`]: page }; + } + nextPage() { + return this.pageQuery(this.currentPage + 1); + } + prevPage() { + return this.pageQuery(this.currentPage - 1); + } - trackByFn(index: number, page: number) { - return page || index; - } + trackByFn(index: number, page: number) { + return page || index; + } - get pages() { - return Array(this.numberOfPages) - .fill('') - .map((x, i) => i + 1); - } + get pages() { + return Array(this.numberOfPages) + .fill('') + .map((x, i) => i + 1); + } - get numberOfPages() { - return Math.ceil(this.numberOfItems / this.itemsPerPage); - } + get numberOfPages() { + return Math.ceil(this.numberOfItems / this.itemsPerPage); + } - /** - * Returns array of visible page buttons. - * Allways returns an odd number of pages while keeping current page in the middle. - */ - get visiblePages() { - const range = (num: number, min: number, max: number) => Math.min(Math.max(num, min), max); - const middle = Math.ceil(this.numberOfVisiblePages / 2); - const clampedPage = range(this.currentPage, middle, this.pages.length - (middle - 1)); + /** + * Returns array of visible page buttons. + * Allways returns an odd number of pages while keeping current page in the middle. + */ + get visiblePages() { + const range = (num: number, min: number, max: number) => Math.min(Math.max(num, min), max); + const middle = Math.ceil(this.numberOfVisiblePages / 2); + const clampedPage = range(this.currentPage, middle, this.pages.length - (middle - 1)); - return this.pages.slice(Math.max(clampedPage - middle, 0), clampedPage + middle - 1); - } + return this.pages.slice(Math.max(clampedPage - middle, 0), clampedPage + middle - 1); + } } diff --git a/src/app/shared/components/router-outlet/router-outlet.component.spec.ts b/src/app/shared/components/router-outlet/router-outlet.component.spec.ts index d04dacffa0..807d44da2d 100644 --- a/src/app/shared/components/router-outlet/router-outlet.component.spec.ts +++ b/src/app/shared/components/router-outlet/router-outlet.component.spec.ts @@ -3,23 +3,23 @@ import { RouterTestingModule } from '@angular/router/testing'; import { RouterOutletComponent } from './router-outlet.component'; describe('RouterOutletComponent', () => { - let component: RouterOutletComponent; - let fixture: ComponentFixture; + let component: RouterOutletComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [RouterOutletComponent], - imports: [RouterTestingModule], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [RouterOutletComponent], + imports: [RouterTestingModule], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(RouterOutletComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(RouterOutletComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/shared/components/router-outlet/router-outlet.component.ts b/src/app/shared/components/router-outlet/router-outlet.component.ts index 02676774da..1f41ee3f94 100644 --- a/src/app/shared/components/router-outlet/router-outlet.component.ts +++ b/src/app/shared/components/router-outlet/router-outlet.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; @Component({ - selector: 'app-router-outlet', - templateUrl: './router-outlet.component.html', + selector: 'app-router-outlet', + templateUrl: './router-outlet.component.html', }) export class RouterOutletComponent {} diff --git a/src/app/shared/components/tag/tag.component.spec.ts b/src/app/shared/components/tag/tag.component.spec.ts index 4714994f1f..5536e01837 100644 --- a/src/app/shared/components/tag/tag.component.spec.ts +++ b/src/app/shared/components/tag/tag.component.spec.ts @@ -2,22 +2,22 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { TagComponent } from './tag.component'; describe('TagComponent', () => { - let component: TagComponent; - let fixture: ComponentFixture; + let component: TagComponent; + let fixture: ComponentFixture; - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [TagComponent], - }).compileComponents(); - }); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TagComponent], + }).compileComponents(); + }); - beforeEach(() => { - fixture = TestBed.createComponent(TagComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(TagComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); + }); }); diff --git a/src/app/shared/components/tag/tag.component.ts b/src/app/shared/components/tag/tag.component.ts index 350dde0a3a..c77dd93cfb 100644 --- a/src/app/shared/components/tag/tag.component.ts +++ b/src/app/shared/components/tag/tag.component.ts @@ -2,19 +2,19 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; export type TagTypes = 'blue' | 'green' | 'orange' | 'red' | 'yellow' | 'purple'; export const TagType = { - BLUE: 'blue' as TagTypes, - GREEN: 'green' as TagTypes, - ORANGE: 'orange' as TagTypes, - RED: 'red' as TagTypes, - YELLOW: 'yellow' as TagTypes, - PURPLE: 'purple' as TagTypes, + BLUE: 'blue' as TagTypes, + GREEN: 'green' as TagTypes, + ORANGE: 'orange' as TagTypes, + RED: 'red' as TagTypes, + YELLOW: 'yellow' as TagTypes, + PURPLE: 'purple' as TagTypes, }; @Component({ - selector: 'app-tag', - templateUrl: './tag.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-tag', + templateUrl: './tag.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class TagComponent { - @Input() type: string = TagType.BLUE; + @Input() type: string = TagType.BLUE; } diff --git a/src/app/shared/components/test-certificate/test-certificate.component.spec.ts b/src/app/shared/components/test-certificate/test-certificate.component.spec.ts index ac6d76b9b5..9414691733 100644 --- a/src/app/shared/components/test-certificate/test-certificate.component.spec.ts +++ b/src/app/shared/components/test-certificate/test-certificate.component.spec.ts @@ -1,102 +1,114 @@ import { HttpClientTestingModule } from '@angular/common/http/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { DocumentRetrievalService } from '@api/document-retrieval'; +import { TestResultModel } from '@models/test-results/test-result.model'; +import { resultOfTestEnum } from '@models/test-types/test-type.model'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; +import { FeatureToggleService } from '@services/feature-toggle-service/feature-toggle-service'; import { RetrieveDocumentDirective } from '@shared/directives/retrieve-document/retrieve-document.directive'; -import { initialAppState, State } from '@store/index'; +import { State, initialAppState } from '@store/index'; import { isTestTypeOldIvaOrMsva, toEditOrNotToEdit } from '@store/test-records'; -import { resultOfTestEnum } from '@models/test-types/test-type.model'; -import { TestResultModel } from '@models/test-results/test-result.model'; -import { FeatureToggleService } from '@services/feature-toggle-service/feature-toggle-service'; import { TestCertificateComponent } from './test-certificate.component'; describe('TestCertificateComponent', () => { - let component: TestCertificateComponent; - let fixture: ComponentFixture; - let store: MockStore; - let featureToggleService: FeatureToggleService; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [RetrieveDocumentDirective, TestCertificateComponent], - imports: [HttpClientTestingModule], - providers: [DocumentRetrievalService, provideMockStore({ initialState: initialAppState }), FeatureToggleService], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(TestCertificateComponent); - component = fixture.componentInstance; - store = TestBed.inject(MockStore); - featureToggleService = TestBed.inject(FeatureToggleService); - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('ngOnInit', () => { - beforeEach(() => { - jest.spyOn(featureToggleService, 'isFeatureEnabled').mockReturnValue(true); - }); - it('should set certNotNeeded to false if test type is not an iva or msva test', () => { - store.overrideSelector(toEditOrNotToEdit, { testTypes: [{ testResult: resultOfTestEnum.pass, testTypeId: '94' }] } as TestResultModel); - store.overrideSelector(isTestTypeOldIvaOrMsva, false); - component.ngOnInit(); - - expect(component.certNotNeeded).toBe(false); - }); - - it('should set certNotNeeded to true if test type is an old iva or msva test', () => { - store.overrideSelector(toEditOrNotToEdit, { testTypes: [{ testResult: resultOfTestEnum.pass, testTypeId: '125' }] } as TestResultModel); - store.overrideSelector(isTestTypeOldIvaOrMsva, true); - component.ngOnInit(); - - expect(component.certNotNeeded).toBe(true); - }); - - it('should set certNotNeeded to true if test type is an new iva or msva test and the test is a pass', () => { - store.overrideSelector(toEditOrNotToEdit, { testTypes: [{ testResult: resultOfTestEnum.pass, testTypeId: '125' }] } as TestResultModel); - store.overrideSelector(isTestTypeOldIvaOrMsva, false); - component.ngOnInit(); - - expect(component.certNotNeeded).toBe(true); - }); - - it('should set certNotNeeded to true if test type is an new iva or msva test and the test is a prs', () => { - store.overrideSelector(toEditOrNotToEdit, { testTypes: [{ testResult: resultOfTestEnum.prs, testTypeId: '125' }] } as TestResultModel); - store.overrideSelector(isTestTypeOldIvaOrMsva, false); - component.ngOnInit(); - - expect(component.certNotNeeded).toBe(true); - }); - - it('should set certNotNeeded to false if test type is an new iva or msva test and the test is a fail', () => { - store.overrideSelector(toEditOrNotToEdit, { testTypes: [{ testResult: resultOfTestEnum.fail, testTypeId: '125' }] } as TestResultModel); - store.overrideSelector(isTestTypeOldIvaOrMsva, false); - component.ngOnInit(); - - expect(component.certNotNeeded).toBe(false); - }); - - it('should not change certNotNeeded value if no test result is found', () => { - component.certNotNeeded = false; - store.overrideSelector(toEditOrNotToEdit, undefined); - store.overrideSelector(isTestTypeOldIvaOrMsva, true); - component.ngOnInit(); - - expect(component.certNotNeeded).toBe(false); - }); - - it('should not certNotNeeded value if requiredStandards feature is false', () => { - component.certNotNeeded = false; - jest.spyOn(featureToggleService, 'isFeatureEnabled').mockReturnValue(false); - store.overrideSelector(toEditOrNotToEdit, { testTypes: [{ testResult: resultOfTestEnum.pass, testTypeId: '125' }] } as TestResultModel); - store.overrideSelector(isTestTypeOldIvaOrMsva, true); - component.ngOnInit(); - - expect(component.certNotNeeded).toBe(false); - }); - }); + let component: TestCertificateComponent; + let fixture: ComponentFixture; + let store: MockStore; + let featureToggleService: FeatureToggleService; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [RetrieveDocumentDirective, TestCertificateComponent], + imports: [HttpClientTestingModule], + providers: [DocumentRetrievalService, provideMockStore({ initialState: initialAppState }), FeatureToggleService], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(TestCertificateComponent); + component = fixture.componentInstance; + store = TestBed.inject(MockStore); + featureToggleService = TestBed.inject(FeatureToggleService); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('ngOnInit', () => { + beforeEach(() => { + jest.spyOn(featureToggleService, 'isFeatureEnabled').mockReturnValue(true); + }); + it('should set certNotNeeded to false if test type is not an iva or msva test', () => { + store.overrideSelector(toEditOrNotToEdit, { + testTypes: [{ testResult: resultOfTestEnum.pass, testTypeId: '94' }], + } as TestResultModel); + store.overrideSelector(isTestTypeOldIvaOrMsva, false); + component.ngOnInit(); + + expect(component.certNotNeeded).toBe(false); + }); + + it('should set certNotNeeded to true if test type is an old iva or msva test', () => { + store.overrideSelector(toEditOrNotToEdit, { + testTypes: [{ testResult: resultOfTestEnum.pass, testTypeId: '125' }], + } as TestResultModel); + store.overrideSelector(isTestTypeOldIvaOrMsva, true); + component.ngOnInit(); + + expect(component.certNotNeeded).toBe(true); + }); + + it('should set certNotNeeded to true if test type is an new iva or msva test and the test is a pass', () => { + store.overrideSelector(toEditOrNotToEdit, { + testTypes: [{ testResult: resultOfTestEnum.pass, testTypeId: '125' }], + } as TestResultModel); + store.overrideSelector(isTestTypeOldIvaOrMsva, false); + component.ngOnInit(); + + expect(component.certNotNeeded).toBe(true); + }); + + it('should set certNotNeeded to true if test type is an new iva or msva test and the test is a prs', () => { + store.overrideSelector(toEditOrNotToEdit, { + testTypes: [{ testResult: resultOfTestEnum.prs, testTypeId: '125' }], + } as TestResultModel); + store.overrideSelector(isTestTypeOldIvaOrMsva, false); + component.ngOnInit(); + + expect(component.certNotNeeded).toBe(true); + }); + + it('should set certNotNeeded to false if test type is an new iva or msva test and the test is a fail', () => { + store.overrideSelector(toEditOrNotToEdit, { + testTypes: [{ testResult: resultOfTestEnum.fail, testTypeId: '125' }], + } as TestResultModel); + store.overrideSelector(isTestTypeOldIvaOrMsva, false); + component.ngOnInit(); + + expect(component.certNotNeeded).toBe(false); + }); + + it('should not change certNotNeeded value if no test result is found', () => { + component.certNotNeeded = false; + store.overrideSelector(toEditOrNotToEdit, undefined); + store.overrideSelector(isTestTypeOldIvaOrMsva, true); + component.ngOnInit(); + + expect(component.certNotNeeded).toBe(false); + }); + + it('should not certNotNeeded value if requiredStandards feature is false', () => { + component.certNotNeeded = false; + jest.spyOn(featureToggleService, 'isFeatureEnabled').mockReturnValue(false); + store.overrideSelector(toEditOrNotToEdit, { + testTypes: [{ testResult: resultOfTestEnum.pass, testTypeId: '125' }], + } as TestResultModel); + store.overrideSelector(isTestTypeOldIvaOrMsva, true); + component.ngOnInit(); + + expect(component.certNotNeeded).toBe(false); + }); + }); }); diff --git a/src/app/shared/components/test-certificate/test-certificate.component.ts b/src/app/shared/components/test-certificate/test-certificate.component.ts index f9371066a2..add1f5beca 100644 --- a/src/app/shared/components/test-certificate/test-certificate.component.ts +++ b/src/app/shared/components/test-certificate/test-certificate.component.ts @@ -1,60 +1,53 @@ -import { - ChangeDetectionStrategy, Component, inject, Input, OnDestroy, OnInit, -} from '@angular/core'; -import { select, Store } from '@ngrx/store'; -import { isTestTypeOldIvaOrMsva, toEditOrNotToEdit } from '@store/test-records'; -import { - Subject, takeUntil, combineLatest, -} from 'rxjs'; -import { State } from '@store/index'; -import { resultOfTestEnum } from '@models/test-types/test-type.model'; +import { ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit, inject } from '@angular/core'; import { TEST_TYPES_GROUP1_SPEC_TEST, TEST_TYPES_GROUP5_SPEC_TEST } from '@forms/models/testTypeId.enum'; +import { resultOfTestEnum } from '@models/test-types/test-type.model'; +import { Store, select } from '@ngrx/store'; import { FeatureToggleService } from '@services/feature-toggle-service/feature-toggle-service'; +import { State } from '@store/index'; +import { isTestTypeOldIvaOrMsva, toEditOrNotToEdit } from '@store/test-records'; +import { Subject, combineLatest, takeUntil } from 'rxjs'; @Component({ - selector: 'app-test-certificate[testNumber][vin]', - templateUrl: './test-certificate.component.html', - styleUrls: ['./test-certificate.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, + selector: 'app-test-certificate[testNumber][vin]', + templateUrl: './test-certificate.component.html', + styleUrls: ['./test-certificate.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class TestCertificateComponent implements OnInit, OnDestroy { - store: Store = inject(Store); - featureToggleService = inject(FeatureToggleService); - @Input() testNumber!: string; - @Input() vin!: string; - @Input() isClickable = true; - certNotNeeded: boolean = false; - private destroyed$ = new Subject(); + store: Store = inject(Store); + featureToggleService = inject(FeatureToggleService); + @Input() testNumber!: string; + @Input() vin!: string; + @Input() isClickable = true; + certNotNeeded = false; + private destroyed$ = new Subject(); - ngOnInit(): void { - const isRequiredStandardsEnabled = this.featureToggleService.isFeatureEnabled('requiredStandards'); - combineLatest([ - this.store.pipe(select(toEditOrNotToEdit)), - this.store.pipe(select(isTestTypeOldIvaOrMsva)), - ]).pipe( - takeUntil(this.destroyed$), - ).subscribe(([testResult, isOldIvaOrMsva]) => { - if (testResult && isRequiredStandardsEnabled) { - const { testResult: result, testTypeId: id } = testResult.testTypes[0]; - const isIvaOrMsvaTest = TEST_TYPES_GROUP1_SPEC_TEST.includes(id) || TEST_TYPES_GROUP5_SPEC_TEST.includes(id); - this.certNotNeeded = isOldIvaOrMsva || (isIvaOrMsvaTest && result !== resultOfTestEnum.fail); - } - }); - } + ngOnInit(): void { + const isRequiredStandardsEnabled = this.featureToggleService.isFeatureEnabled('requiredStandards'); + combineLatest([this.store.pipe(select(toEditOrNotToEdit)), this.store.pipe(select(isTestTypeOldIvaOrMsva))]) + .pipe(takeUntil(this.destroyed$)) + .subscribe(([testResult, isOldIvaOrMsva]) => { + if (testResult && isRequiredStandardsEnabled) { + const { testResult: result, testTypeId: id } = testResult.testTypes[0]; + const isIvaOrMsvaTest = TEST_TYPES_GROUP1_SPEC_TEST.includes(id) || TEST_TYPES_GROUP5_SPEC_TEST.includes(id); + this.certNotNeeded = isOldIvaOrMsva || (isIvaOrMsvaTest && result !== resultOfTestEnum.fail); + } + }); + } - get documentParams(): Map { - return new Map([ - ['testNumber', this.testNumber], - ['vinNumber', this.vin], - ]); - } + get documentParams(): Map { + return new Map([ + ['testNumber', this.testNumber], + ['vinNumber', this.vin], + ]); + } - get fileName(): string { - return `${this.testNumber}_${this.vin}`; - } + get fileName(): string { + return `${this.testNumber}_${this.vin}`; + } - ngOnDestroy(): void { - this.destroyed$.next(); - this.destroyed$.complete(); - } + ngOnDestroy(): void { + this.destroyed$.next(); + this.destroyed$.complete(); + } } diff --git a/src/app/shared/custom-module/fixNgZoneError.ts b/src/app/shared/custom-module/fixNgZoneError.ts index 437da7e5cc..1f6e9e5ce3 100644 --- a/src/app/shared/custom-module/fixNgZoneError.ts +++ b/src/app/shared/custom-module/fixNgZoneError.ts @@ -8,6 +8,6 @@ import { Router } from '@angular/router'; */ @NgModule() export class FixNavigationTriggeredOutsideAngularZoneNgModule { - // eslint-disable-next-line @typescript-eslint/no-useless-constructor, @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars - constructor(_router: Router) { } + // eslint-disable-next-line @typescript-eslint/no-useless-constructor, @typescript-eslint/no-empty-function, @typescript-eslint/no-unused-vars + constructor(_router: Router) {} } diff --git a/src/app/shared/directives/prevent-double-click/prevent-double-click.directive.spec.ts b/src/app/shared/directives/prevent-double-click/prevent-double-click.directive.spec.ts index 37ab08dde9..d15bbc3b07 100644 --- a/src/app/shared/directives/prevent-double-click/prevent-double-click.directive.spec.ts +++ b/src/app/shared/directives/prevent-double-click/prevent-double-click.directive.spec.ts @@ -4,55 +4,55 @@ import { By } from '@angular/platform-browser'; import { PreventDoubleClickDirective } from './prevent-double-click.directive'; @Component({ - selector: 'app-host', - template: '', + selector: 'app-host', + template: '', }) class HostComponent { - clicked = new EventEmitter(); + clicked = new EventEmitter(); } describe('PreventDoubleClickDirective', () => { - let component: HostComponent; - let fixture: ComponentFixture; + let component: HostComponent; + let fixture: ComponentFixture; - beforeEach(waitForAsync(async () => { - await TestBed.configureTestingModule({ - declarations: [HostComponent, PreventDoubleClickDirective], - }).compileComponents(); - })); + beforeEach(waitForAsync(async () => { + await TestBed.configureTestingModule({ + declarations: [HostComponent, PreventDoubleClickDirective], + }).compileComponents(); + })); - beforeEach(() => { - fixture = TestBed.createComponent(HostComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); + beforeEach(() => { + fixture = TestBed.createComponent(HostComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); - it('should emit clicked once', () => { - const emitSpy = jest.spyOn(component.clicked, 'emit'); - const button: HTMLButtonElement = fixture.debugElement.query(By.css('button')).nativeElement; + it('should emit clicked once', () => { + const emitSpy = jest.spyOn(component.clicked, 'emit'); + const button: HTMLButtonElement = fixture.debugElement.query(By.css('button')).nativeElement; - button.click(); - button.click(); + button.click(); + button.click(); - expect(emitSpy).toHaveBeenCalledTimes(1); - }); + expect(emitSpy).toHaveBeenCalledTimes(1); + }); - it('should emit clicked twice', async () => { - const emitSpy = jest.spyOn(component.clicked, 'emit'); - const button: HTMLButtonElement = fixture.debugElement.query(By.css('button')).nativeElement; + it('should emit clicked twice', async () => { + const emitSpy = jest.spyOn(component.clicked, 'emit'); + const button: HTMLButtonElement = fixture.debugElement.query(By.css('button')).nativeElement; - button.click(); + button.click(); - await new Promise((resolve) => { - const wait = setTimeout(() => { - clearTimeout(wait); - button.click(); - resolve(); - }, 1001); - }); + await new Promise((resolve) => { + const wait = setTimeout(() => { + clearTimeout(wait); + button.click(); + resolve(); + }, 1001); + }); - button.click(); + button.click(); - expect(emitSpy).toHaveBeenCalledTimes(2); - }); + expect(emitSpy).toHaveBeenCalledTimes(2); + }); }); diff --git a/src/app/shared/directives/prevent-double-click/prevent-double-click.directive.ts b/src/app/shared/directives/prevent-double-click/prevent-double-click.directive.ts index b399a3a587..349d8eff07 100644 --- a/src/app/shared/directives/prevent-double-click/prevent-double-click.directive.ts +++ b/src/app/shared/directives/prevent-double-click/prevent-double-click.directive.ts @@ -1,37 +1,37 @@ -import { - Directive, EventEmitter, HostListener, Input, OnDestroy, Output, -} from '@angular/core'; +import { Directive, EventEmitter, HostListener, Input, OnDestroy, Output } from '@angular/core'; import { Subject, Subscription, throttleTime } from 'rxjs'; @Directive({ - selector: '[appPreventDoubleClick]', + selector: '[appPreventDoubleClick]', }) export class PreventDoubleClickDirective implements OnDestroy { - @Input() - throttleTime = 1000; + @Input() + throttleTime = 1000; - @Output() - clicked = new EventEmitter(); + @Output() + clicked = new EventEmitter(); - private clicks = new Subject(); - private subscription: Subscription; + private clicks = new Subject(); + private subscription: Subscription; - constructor() { - this.subscription = this.clicks.pipe(throttleTime(this.throttleTime)).subscribe((e: PointerEvent) => this.emitThrottledClick(e)); - } + constructor() { + this.subscription = this.clicks + .pipe(throttleTime(this.throttleTime)) + .subscribe((e: PointerEvent) => this.emitThrottledClick(e)); + } - emitThrottledClick(e: PointerEvent) { - this.clicked.emit(e); - } + emitThrottledClick(e: PointerEvent) { + this.clicked.emit(e); + } - ngOnDestroy() { - this.subscription.unsubscribe(); - } + ngOnDestroy() { + this.subscription.unsubscribe(); + } - @HostListener('click', ['$event']) - clickEvent(event: PointerEvent) { - event.preventDefault(); - event.stopPropagation(); - this.clicks.next(event); - } + @HostListener('click', ['$event']) + clickEvent(event: PointerEvent) { + event.preventDefault(); + event.stopPropagation(); + this.clicks.next(event); + } } diff --git a/src/app/shared/directives/retrieve-document/retrieve-document.directive.spec.ts b/src/app/shared/directives/retrieve-document/retrieve-document.directive.spec.ts index a9984cc35d..49f42f393c 100644 --- a/src/app/shared/directives/retrieve-document/retrieve-document.directive.spec.ts +++ b/src/app/shared/directives/retrieve-document/retrieve-document.directive.spec.ts @@ -7,24 +7,18 @@ import { State, initialAppState } from '@store/index'; import { RetrieveDocumentDirective } from './retrieve-document.directive'; describe('RetrieveDocumentDirective', () => { - let store: MockStore; - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [ - provideMockStore({ initialState: initialAppState }), - ], - }); - }); - it('should create an instance', () => { - const directive = new RetrieveDocumentDirective( - new DocumentRetrievalService( - {} as HttpClient, - '', - new Configuration(), - ), - new DocumentsService(), - store, - ); - expect(directive).toBeTruthy(); - }); + let store: MockStore; + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideMockStore({ initialState: initialAppState })], + }); + }); + it('should create an instance', () => { + const directive = new RetrieveDocumentDirective( + new DocumentRetrievalService({} as HttpClient, '', new Configuration()), + new DocumentsService(), + store + ); + expect(directive).toBeTruthy(); + }); }); diff --git a/src/app/shared/directives/retrieve-document/retrieve-document.directive.ts b/src/app/shared/directives/retrieve-document/retrieve-document.directive.ts index 67222eff74..6e6252f61a 100644 --- a/src/app/shared/directives/retrieve-document/retrieve-document.directive.ts +++ b/src/app/shared/directives/retrieve-document/retrieve-document.directive.ts @@ -9,37 +9,41 @@ import { takeWhile } from 'rxjs'; @Directive({ selector: '[appRetrieveDocument][params][fileName]' }) export class RetrieveDocumentDirective { - @Input() params: Map = new Map(); - @Input() fileName = ''; - @Input() loading?: Boolean; - @Input() certNotNeeded: boolean = false; - @Input() fileType: string = 'pdf'; + @Input() params: Map = new Map(); + @Input() fileName = ''; + @Input() loading?: boolean; + @Input() certNotNeeded = false; + @Input() fileType = 'pdf'; - constructor(private documentRetrievalService: DocumentRetrievalService, private documentsService: DocumentsService, private store: Store) { } + constructor( + private documentRetrievalService: DocumentRetrievalService, + private documentsService: DocumentsService, + private store: Store + ) {} - @HostListener('click', ['$event']) clickEvent(event: PointerEvent) { - if (this.certNotNeeded) return; - event.preventDefault(); - event.stopPropagation(); + @HostListener('click', ['$event']) clickEvent(event: PointerEvent) { + if (this.certNotNeeded) return; + event.preventDefault(); + event.stopPropagation(); - if (this.loading) { - this.store.dispatch(setSpinnerState({ showSpinner: true })); - } + if (this.loading) { + this.store.dispatch(setSpinnerState({ showSpinner: true })); + } - this.documentRetrievalService - .getDocument(this.params) - .pipe(takeWhile((doc) => doc.type !== HttpEventType.Response, true)) - .subscribe((response) => { - switch (response.type) { - case HttpEventType.DownloadProgress: - break; - case HttpEventType.Response: - this.documentsService.openDocumentFromResponse(this.fileName, response.body, this.fileType); - this.store.dispatch(setSpinnerState({ showSpinner: false })); - break; - default: - break; - } - }); - } + this.documentRetrievalService + .getDocument(this.params) + .pipe(takeWhile((doc) => doc.type !== HttpEventType.Response, true)) + .subscribe((response) => { + switch (response.type) { + case HttpEventType.DownloadProgress: + break; + case HttpEventType.Response: + this.documentsService.openDocumentFromResponse(this.fileName, response.body, this.fileType); + this.store.dispatch(setSpinnerState({ showSpinner: false })); + break; + default: + break; + } + }); + } } diff --git a/src/app/shared/pipes/default-null-or-empty/default-null-or-empty.pipe.spec.ts b/src/app/shared/pipes/default-null-or-empty/default-null-or-empty.pipe.spec.ts index 74ec2a5924..cfad598ce8 100644 --- a/src/app/shared/pipes/default-null-or-empty/default-null-or-empty.pipe.spec.ts +++ b/src/app/shared/pipes/default-null-or-empty/default-null-or-empty.pipe.spec.ts @@ -1,40 +1,40 @@ import { DefaultNullOrEmpty } from './default-null-or-empty.pipe'; describe('DefaultNullOrEmpty pipe tests', () => { - // This pipe is a pure, stateless function so no need for BeforeEach - const pipe = new DefaultNullOrEmpty(); - - it('transforms null to "-"', () => { - expect(pipe.transform(null)).toBe('-'); - }); - - it('transforms "" to "-"', () => { - expect(pipe.transform('')).toBe('-'); - }); - - it('transforms " " to "-"', () => { - expect(pipe.transform(' ')).toBe('-'); - }); - - it('transforms boolean "true" to "Yes"', () => { - expect(pipe.transform(true)).toBe('Yes'); - }); - - it('transforms boolean "false" to "No"', () => { - expect(pipe.transform(false)).toBe('No'); - }); - - it('otherwise returns the string value unchanged', () => { - expect(pipe.transform('This is OK')).toBe('This is OK'); - }); - - it('otherwise returns the date value unchanged', () => { - const val = new Date(); - expect(pipe.transform(val)).toBe(val); - }); - - it('should capitalise the first character of a string', () => { - const val = 'lowercase string'; - expect(pipe.transform(val)).toBe('Lowercase string'); - }); + // This pipe is a pure, stateless function so no need for BeforeEach + const pipe = new DefaultNullOrEmpty(); + + it('transforms null to "-"', () => { + expect(pipe.transform(null)).toBe('-'); + }); + + it('transforms "" to "-"', () => { + expect(pipe.transform('')).toBe('-'); + }); + + it('transforms " " to "-"', () => { + expect(pipe.transform(' ')).toBe('-'); + }); + + it('transforms boolean "true" to "Yes"', () => { + expect(pipe.transform(true)).toBe('Yes'); + }); + + it('transforms boolean "false" to "No"', () => { + expect(pipe.transform(false)).toBe('No'); + }); + + it('otherwise returns the string value unchanged', () => { + expect(pipe.transform('This is OK')).toBe('This is OK'); + }); + + it('otherwise returns the date value unchanged', () => { + const val = new Date(); + expect(pipe.transform(val)).toBe(val); + }); + + it('should capitalise the first character of a string', () => { + const val = 'lowercase string'; + expect(pipe.transform(val)).toBe('Lowercase string'); + }); }); diff --git a/src/app/shared/pipes/default-null-or-empty/default-null-or-empty.pipe.ts b/src/app/shared/pipes/default-null-or-empty/default-null-or-empty.pipe.ts index a7b53d3d7b..8c4b8e4bd6 100644 --- a/src/app/shared/pipes/default-null-or-empty/default-null-or-empty.pipe.ts +++ b/src/app/shared/pipes/default-null-or-empty/default-null-or-empty.pipe.ts @@ -2,24 +2,24 @@ import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'defaultNullOrEmpty' }) export class DefaultNullOrEmpty implements PipeTransform { - titleCaseFirstWord(value: string) { - return value[0].toUpperCase() + value.substring(1); - } + titleCaseFirstWord(value: string) { + return value[0].toUpperCase() + value.substring(1); + } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - transform(value: any) { - if (typeof value === 'string') { - if (value.toLowerCase() === 'true') { - return 'Yes'; - } - if (value.toLowerCase() === 'false') { - return 'No'; - } - return value.trim().length > 0 ? this.titleCaseFirstWord(value) : '-'; - } - if (typeof value === 'boolean') { - return value ? 'Yes' : 'No'; - } - return value == null ? '-' : value; - } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + transform(value: any) { + if (typeof value === 'string') { + if (value.toLowerCase() === 'true') { + return 'Yes'; + } + if (value.toLowerCase() === 'false') { + return 'No'; + } + return value.trim().length > 0 ? this.titleCaseFirstWord(value) : '-'; + } + if (typeof value === 'boolean') { + return value ? 'Yes' : 'No'; + } + return value == null ? '-' : value; + } } diff --git a/src/app/shared/pipes/digit-group-separator/digit-group-separator.pipe.spec.ts b/src/app/shared/pipes/digit-group-separator/digit-group-separator.pipe.spec.ts index 4a5bcf1802..836ff6cfa9 100644 --- a/src/app/shared/pipes/digit-group-separator/digit-group-separator.pipe.spec.ts +++ b/src/app/shared/pipes/digit-group-separator/digit-group-separator.pipe.spec.ts @@ -1,22 +1,22 @@ import { DigitGroupSeparatorPipe } from './digit-group-separator.pipe'; describe('digitGroupSeparator pipe tests', () => { - // This pipe is a pure, stateless function so no need for BeforeEach - const pipe = new DigitGroupSeparatorPipe(); + // This pipe is a pure, stateless function so no need for BeforeEach + const pipe = new DigitGroupSeparatorPipe(); - it('returns undefined', () => { - expect(pipe.transform(undefined)).toBeUndefined(); - }); + it('returns undefined', () => { + expect(pipe.transform(undefined)).toBeUndefined(); + }); - it('does not separate number', () => { - expect(pipe.transform(10)).toBe('10'); - }); + it('does not separate number', () => { + expect(pipe.transform(10)).toBe('10'); + }); - it('transforms 1000 to "1,000"', () => { - expect(pipe.transform(1000)).toBe('1,000'); - }); + it('transforms 1000 to "1,000"', () => { + expect(pipe.transform(1000)).toBe('1,000'); + }); - it('transforms 1000000 to "1,000,000"', () => { - expect(pipe.transform(1000000)).toBe('1,000,000'); - }); + it('transforms 1000000 to "1,000,000"', () => { + expect(pipe.transform(1000000)).toBe('1,000,000'); + }); }); diff --git a/src/app/shared/pipes/digit-group-separator/digit-group-separator.pipe.ts b/src/app/shared/pipes/digit-group-separator/digit-group-separator.pipe.ts index 8bedcae373..3936498556 100644 --- a/src/app/shared/pipes/digit-group-separator/digit-group-separator.pipe.ts +++ b/src/app/shared/pipes/digit-group-separator/digit-group-separator.pipe.ts @@ -1,13 +1,13 @@ import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ - name: 'digitGroupSeparator', + name: 'digitGroupSeparator', }) export class DigitGroupSeparatorPipe implements PipeTransform { - transform(value: number | undefined): string | undefined { - if (value) { - return value.toLocaleString(); - } - return undefined; - } + transform(value: number | undefined): string | undefined { + if (value) { + return value.toLocaleString(); + } + return undefined; + } } diff --git a/src/app/shared/pipes/format-vehicle-type/format-vehicle-type.pipe.spec.ts b/src/app/shared/pipes/format-vehicle-type/format-vehicle-type.pipe.spec.ts index 794fc3473f..430b3b6965 100644 --- a/src/app/shared/pipes/format-vehicle-type/format-vehicle-type.pipe.spec.ts +++ b/src/app/shared/pipes/format-vehicle-type/format-vehicle-type.pipe.spec.ts @@ -2,24 +2,24 @@ import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { FormatVehicleTypePipe } from './format-vehicle-type.pipe'; describe('FormatVehicleTypePipe', () => { - it('create an instance', () => { - const pipe = new FormatVehicleTypePipe(); - expect(pipe).toBeTruthy(); - }); + it('create an instance', () => { + const pipe = new FormatVehicleTypePipe(); + expect(pipe).toBeTruthy(); + }); - describe('transform the values', () => { - const pipe = new FormatVehicleTypePipe(); + describe('transform the values', () => { + const pipe = new FormatVehicleTypePipe(); - it('should return trailer if value is trl', () => { - expect(pipe.transform(VehicleTypes.TRL)).toBe('trailer'); - }); + it('should return trailer if value is trl', () => { + expect(pipe.transform(VehicleTypes.TRL)).toBe('trailer'); + }); - it('should return HGV if value is hgv', () => { - expect(pipe.transform(VehicleTypes.HGV)).toBe('HGV'); - }); + it('should return HGV if value is hgv', () => { + expect(pipe.transform(VehicleTypes.HGV)).toBe('HGV'); + }); - it('should return undefined if value is undefined', () => { - expect(pipe.transform(undefined)).toBeUndefined(); - }); - }); + it('should return undefined if value is undefined', () => { + expect(pipe.transform(undefined)).toBeUndefined(); + }); + }); }); diff --git a/src/app/shared/pipes/format-vehicle-type/format-vehicle-type.pipe.ts b/src/app/shared/pipes/format-vehicle-type/format-vehicle-type.pipe.ts index 6b994b5e7e..aaadfda17e 100644 --- a/src/app/shared/pipes/format-vehicle-type/format-vehicle-type.pipe.ts +++ b/src/app/shared/pipes/format-vehicle-type/format-vehicle-type.pipe.ts @@ -2,15 +2,15 @@ import { Pipe, PipeTransform } from '@angular/core'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; @Pipe({ - name: 'formatVehicleType', + name: 'formatVehicleType', }) export class FormatVehicleTypePipe implements PipeTransform { - transform(value: VehicleTypes | undefined | null): unknown { - switch (value) { - case VehicleTypes.TRL: - return 'trailer'; - default: - return value?.toUpperCase(); - } - } + transform(value: VehicleTypes | undefined | null): unknown { + switch (value) { + case VehicleTypes.TRL: + return 'trailer'; + default: + return value?.toUpperCase(); + } + } } diff --git a/src/app/shared/pipes/get-control-label/get-control-label.pipe.spec.ts b/src/app/shared/pipes/get-control-label/get-control-label.pipe.spec.ts index 3b71d23ae7..1740b4b00f 100644 --- a/src/app/shared/pipes/get-control-label/get-control-label.pipe.spec.ts +++ b/src/app/shared/pipes/get-control-label/get-control-label.pipe.spec.ts @@ -2,27 +2,27 @@ import { FormNodeOption } from '@forms/services/dynamic-form.types'; import { GetControlLabelPipe } from './get-control-label.pipe'; describe('GetControlLabelPipe', () => { - let testOptions: FormNodeOption[]; + let testOptions: FormNodeOption[]; - beforeEach(() => { - testOptions = [ - { label: 'Test', value: 'test' }, - { label: 'Foo', value: 'bar' }, - ]; - }); + beforeEach(() => { + testOptions = [ + { label: 'Test', value: 'test' }, + { label: 'Foo', value: 'bar' }, + ]; + }); - it('create an instance', () => { - const pipe = new GetControlLabelPipe(); - expect(pipe).toBeTruthy(); - }); + it('create an instance', () => { + const pipe = new GetControlLabelPipe(); + expect(pipe).toBeTruthy(); + }); - it('should return the label if one is available', () => { - const pipe = new GetControlLabelPipe(); - expect(pipe.transform('test', testOptions)).toBe('Test'); - }); + it('should return the label if one is available', () => { + const pipe = new GetControlLabelPipe(); + expect(pipe.transform('test', testOptions)).toBe('Test'); + }); - it('should return the value if no label is available', () => { - const pipe = new GetControlLabelPipe(); - expect(pipe.transform('foo', testOptions)).toBe('foo'); - }); + it('should return the value if no label is available', () => { + const pipe = new GetControlLabelPipe(); + expect(pipe.transform('foo', testOptions)).toBe('foo'); + }); }); diff --git a/src/app/shared/pipes/get-control-label/get-control-label.pipe.ts b/src/app/shared/pipes/get-control-label/get-control-label.pipe.ts index d4af9ecc31..f3001aa8f5 100644 --- a/src/app/shared/pipes/get-control-label/get-control-label.pipe.ts +++ b/src/app/shared/pipes/get-control-label/get-control-label.pipe.ts @@ -2,13 +2,13 @@ import { Pipe, PipeTransform } from '@angular/core'; import { FormNodeCombinationOptions, FormNodeOption } from '@forms/services/dynamic-form.types'; @Pipe({ - name: 'getControlLabel', + name: 'getControlLabel', }) export class GetControlLabelPipe implements PipeTransform { - transform( - value: string | number | null | undefined, - options?: FormNodeOption[] | FormNodeCombinationOptions | undefined, - ): string | number | null | undefined { - return (Array.isArray(options) && options?.find((option) => option.value === value)?.label) || value; - } + transform( + value: string | number | null | undefined, + options?: FormNodeOption[] | FormNodeCombinationOptions | undefined + ): string | number | null | undefined { + return (Array.isArray(options) && options?.find((option) => option.value === value)?.label) || value; + } } diff --git a/src/app/shared/pipes/ref-data-decode/ref-data-decode.pipe.spec.ts b/src/app/shared/pipes/ref-data-decode/ref-data-decode.pipe.spec.ts index 4e1e042b24..c632e88af4 100644 --- a/src/app/shared/pipes/ref-data-decode/ref-data-decode.pipe.spec.ts +++ b/src/app/shared/pipes/ref-data-decode/ref-data-decode.pipe.spec.ts @@ -7,130 +7,130 @@ import { STORE_FEATURE_REFERENCE_DATA_KEY, initialReferenceDataState } from '@st import { RefDataDecodePipe } from './ref-data-decode.pipe'; describe('RefDataDecodePipe', () => { - let store: MockStore; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [BrowserModule], - providers: [provideMockStore({ initialState: initialAppState })], - }); - - store = TestBed.inject(MockStore); - - store.setState({ - ...initialAppState, - [STORE_FEATURE_REFERENCE_DATA_KEY]: { - ...initialReferenceDataState, - [ReferenceDataResourceType.CountryOfRegistration]: { - ids: ['gb'], - entities: { - gb: { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'gb', - description: 'Great Britain', - }, - }, - loading: false, - }, - [(`${ReferenceDataResourceType.CountryOfRegistration}#AUDIT`) as ReferenceDataResourceType]: { - searchReturn: [ - { - resourceType: (`${ReferenceDataResourceType.CountryOfRegistration}#AUDIT`) as ReferenceDataResourceType, - resourceKey: 'a', - description: 'Austria', - }, - ], - loading: false, - }, - [ReferenceDataResourceType.Tyres]: { - ids: ['101'], - entities: { - 101: { - resourceType: ReferenceDataResourceType.Tyres, - resourceKey: '101', - tyreSize: '235/75-17.5', - } as ReferenceDataTyre, - }, - loading: false, - }, - }, - }); - }); - - afterEach(() => { - jest.clearAllMocks(); - store.refreshState(); - }); - - it('should return description', (done) => { - const pipe = new RefDataDecodePipe(store); - - pipe.transform('gb', ReferenceDataResourceType.CountryOfRegistration).subscribe((val) => { - expect(val).toBe('Great Britain'); - done(); - }); - }); - - it('should return description of deleted item', (done) => { - const pipe = new RefDataDecodePipe(store); - - pipe.transform('a', ReferenceDataResourceType.CountryOfRegistration).subscribe((val) => { - expect(val).toBe('Austria'); - done(); - }); - }); - - it('should return tyreSize', (done) => { - const pipe = new RefDataDecodePipe(store); - - pipe.transform('101', ReferenceDataResourceType.Tyres, 'tyreSize').subscribe((val) => { - expect(val).toBe('235/75-17.5'); - done(); - }); - }); - - it('should return untransformed value when description is undefined', (done) => { - const pipe = new RefDataDecodePipe(store); - - pipe.transform('101', ReferenceDataResourceType.Tyres).subscribe((val) => { - expect(val).toBe('101'); - done(); - }); - }); - - it('should return untransformed value when value is not a known resourceKey', (done) => { - const pipe = new RefDataDecodePipe(store); - - pipe.transform('foo', ReferenceDataResourceType.Tyres, 'tyreSize').subscribe((val) => { - expect(val).toBe('foo'); - done(); - }); - }); - - it('should return untransformed value when value is falsy', (done) => { - const pipe = new RefDataDecodePipe(store); - - pipe.transform('', ReferenceDataResourceType.Tyres, 'tyreSize').subscribe((val) => { - expect(val).toBe(''); - done(); - }); - }); - - it('should return untransformed value when resourceType is falsy', (done) => { - const pipe = new RefDataDecodePipe(store); - - pipe.transform('101', '', 'tyreSize').subscribe((val) => { - expect(val).toBe('101'); - done(); - }); - }); - - it('should return untransformed value when data not in state', (done) => { - const pipe = new RefDataDecodePipe(store); - - pipe.transform('bar', 'baz').subscribe((val) => { - expect(val).toBe('bar'); - done(); - }); - }); + let store: MockStore; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [BrowserModule], + providers: [provideMockStore({ initialState: initialAppState })], + }); + + store = TestBed.inject(MockStore); + + store.setState({ + ...initialAppState, + [STORE_FEATURE_REFERENCE_DATA_KEY]: { + ...initialReferenceDataState, + [ReferenceDataResourceType.CountryOfRegistration]: { + ids: ['gb'], + entities: { + gb: { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'gb', + description: 'Great Britain', + }, + }, + loading: false, + }, + [`${ReferenceDataResourceType.CountryOfRegistration}#AUDIT` as ReferenceDataResourceType]: { + searchReturn: [ + { + resourceType: `${ReferenceDataResourceType.CountryOfRegistration}#AUDIT` as ReferenceDataResourceType, + resourceKey: 'a', + description: 'Austria', + }, + ], + loading: false, + }, + [ReferenceDataResourceType.Tyres]: { + ids: ['101'], + entities: { + 101: { + resourceType: ReferenceDataResourceType.Tyres, + resourceKey: '101', + tyreSize: '235/75-17.5', + } as ReferenceDataTyre, + }, + loading: false, + }, + }, + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + store.refreshState(); + }); + + it('should return description', (done) => { + const pipe = new RefDataDecodePipe(store); + + pipe.transform('gb', ReferenceDataResourceType.CountryOfRegistration).subscribe((val) => { + expect(val).toBe('Great Britain'); + done(); + }); + }); + + it('should return description of deleted item', (done) => { + const pipe = new RefDataDecodePipe(store); + + pipe.transform('a', ReferenceDataResourceType.CountryOfRegistration).subscribe((val) => { + expect(val).toBe('Austria'); + done(); + }); + }); + + it('should return tyreSize', (done) => { + const pipe = new RefDataDecodePipe(store); + + pipe.transform('101', ReferenceDataResourceType.Tyres, 'tyreSize').subscribe((val) => { + expect(val).toBe('235/75-17.5'); + done(); + }); + }); + + it('should return untransformed value when description is undefined', (done) => { + const pipe = new RefDataDecodePipe(store); + + pipe.transform('101', ReferenceDataResourceType.Tyres).subscribe((val) => { + expect(val).toBe('101'); + done(); + }); + }); + + it('should return untransformed value when value is not a known resourceKey', (done) => { + const pipe = new RefDataDecodePipe(store); + + pipe.transform('foo', ReferenceDataResourceType.Tyres, 'tyreSize').subscribe((val) => { + expect(val).toBe('foo'); + done(); + }); + }); + + it('should return untransformed value when value is falsy', (done) => { + const pipe = new RefDataDecodePipe(store); + + pipe.transform('', ReferenceDataResourceType.Tyres, 'tyreSize').subscribe((val) => { + expect(val).toBe(''); + done(); + }); + }); + + it('should return untransformed value when resourceType is falsy', (done) => { + const pipe = new RefDataDecodePipe(store); + + pipe.transform('101', '', 'tyreSize').subscribe((val) => { + expect(val).toBe('101'); + done(); + }); + }); + + it('should return untransformed value when data not in state', (done) => { + const pipe = new RefDataDecodePipe(store); + + pipe.transform('bar', 'baz').subscribe((val) => { + expect(val).toBe('bar'); + done(); + }); + }); }); diff --git a/src/app/shared/pipes/ref-data-decode/ref-data-decode.pipe.ts b/src/app/shared/pipes/ref-data-decode/ref-data-decode.pipe.ts index d561cbafb1..9e972bb656 100644 --- a/src/app/shared/pipes/ref-data-decode/ref-data-decode.pipe.ts +++ b/src/app/shared/pipes/ref-data-decode/ref-data-decode.pipe.ts @@ -1,83 +1,89 @@ import { OnDestroy, Pipe, PipeTransform } from '@angular/core'; import { SpecialRefData } from '@forms/services/multi-options.service'; -import { ReferenceDataModelBase, ReferenceDataResourceType, ReferenceDataResourceTypeAudit } from '@models/reference-data.model'; +import { + ReferenceDataModelBase, + ReferenceDataResourceType, + ReferenceDataResourceTypeAudit, +} from '@models/reference-data.model'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { Store } from '@ngrx/store'; import { State } from '@store/index'; import { - fetchReferenceData, fetchReferenceDataByKeySearch, selectReferenceDataByResourceKey, selectSearchReturn, + fetchReferenceData, + fetchReferenceDataByKeySearch, + selectReferenceDataByResourceKey, + selectSearchReturn, } from '@store/reference-data'; import { getSingleVehicleType } from '@store/technical-records'; -import { - Observable, Subject, - asapScheduler, - combineLatest, map, of, take, -} from 'rxjs'; +import { Observable, Subject, asapScheduler, combineLatest, map, of, take } from 'rxjs'; @Pipe({ - name: 'refDataDecode$', + name: 'refDataDecode$', }) export class RefDataDecodePipe implements PipeTransform, OnDestroy { - constructor(private store: Store) {} + constructor(private store: Store) {} - private destroy$ = new Subject(); + private destroy$ = new Subject(); - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } - transform( - value: string | number | undefined, - resourceType: string | undefined, - decodeKey: string | number = 'description', - ): Observable { - if (!resourceType || !value) { - return of(value); - } + transform( + value: string | number | undefined, + resourceType: string | undefined, + decodeKey: string | number = 'description' + ): Observable { + if (!resourceType || !value) { + return of(value); + } - if (resourceType === SpecialRefData.ReasonsForAbandoning) { - this.store - .select(getSingleVehicleType) - .pipe(take(1)) - .subscribe((vehicleType) => { - switch (vehicleType) { - case VehicleTypes.HGV: - resourceType = ReferenceDataResourceType.ReasonsForAbandoningHgv; - break; - case VehicleTypes.PSV: - resourceType = ReferenceDataResourceType.ReasonsForAbandoningPsv; - break; - case VehicleTypes.TRL: - resourceType = ReferenceDataResourceType.ReasonsForAbandoningTrl; - break; - default: - resourceType = ReferenceDataResourceType.ReasonsForAbandoningHgv; - break; - } - }); - } + if (resourceType === SpecialRefData.ReasonsForAbandoning) { + this.store + .select(getSingleVehicleType) + .pipe(take(1)) + .subscribe((vehicleType) => { + switch (vehicleType) { + case VehicleTypes.HGV: + resourceType = ReferenceDataResourceType.ReasonsForAbandoningHgv; + break; + case VehicleTypes.PSV: + resourceType = ReferenceDataResourceType.ReasonsForAbandoningPsv; + break; + case VehicleTypes.TRL: + resourceType = ReferenceDataResourceType.ReasonsForAbandoningTrl; + break; + default: + resourceType = ReferenceDataResourceType.ReasonsForAbandoningHgv; + break; + } + }); + } - asapScheduler.schedule(() => { - this.store.dispatch(fetchReferenceData({ resourceType: resourceType as ReferenceDataResourceType })); - }); + asapScheduler.schedule(() => { + this.store.dispatch(fetchReferenceData({ resourceType: resourceType as ReferenceDataResourceType })); + }); - asapScheduler.schedule(() => { - this.store.dispatch( - fetchReferenceDataByKeySearch({ resourceType: (`${resourceType}#AUDIT`) as ReferenceDataResourceType, resourceKey: `${value}#` }), - ); - }); + asapScheduler.schedule(() => { + this.store.dispatch( + fetchReferenceDataByKeySearch({ + resourceType: `${resourceType}#AUDIT` as ReferenceDataResourceType, + resourceKey: `${value}#`, + }) + ); + }); - return combineLatest([ - this.store.select(selectReferenceDataByResourceKey(resourceType as ReferenceDataResourceType, value)), - this.store.select(selectSearchReturn((`${resourceType}#AUDIT`) as ReferenceDataResourceTypeAudit)), - ]).pipe( - map(([refDataItem, refDataItemAudit]) => { - if (!refDataItem) { - return refDataItemAudit?.[0].description ?? value; - } - return refDataItem[decodeKey as keyof ReferenceDataModelBase] ?? value; - }), - ); - } + return combineLatest([ + this.store.select(selectReferenceDataByResourceKey(resourceType as ReferenceDataResourceType, value)), + this.store.select(selectSearchReturn(`${resourceType}#AUDIT` as ReferenceDataResourceTypeAudit)), + ]).pipe( + map(([refDataItem, refDataItemAudit]) => { + if (!refDataItem) { + return refDataItemAudit?.[0].description ?? value; + } + return refDataItem[decodeKey as keyof ReferenceDataModelBase] ?? value; + }) + ); + } } diff --git a/src/app/shared/pipes/test-type-name/test-type-name.pipe.spec.ts b/src/app/shared/pipes/test-type-name/test-type-name.pipe.spec.ts index 1e4c726c09..1e0efd40ac 100644 --- a/src/app/shared/pipes/test-type-name/test-type-name.pipe.spec.ts +++ b/src/app/shared/pipes/test-type-name/test-type-name.pipe.spec.ts @@ -2,45 +2,45 @@ import { TestTypesTaxonomy } from '@api/test-types'; import { TestTypeNamePipe } from './test-type-name.pipe'; const testTypes = [ - { - id: '1', - suggestedTestTypeDisplayName: 'Test Type Display Name 1', - }, - { - id: '2', - testTypeName: 'Test Type Name 2', - }, - { - id: '3', - nextTestTypesOrCategories: [ - { - id: '4', - name: 'Test Name 4', - nextTestTypesOrCategories: [ - { - id: '5', - name: 'Test Name 5', - }, - ], - }, - ], - }, + { + id: '1', + suggestedTestTypeDisplayName: 'Test Type Display Name 1', + }, + { + id: '2', + testTypeName: 'Test Type Name 2', + }, + { + id: '3', + nextTestTypesOrCategories: [ + { + id: '4', + name: 'Test Name 4', + nextTestTypesOrCategories: [ + { + id: '5', + name: 'Test Name 5', + }, + ], + }, + ], + }, ] as TestTypesTaxonomy; describe('TestTypeNamePipe', () => { - it('create an instance', () => { - const pipe = new TestTypeNamePipe(); - expect(pipe).toBeTruthy(); - }); + it('create an instance', () => { + const pipe = new TestTypeNamePipe(); + expect(pipe).toBeTruthy(); + }); - it.each([ - ['Test Name 5', '5'], - ['Test Name 4', '4'], - ['-', '3'], - ['Test Type Name 2', '2'], - ['Test Type Display Name 1', '1'], - ])('should %s for id: %s', (expected: string, id: string) => { - const pipe = new TestTypeNamePipe(); - expect(pipe.transform(id, testTypes)).toBe(expected); - }); + it.each([ + ['Test Name 5', '5'], + ['Test Name 4', '4'], + ['-', '3'], + ['Test Type Name 2', '2'], + ['Test Type Display Name 1', '1'], + ])('should %s for id: %s', (expected: string, id: string) => { + const pipe = new TestTypeNamePipe(); + expect(pipe.transform(id, testTypes)).toBe(expected); + }); }); diff --git a/src/app/shared/pipes/test-type-name/test-type-name.pipe.ts b/src/app/shared/pipes/test-type-name/test-type-name.pipe.ts index a4e96db364..aca802585b 100644 --- a/src/app/shared/pipes/test-type-name/test-type-name.pipe.ts +++ b/src/app/shared/pipes/test-type-name/test-type-name.pipe.ts @@ -2,36 +2,38 @@ import { Pipe, PipeTransform } from '@angular/core'; import { TestType, TestTypeCategory } from '@api/test-types'; @Pipe({ - name: 'testTypeName', + name: 'testTypeName', }) export class TestTypeNamePipe implements PipeTransform { - findTestTypeNameById(id: string, testTypes: Array): TestType | undefined { - function idMatch(testType: TestType | TestTypeCategory) { - if (testType.id === id) { - result = testType; - return true; - } - return Object.prototype.hasOwnProperty.call(testType, 'nextTestTypesOrCategories') - && (testType as TestTypeCategory).nextTestTypesOrCategories?.some(idMatch); - } + findTestTypeNameById(id: string, testTypes: Array): TestType | undefined { + function idMatch(testType: TestType | TestTypeCategory) { + if (testType.id === id) { + result = testType; + return true; + } + return ( + Object.prototype.hasOwnProperty.call(testType, 'nextTestTypesOrCategories') && + (testType as TestTypeCategory).nextTestTypesOrCategories?.some(idMatch) + ); + } - let result; - testTypes.some(idMatch); - return result; - } + let result; + testTypes.some(idMatch); + return result; + } - transform(value: string, testTypes: Array | null): string { - if (!testTypes) { - return value; - } + transform(value: string, testTypes: Array | null): string { + if (!testTypes) { + return value; + } - const match = this.findTestTypeNameById(value, testTypes); + const match = this.findTestTypeNameById(value, testTypes); - if (!match) { - return '-'; - } + if (!match) { + return '-'; + } - const { suggestedTestTypeDisplayName, testTypeName, name } = match; - return suggestedTestTypeDisplayName || testTypeName || name || '-'; - } + const { suggestedTestTypeDisplayName, testTypeName, name } = match; + return suggestedTestTypeDisplayName || testTypeName || name || '-'; + } } diff --git a/src/app/shared/pipes/truncate/truncate.pipe.spec.ts b/src/app/shared/pipes/truncate/truncate.pipe.spec.ts index e6a142369b..ce36e89ad1 100644 --- a/src/app/shared/pipes/truncate/truncate.pipe.spec.ts +++ b/src/app/shared/pipes/truncate/truncate.pipe.spec.ts @@ -1,18 +1,18 @@ import { TruncatePipe } from './truncate.pipe'; describe('truncatePipe pipe tests', () => { - // This pipe is a pure, stateless function so no need for BeforeEach - const pipe = new TruncatePipe(); + // This pipe is a pure, stateless function so no need for BeforeEach + const pipe = new TruncatePipe(); - it('does not truncate string', () => { - expect(pipe.transform('too short', 10, '...')).toBe('too short'); - }); + it('does not truncate string', () => { + expect(pipe.transform('too short', 10, '...')).toBe('too short'); + }); - it('transforms "this string is too long" to "this string is too..."', () => { - expect(pipe.transform('this string is too long', 11)).toBe('this string...'); - }); + it('transforms "this string is too long" to "this string is too..."', () => { + expect(pipe.transform('this string is too long', 11)).toBe('this string...'); + }); - it('transforms "this string is too long" to "this string is too:::"', () => { - expect(pipe.transform('this string is too long', 11, ':::')).toBe('this string:::'); - }); + it('transforms "this string is too long" to "this string is too:::"', () => { + expect(pipe.transform('this string is too long', 11, ':::')).toBe('this string:::'); + }); }); diff --git a/src/app/shared/pipes/truncate/truncate.pipe.ts b/src/app/shared/pipes/truncate/truncate.pipe.ts index e468eaac33..4dc9b42882 100644 --- a/src/app/shared/pipes/truncate/truncate.pipe.ts +++ b/src/app/shared/pipes/truncate/truncate.pipe.ts @@ -1,10 +1,10 @@ import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ - name: 'truncate', + name: 'truncate', }) export class TruncatePipe implements PipeTransform { - transform(value: string, limit = 20, trail = '...'): string { - return value.length > limit ? value.substring(0, limit) + trail : value; - } + transform(value: string, limit = 20, trail = '...'): string { + return value.length > limit ? value.substring(0, limit) + trail : value; + } } diff --git a/src/app/shared/pipes/tyre-axle-load/tyre-axle-load.pipe.spec.ts b/src/app/shared/pipes/tyre-axle-load/tyre-axle-load.pipe.spec.ts index 462fcf3592..e572beb555 100644 --- a/src/app/shared/pipes/tyre-axle-load/tyre-axle-load.pipe.spec.ts +++ b/src/app/shared/pipes/tyre-axle-load/tyre-axle-load.pipe.spec.ts @@ -2,26 +2,28 @@ import { ReferenceDataResourceType } from '@models/reference-data.model'; import { TyreAxleLoadPipe } from './tyre-axle-load.pipe'; describe('TyreAxleLoadPipe', () => { - it('create an instance', () => { - const pipe = new TyreAxleLoadPipe(); - expect(pipe).toBeTruthy(); - }); + it('create an instance', () => { + const pipe = new TyreAxleLoadPipe(); + expect(pipe).toBeTruthy(); + }); - describe('transform the values', () => { - const pipe = new TyreAxleLoadPipe(); + describe('transform the values', () => { + const pipe = new TyreAxleLoadPipe(); - it('should return the value of the axle load if it is defined', () => { - expect(pipe.transform('value', '123', 2, [])).toBe('value'); - }); + it('should return the value of the axle load if it is defined', () => { + expect(pipe.transform('value', '123', 2, [])).toBe('value'); + }); - it('should multiply the value by the given factor and return the value as a string', () => { - expect( - pipe.transform(undefined, '123', 2, [{ resourceType: ReferenceDataResourceType.TyreLoadIndex, resourceKey: '123', loadIndex: '200' }]), - ).toBe((200 * 2).toString()); - }); + it('should multiply the value by the given factor and return the value as a string', () => { + expect( + pipe.transform(undefined, '123', 2, [ + { resourceType: ReferenceDataResourceType.TyreLoadIndex, resourceKey: '123', loadIndex: '200' }, + ]) + ).toBe((200 * 2).toString()); + }); - it('should return undefined if the loadIndex is undefined and the value is undefined', () => { - expect(pipe.transform(undefined, undefined, 3, [])).toBeUndefined(); - }); - }); + it('should return undefined if the loadIndex is undefined and the value is undefined', () => { + expect(pipe.transform(undefined, undefined, 3, [])).toBeUndefined(); + }); + }); }); diff --git a/src/app/shared/pipes/tyre-axle-load/tyre-axle-load.pipe.ts b/src/app/shared/pipes/tyre-axle-load/tyre-axle-load.pipe.ts index 70f2b2eb95..b140e76af3 100644 --- a/src/app/shared/pipes/tyre-axle-load/tyre-axle-load.pipe.ts +++ b/src/app/shared/pipes/tyre-axle-load/tyre-axle-load.pipe.ts @@ -2,19 +2,19 @@ import { Pipe, PipeTransform } from '@angular/core'; import { ReferenceDataTyreLoadIndex } from '@models/reference-data.model'; @Pipe({ - name: 'tyreAxleLoad', + name: 'tyreAxleLoad', }) export class TyreAxleLoadPipe implements PipeTransform { - transform( - axleLoad: string | undefined, - index: string | undefined, - factor: number, - loadIndex: ReferenceDataTyreLoadIndex[] | null, - ): undefined | string | number { - if (axleLoad) { - return axleLoad; - } - const axleLoadIndex = loadIndex?.find((resource) => resource.resourceKey === index); - return axleLoadIndex?.loadIndex ? String(+axleLoadIndex.loadIndex * factor) : undefined; - } + transform( + axleLoad: string | undefined, + index: string | undefined, + factor: number, + loadIndex: ReferenceDataTyreLoadIndex[] | null + ): undefined | string | number { + if (axleLoad) { + return axleLoad; + } + const axleLoadIndex = loadIndex?.find((resource) => resource.resourceKey === index); + return axleLoadIndex?.loadIndex ? String(+axleLoadIndex.loadIndex * factor) : undefined; + } } diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index c812d56293..5c2117b418 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -29,62 +29,61 @@ import { TestTypeNamePipe } from './pipes/test-type-name/test-type-name.pipe'; import { TyreAxleLoadPipe } from './pipes/tyre-axle-load/tyre-axle-load.pipe'; @NgModule({ - declarations: [ - DefaultNullOrEmpty, - ButtonGroupComponent, - ButtonComponent, - BannerComponent, - RoleRequiredDirective, - FeatureToggleDirective, - FeatureToggleDirective, - TagComponent, - NumberPlateComponent, - IconComponent, - TestTypeNamePipe, - AccordionComponent, - AccordionControlComponent, - PaginationComponent, - TestCertificateComponent, - PreventDoubleClickDirective, - BaseDialogComponent, - DigitGroupSeparatorPipe, - RefDataDecodePipe, - RetrieveDocumentDirective, - InputSpinnerComponent, - RouterOutletComponent, - TyreAxleLoadPipe, - GetControlLabelPipe, - FormatVehicleTypePipe, - CollapsibleTextComponent, - ], - imports: [CommonModule, RouterModule], - exports: [ - DefaultNullOrEmpty, - ButtonGroupComponent, - ButtonComponent, - BannerComponent, - RoleRequiredDirective, - FeatureToggleDirective, - TagComponent, - NumberPlateComponent, - IconComponent, - TestTypeNamePipe, - AccordionComponent, - AccordionControlComponent, - PaginationComponent, - TestCertificateComponent, - BaseDialogComponent, - DigitGroupSeparatorPipe, - RefDataDecodePipe, - RetrieveDocumentDirective, - InputSpinnerComponent, - RouterOutletComponent, - TyreAxleLoadPipe, - GetControlLabelPipe, - FormatVehicleTypePipe, - CollapsibleTextComponent, - - ], - providers: [DocumentRetrievalService], + declarations: [ + DefaultNullOrEmpty, + ButtonGroupComponent, + ButtonComponent, + BannerComponent, + RoleRequiredDirective, + FeatureToggleDirective, + FeatureToggleDirective, + TagComponent, + NumberPlateComponent, + IconComponent, + TestTypeNamePipe, + AccordionComponent, + AccordionControlComponent, + PaginationComponent, + TestCertificateComponent, + PreventDoubleClickDirective, + BaseDialogComponent, + DigitGroupSeparatorPipe, + RefDataDecodePipe, + RetrieveDocumentDirective, + InputSpinnerComponent, + RouterOutletComponent, + TyreAxleLoadPipe, + GetControlLabelPipe, + FormatVehicleTypePipe, + CollapsibleTextComponent, + ], + imports: [CommonModule, RouterModule], + exports: [ + DefaultNullOrEmpty, + ButtonGroupComponent, + ButtonComponent, + BannerComponent, + RoleRequiredDirective, + FeatureToggleDirective, + TagComponent, + NumberPlateComponent, + IconComponent, + TestTypeNamePipe, + AccordionComponent, + AccordionControlComponent, + PaginationComponent, + TestCertificateComponent, + BaseDialogComponent, + DigitGroupSeparatorPipe, + RefDataDecodePipe, + RetrieveDocumentDirective, + InputSpinnerComponent, + RouterOutletComponent, + TyreAxleLoadPipe, + GetControlLabelPipe, + FormatVehicleTypePipe, + CollapsibleTextComponent, + ], + providers: [DocumentRetrievalService], }) export class SharedModule {} diff --git a/src/app/store/app-store.module.ts b/src/app/store/app-store.module.ts index a27747510a..4cb77fba32 100644 --- a/src/app/store/app-store.module.ts +++ b/src/app/store/app-store.module.ts @@ -20,32 +20,32 @@ import { TestTypesStateModule } from './test-types/test-types.module'; import { UserStateModule } from './user/user-state.module'; @NgModule({ - declarations: [], - imports: [ - CommonModule, - StoreModule.forRoot({}), - EffectsModule.forRoot([]), - environment.EnableDevTools - ? StoreDevtoolsModule.instrument({ - name: 'VTM Web Dev Tools', - maxAge: 25, // Retains last 25 states - logOnly: environment.production, // Log-only mode in production - }) - : [], - DefectsStateModule, - GlobalErrorStateModule, - GlobalWarningStateModule, - ReferenceDataStateModule, - RouterStateModule, - SpinnerStateModule, - TechnicalRecordsStateModule, - TestRecordsStateModule, - TestStationsStateModule, - TestTypesStateModule, - UserStateModule, - TechRecordSearchStateModule, - RetryInterceptorStateModule, - RequiredStandardsStateModule, - ], + declarations: [], + imports: [ + CommonModule, + StoreModule.forRoot({}), + EffectsModule.forRoot([]), + environment.EnableDevTools + ? StoreDevtoolsModule.instrument({ + name: 'VTM Web Dev Tools', + maxAge: 25, // Retains last 25 states + logOnly: environment.production, // Log-only mode in production + }) + : [], + DefectsStateModule, + GlobalErrorStateModule, + GlobalWarningStateModule, + ReferenceDataStateModule, + RouterStateModule, + SpinnerStateModule, + TechnicalRecordsStateModule, + TestRecordsStateModule, + TestStationsStateModule, + TestTypesStateModule, + UserStateModule, + TechRecordSearchStateModule, + RetryInterceptorStateModule, + RequiredStandardsStateModule, + ], }) export class AppStoreModule {} diff --git a/src/app/store/defects/actions/defects.actions.spec.ts b/src/app/store/defects/actions/defects.actions.spec.ts index d97c9872d7..86c3a1cbb4 100644 --- a/src/app/store/defects/actions/defects.actions.spec.ts +++ b/src/app/store/defects/actions/defects.actions.spec.ts @@ -1,14 +1,19 @@ import { - fetchDefect, fetchDefectFailed, fetchDefects, fetchDefectsFailed, fetchDefectsSuccess, fetchDefectSuccess, + fetchDefect, + fetchDefectFailed, + fetchDefectSuccess, + fetchDefects, + fetchDefectsFailed, + fetchDefectsSuccess, } from './defects.actions'; describe('Defects Actions', () => { - it('should return correct types', () => { - expect(fetchDefects.type).toBe('[API/defects] Fetch Defects'); - expect(fetchDefectsSuccess.type).toBe('[API/defects] Fetch Defects Success'); - expect(fetchDefectsFailed.type).toBe('[API/defects] Fetch Defects Failed'); - expect(fetchDefect.type).toBe('[API/defects] Fetch Defect by ID'); - expect(fetchDefectSuccess.type).toBe('[API/defects] Fetch Defect by ID Success'); - expect(fetchDefectFailed.type).toBe('[API/defects] Fetch Defect by ID Failed'); - }); + it('should return correct types', () => { + expect(fetchDefects.type).toBe('[API/defects] Fetch Defects'); + expect(fetchDefectsSuccess.type).toBe('[API/defects] Fetch Defects Success'); + expect(fetchDefectsFailed.type).toBe('[API/defects] Fetch Defects Failed'); + expect(fetchDefect.type).toBe('[API/defects] Fetch Defect by ID'); + expect(fetchDefectSuccess.type).toBe('[API/defects] Fetch Defect by ID Success'); + expect(fetchDefectFailed.type).toBe('[API/defects] Fetch Defect by ID Failed'); + }); }); diff --git a/src/app/store/defects/actions/defects.actions.ts b/src/app/store/defects/actions/defects.actions.ts index 2146070585..b2d49ae7e5 100644 --- a/src/app/store/defects/actions/defects.actions.ts +++ b/src/app/store/defects/actions/defects.actions.ts @@ -11,7 +11,7 @@ export const fetchDefectSuccess = createAction(getTitle(false, 'Success'), props export const fetchDefectFailed = createAction(getTitle(false, 'Failed'), props()); function getTitle(isPlural = false, suffix = ''): string { - const plural = isPlural ? 's' : ' by ID'; - suffix = suffix ? ` ${suffix}` : suffix; - return `[API/defects] Fetch Defect${plural}${suffix}`; + const plural = isPlural ? 's' : ' by ID'; + suffix = suffix ? ` ${suffix}` : suffix; + return `[API/defects] Fetch Defect${plural}${suffix}`; } diff --git a/src/app/store/defects/defects-state.module.ts b/src/app/store/defects/defects-state.module.ts index 62a1dc1081..b0d9f1af36 100644 --- a/src/app/store/defects/defects-state.module.ts +++ b/src/app/store/defects/defects-state.module.ts @@ -3,10 +3,14 @@ import { NgModule } from '@angular/core'; import { EffectsModule } from '@ngrx/effects'; import { StoreModule } from '@ngrx/store'; import { DefectsEffects } from './effects/defects.effects'; -import { defectsReducer, STORE_FEATURE_DEFECTS_KEY } from './reducers/defects.reducer'; +import { STORE_FEATURE_DEFECTS_KEY, defectsReducer } from './reducers/defects.reducer'; @NgModule({ - declarations: [], - imports: [CommonModule, StoreModule.forFeature(STORE_FEATURE_DEFECTS_KEY, defectsReducer), EffectsModule.forFeature([DefectsEffects])], + declarations: [], + imports: [ + CommonModule, + StoreModule.forFeature(STORE_FEATURE_DEFECTS_KEY, defectsReducer), + EffectsModule.forFeature([DefectsEffects]), + ], }) export class DefectsStateModule {} diff --git a/src/app/store/defects/effects/defects.effects.spec.ts b/src/app/store/defects/effects/defects.effects.spec.ts index a859d83739..c749d5cdc1 100644 --- a/src/app/store/defects/effects/defects.effects.spec.ts +++ b/src/app/store/defects/effects/defects.effects.spec.ts @@ -9,113 +9,117 @@ import { initialAppState } from '@store/.'; import { Observable } from 'rxjs'; import { TestScheduler } from 'rxjs/testing'; import { - fetchDefect, - fetchDefectFailed, - fetchDefects, - fetchDefectsFailed, - fetchDefectsSuccess, - fetchDefectSuccess, + fetchDefect, + fetchDefectFailed, + fetchDefectSuccess, + fetchDefects, + fetchDefectsFailed, + fetchDefectsSuccess, } from '../actions/defects.actions'; import { DefectsEffects } from './defects.effects'; describe('DefectsEffects', () => { - let effects: DefectsEffects; - let actions$ = new Observable(); - let testScheduler: TestScheduler; - let service: DefectsService; - - const expectedResult = { imNumber: 1 } as Defect; - const testCases = [ - { - id: expectedResult.imNumber, - payload: [expectedResult], - }, - ]; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - DefectsEffects, - provideMockActions(() => actions$), - DefectsService, - provideMockStore({ - initialState: initialAppState, - }), - ], - }); - - effects = TestBed.inject(DefectsEffects); - service = TestBed.inject(DefectsService); - }); - - beforeEach(() => { - testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - }); - - describe('fetchDefects$', () => { - it.each(testCases)('should return fetchDefectsSuccess action on successfull API call', (value) => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const { payload } = value; - - // mock action to trigger effect - actions$ = hot('-a--', { a: fetchDefects() }); - - // mock service call - jest.spyOn(service, 'fetchDefects').mockReturnValue(cold('--a|', { a: payload })); - - // expect effect to return success action - expectObservable(effects.fetchDefects$).toBe('---b', { - b: fetchDefectsSuccess({ payload }), - }); - }); - }); - - it.each(testCases)('should return fetchDefectsFailed action on API error', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - actions$ = hot('-a--', { a: fetchDefects() }); - - const expectedError = new Error('Reference data resourceType is required'); - - jest.spyOn(service, 'fetchDefects').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.fetchDefects$).toBe('---b', { b: fetchDefectsFailed({ error: 'Reference data resourceType is required' }) }); - }); - }); - }); - - describe('fetchDefect$', () => { - it.each(testCases)('should return fetchDefectSuccess action on successfull API call', (value) => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const { id, payload } = value; - const entity = payload.find((d) => d.imNumber === id) as Defect; - - // mock action to trigger effect - actions$ = hot('-a--', { a: fetchDefect({ id }) }); - - // mock service call - jest.spyOn(service, 'fetchDefect').mockReturnValue(cold('--a|', { a: entity })); - - // expect effect to return success action - expectObservable(effects.fetchDefect$).toBe('---b', { - b: fetchDefectSuccess({ id, payload: entity }), - }); - }); - }); - - it.each(testCases)('should return fetchDefectFailed action on API error', (value) => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const { id } = value; - actions$ = hot('-a--', { a: fetchDefect({ id }) }); - - const expectedError = new Error('Reference data resourceKey is required'); - - jest.spyOn(service, 'fetchDefect').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.fetchDefect$).toBe('---b', { b: fetchDefectFailed({ error: 'Reference data resourceKey is required' }) }); - }); - }); - }); + let effects: DefectsEffects; + let actions$ = new Observable(); + let testScheduler: TestScheduler; + let service: DefectsService; + + const expectedResult = { imNumber: 1 } as Defect; + const testCases = [ + { + id: expectedResult.imNumber, + payload: [expectedResult], + }, + ]; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + DefectsEffects, + provideMockActions(() => actions$), + DefectsService, + provideMockStore({ + initialState: initialAppState, + }), + ], + }); + + effects = TestBed.inject(DefectsEffects); + service = TestBed.inject(DefectsService); + }); + + beforeEach(() => { + testScheduler = new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); + }); + }); + + describe('fetchDefects$', () => { + it.each(testCases)('should return fetchDefectsSuccess action on successfull API call', (value) => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const { payload } = value; + + // mock action to trigger effect + actions$ = hot('-a--', { a: fetchDefects() }); + + // mock service call + jest.spyOn(service, 'fetchDefects').mockReturnValue(cold('--a|', { a: payload })); + + // expect effect to return success action + expectObservable(effects.fetchDefects$).toBe('---b', { + b: fetchDefectsSuccess({ payload }), + }); + }); + }); + + it.each(testCases)('should return fetchDefectsFailed action on API error', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + actions$ = hot('-a--', { a: fetchDefects() }); + + const expectedError = new Error('Reference data resourceType is required'); + + jest.spyOn(service, 'fetchDefects').mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.fetchDefects$).toBe('---b', { + b: fetchDefectsFailed({ error: 'Reference data resourceType is required' }), + }); + }); + }); + }); + + describe('fetchDefect$', () => { + it.each(testCases)('should return fetchDefectSuccess action on successfull API call', (value) => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const { id, payload } = value; + const entity = payload.find((d) => d.imNumber === id) as Defect; + + // mock action to trigger effect + actions$ = hot('-a--', { a: fetchDefect({ id }) }); + + // mock service call + jest.spyOn(service, 'fetchDefect').mockReturnValue(cold('--a|', { a: entity })); + + // expect effect to return success action + expectObservable(effects.fetchDefect$).toBe('---b', { + b: fetchDefectSuccess({ id, payload: entity }), + }); + }); + }); + + it.each(testCases)('should return fetchDefectFailed action on API error', (value) => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const { id } = value; + actions$ = hot('-a--', { a: fetchDefect({ id }) }); + + const expectedError = new Error('Reference data resourceKey is required'); + + jest.spyOn(service, 'fetchDefect').mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.fetchDefect$).toBe('---b', { + b: fetchDefectFailed({ error: 'Reference data resourceKey is required' }), + }); + }); + }); + }); }); diff --git a/src/app/store/defects/effects/defects.effects.ts b/src/app/store/defects/effects/defects.effects.ts index 8497779325..3d8488ac58 100644 --- a/src/app/store/defects/effects/defects.effects.ts +++ b/src/app/store/defects/effects/defects.effects.ts @@ -1,39 +1,44 @@ import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { DefectsService } from '@services/defects/defects.service'; +import { catchError, map, mergeMap, of } from 'rxjs'; import { - catchError, map, mergeMap, of, -} from 'rxjs'; -import { - fetchDefect, - fetchDefectFailed, - fetchDefects, - fetchDefectsFailed, - fetchDefectsSuccess, - fetchDefectSuccess, + fetchDefect, + fetchDefectFailed, + fetchDefectSuccess, + fetchDefects, + fetchDefectsFailed, + fetchDefectsSuccess, } from '../actions/defects.actions'; @Injectable() export class DefectsEffects { - fetchDefects$ = createEffect(() => - this.actions$.pipe( - ofType(fetchDefects), - mergeMap(() => - this.defectsService.fetchDefects().pipe( - map((defects) => fetchDefectsSuccess({ payload: defects })), - catchError((e) => of(fetchDefectsFailed({ error: e.message }))), - )), - )); + fetchDefects$ = createEffect(() => + this.actions$.pipe( + ofType(fetchDefects), + mergeMap(() => + this.defectsService.fetchDefects().pipe( + map((defects) => fetchDefectsSuccess({ payload: defects })), + catchError((e) => of(fetchDefectsFailed({ error: e.message }))) + ) + ) + ) + ); - fetchDefect$ = createEffect(() => - this.actions$.pipe( - ofType(fetchDefect), - mergeMap(({ id }) => - this.defectsService.fetchDefect(id).pipe( - map((defect) => fetchDefectSuccess({ id, payload: defect })), - catchError((e) => of(fetchDefectFailed({ error: e.message }))), - )), - )); + fetchDefect$ = createEffect(() => + this.actions$.pipe( + ofType(fetchDefect), + mergeMap(({ id }) => + this.defectsService.fetchDefect(id).pipe( + map((defect) => fetchDefectSuccess({ id, payload: defect })), + catchError((e) => of(fetchDefectFailed({ error: e.message }))) + ) + ) + ) + ); - constructor(private actions$: Actions, private defectsService: DefectsService) {} + constructor( + private actions$: Actions, + private defectsService: DefectsService + ) {} } diff --git a/src/app/store/defects/reducers/defects.reducer.spec.ts b/src/app/store/defects/reducers/defects.reducer.spec.ts index dd1ada9d0e..b14cdf0ea0 100644 --- a/src/app/store/defects/reducers/defects.reducer.spec.ts +++ b/src/app/store/defects/reducers/defects.reducer.spec.ts @@ -1,99 +1,99 @@ import { Defect } from '@models/defects/defect.model'; import { - fetchDefect, - fetchDefectFailed, - fetchDefects, - fetchDefectsFailed, - fetchDefectsSuccess, - fetchDefectSuccess, + fetchDefect, + fetchDefectFailed, + fetchDefectSuccess, + fetchDefects, + fetchDefectsFailed, + fetchDefectsSuccess, } from '../actions/defects.actions'; -import { defectsReducer, DefectsState, initialDefectsState } from './defects.reducer'; +import { DefectsState, defectsReducer, initialDefectsState } from './defects.reducer'; describe('Defects Reducer', () => { - const expectedDefects = [{ imNumber: 1, imDescription: 'some description' } as Defect]; + const expectedDefects = [{ imNumber: 1, imDescription: 'some description' } as Defect]; - describe('unknown action', () => { - it('should return the default state', () => { - const action = { - type: 'Unknown', - }; - const state = defectsReducer(initialDefectsState, action); + describe('unknown action', () => { + it('should return the default state', () => { + const action = { + type: 'Unknown', + }; + const state = defectsReducer(initialDefectsState, action); - expect(state).toBe(initialDefectsState); - }); - }); + expect(state).toBe(initialDefectsState); + }); + }); - describe('fetchDefects actions', () => { - it('should set loading to true', () => { - const newState: DefectsState = { ...initialDefectsState, loading: true }; - const action = fetchDefects(); - const state = defectsReducer(initialDefectsState, action); + describe('fetchDefects actions', () => { + it('should set loading to true', () => { + const newState: DefectsState = { ...initialDefectsState, loading: true }; + const action = fetchDefects(); + const state = defectsReducer(initialDefectsState, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); - describe('fetchDefectsSuccess', () => { - it('should set all test result records', () => { - const newState: DefectsState = { - ...initialDefectsState, - ids: ['1: some description'], - entities: { '1: some description': expectedDefects[0] }, - }; - const action = fetchDefectsSuccess({ payload: [...expectedDefects] }); - const state = defectsReducer(initialDefectsState, action); + describe('fetchDefectsSuccess', () => { + it('should set all test result records', () => { + const newState: DefectsState = { + ...initialDefectsState, + ids: ['1: some description'], + entities: { '1: some description': expectedDefects[0] }, + }; + const action = fetchDefectsSuccess({ payload: [...expectedDefects] }); + const state = defectsReducer(initialDefectsState, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); - describe('fetchDefectsFailed', () => { - it('should set error state', () => { - const newState = { ...initialDefectsState, loading: false }; - const action = fetchDefectsFailed({ error: 'unit testing error message' }); - const state = defectsReducer({ ...initialDefectsState, loading: true }, action); + describe('fetchDefectsFailed', () => { + it('should set error state', () => { + const newState = { ...initialDefectsState, loading: false }; + const action = fetchDefectsFailed({ error: 'unit testing error message' }); + const state = defectsReducer({ ...initialDefectsState, loading: true }, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - }); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + }); + }); - describe('fetchDefect actions', () => { - it('should set loading to true', () => { - const newState: DefectsState = { ...initialDefectsState, loading: true }; - const action = fetchDefect({ id: 1 }); - const state = defectsReducer(initialDefectsState, action); + describe('fetchDefect actions', () => { + it('should set loading to true', () => { + const newState: DefectsState = { ...initialDefectsState, loading: true }; + const action = fetchDefect({ id: 1 }); + const state = defectsReducer(initialDefectsState, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); - describe('fetchDefectSuccess', () => { - it('should set all test result records', () => { - const newState: DefectsState = { - ...initialDefectsState, - ids: ['1: some description'], - entities: { '1: some description': expectedDefects[0] }, - }; - const action = fetchDefectSuccess({ id: 1, payload: expectedDefects[0] }); - const state = defectsReducer(initialDefectsState, action); + describe('fetchDefectSuccess', () => { + it('should set all test result records', () => { + const newState: DefectsState = { + ...initialDefectsState, + ids: ['1: some description'], + entities: { '1: some description': expectedDefects[0] }, + }; + const action = fetchDefectSuccess({ id: 1, payload: expectedDefects[0] }); + const state = defectsReducer(initialDefectsState, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); - describe('fetchDefectFailed', () => { - it('should set error state', () => { - const newState = { ...initialDefectsState, loading: false }; - const action = fetchDefectFailed({ error: 'unit testing error message' }); - const state = defectsReducer({ ...initialDefectsState, loading: true }, action); + describe('fetchDefectFailed', () => { + it('should set error state', () => { + const newState = { ...initialDefectsState, loading: false }; + const action = fetchDefectFailed({ error: 'unit testing error message' }); + const state = defectsReducer({ ...initialDefectsState, loading: true }, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + }); }); diff --git a/src/app/store/defects/reducers/defects.reducer.ts b/src/app/store/defects/reducers/defects.reducer.ts index c97ac8623f..ee377a4e04 100644 --- a/src/app/store/defects/reducers/defects.reducer.ts +++ b/src/app/store/defects/reducers/defects.reducer.ts @@ -1,18 +1,18 @@ import { Defect } from '@models/defects/defect.model'; -import { createEntityAdapter, EntityAdapter, EntityState } from '@ngrx/entity'; +import { EntityAdapter, EntityState, createEntityAdapter } from '@ngrx/entity'; import { createFeatureSelector, createReducer, on } from '@ngrx/store'; import { - fetchDefect, - fetchDefectFailed, - fetchDefects, - fetchDefectsFailed, - fetchDefectsSuccess, - fetchDefectSuccess, + fetchDefect, + fetchDefectFailed, + fetchDefectSuccess, + fetchDefects, + fetchDefectsFailed, + fetchDefectsSuccess, } from '../actions/defects.actions'; export interface DefectsState extends EntityState { - loading: boolean; - error: string; + loading: boolean; + error: string; } export const STORE_FEATURE_DEFECTS_KEY = 'Defects'; @@ -20,19 +20,19 @@ export const STORE_FEATURE_DEFECTS_KEY = 'Defects'; export const defectsFeatureState = createFeatureSelector(STORE_FEATURE_DEFECTS_KEY); export const defectsAdapter: EntityAdapter = createEntityAdapter({ - selectId: (defect) => `${defect.imNumber}: ${defect.imDescription}`, + selectId: (defect) => `${defect.imNumber}: ${defect.imDescription}`, }); export const initialDefectsState = defectsAdapter.getInitialState({ loading: false, error: '' }); export const defectsReducer = createReducer( - initialDefectsState, + initialDefectsState, - on(fetchDefects, (state) => ({ ...state, loading: true })), - on(fetchDefectsSuccess, (state, action) => ({ ...defectsAdapter.setAll(action.payload, state), loading: false })), - on(fetchDefectsFailed, (state) => ({ ...defectsAdapter.setAll([], state), loading: false })), + on(fetchDefects, (state) => ({ ...state, loading: true })), + on(fetchDefectsSuccess, (state, action) => ({ ...defectsAdapter.setAll(action.payload, state), loading: false })), + on(fetchDefectsFailed, (state) => ({ ...defectsAdapter.setAll([], state), loading: false })), - on(fetchDefect, (state) => ({ ...state, loading: true })), - on(fetchDefectSuccess, (state, action) => ({ ...defectsAdapter.upsertOne(action.payload, state), loading: false })), - on(fetchDefectFailed, (state) => ({ ...defectsAdapter.setAll([], state), loading: false })), + on(fetchDefect, (state) => ({ ...state, loading: true })), + on(fetchDefectSuccess, (state, action) => ({ ...defectsAdapter.upsertOne(action.payload, state), loading: false })), + on(fetchDefectFailed, (state) => ({ ...defectsAdapter.setAll([], state), loading: false })) ); diff --git a/src/app/store/defects/selectors/defects.selectors.spec.ts b/src/app/store/defects/selectors/defects.selectors.spec.ts index 416a621385..5fb66a9b81 100644 --- a/src/app/store/defects/selectors/defects.selectors.spec.ts +++ b/src/app/store/defects/selectors/defects.selectors.spec.ts @@ -4,85 +4,83 @@ import { Deficiency } from '@models/defects/deficiency.model'; import { Item } from '@models/defects/item.model'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { DefectsState, initialDefectsState } from '../reducers/defects.reducer'; -import { - defect, defects, defectsLoadingState, selectByDeficiencyRef, selectByImNumber, -} from './defects.selectors'; +import { defect, defects, defectsLoadingState, selectByDeficiencyRef, selectByImNumber } from './defects.selectors'; describe('Defects Selectors', () => { - describe('adapter selectors', () => { - it('should return correct state', () => { - const state = { ...initialDefectsState, ids: [1], entities: { 1: { preparerId: 2 } } } as unknown as DefectsState; + describe('adapter selectors', () => { + it('should return correct state', () => { + const state = { ...initialDefectsState, ids: [1], entities: { 1: { preparerId: 2 } } } as unknown as DefectsState; - expect(defects.projector(state)).toEqual([{ preparerId: 2 }]); - expect(defect('1').projector(state)).toEqual({ preparerId: 2 }); - }); - }); + expect(defects.projector(state)).toEqual([{ preparerId: 2 }]); + expect(defect('1').projector(state)).toEqual({ preparerId: 2 }); + }); + }); - describe('testStationsLoadingState', () => { - it('should return loading state', () => { - const state: DefectsState = { ...initialDefectsState, loading: true }; - const selectedState = defectsLoadingState.projector(state); - expect(selectedState).toBeTruthy(); - }); - }); + describe('testStationsLoadingState', () => { + it('should return loading state', () => { + const state: DefectsState = { ...initialDefectsState, loading: true }; + const selectedState = defectsLoadingState.projector(state); + expect(selectedState).toBeTruthy(); + }); + }); - describe('should return correct state', () => { - const deficiency: Deficiency = { - deficiencyCategory: deficiencyCategory.Major, - deficiencyId: 'a', - deficiencySubId: '', - deficiencyText: 'missing.', - forVehicleType: [VehicleTypes.PSV], - ref: '1.1.a', - stdForProhibition: false, - }; + describe('should return correct state', () => { + const deficiency: Deficiency = { + deficiencyCategory: deficiencyCategory.Major, + deficiencyId: 'a', + deficiencySubId: '', + deficiencyText: 'missing.', + forVehicleType: [VehicleTypes.PSV], + ref: '1.1.a', + stdForProhibition: false, + }; - const item: Item = { - deficiencies: [deficiency], - forVehicleType: [VehicleTypes.PSV], - itemDescription: 'A registration plate:', - itemNumber: 1, - }; + const item: Item = { + deficiencies: [deficiency], + forVehicleType: [VehicleTypes.PSV], + itemDescription: 'A registration plate:', + itemNumber: 1, + }; - const mockDefect: Defect = { - additionalInfo: { - [VehicleTypes.PSV]: { - location: { - longitudinal: ['front', 'rear'], - }, - notes: false, - }, - }, - forVehicleType: [VehicleTypes.PSV], - imDescription: 'Registration Plate', - imNumber: 1, - items: [item], - }; - const defect2: Defect = { - additionalInfo: { - [VehicleTypes.PSV]: { - location: { - longitudinal: ['front', 'rear'], - }, - notes: false, - }, - }, - forVehicleType: [VehicleTypes.PSV], - imDescription: 'Registration Plate', - imNumber: 2, - items: [item], - }; + const mockDefect: Defect = { + additionalInfo: { + [VehicleTypes.PSV]: { + location: { + longitudinal: ['front', 'rear'], + }, + notes: false, + }, + }, + forVehicleType: [VehicleTypes.PSV], + imDescription: 'Registration Plate', + imNumber: 1, + items: [item], + }; + const defect2: Defect = { + additionalInfo: { + [VehicleTypes.PSV]: { + location: { + longitudinal: ['front', 'rear'], + }, + notes: false, + }, + }, + forVehicleType: [VehicleTypes.PSV], + imDescription: 'Registration Plate', + imNumber: 2, + items: [item], + }; - const defectList: Defect[] = [mockDefect, defect2]; + const defectList: Defect[] = [mockDefect, defect2]; - it('should return filtered defect by IM number', () => { - const selectedState = selectByImNumber(2, VehicleTypes.PSV).projector(defectList); - expect(selectedState).toEqual(defect2); - }); + it('should return filtered defect by IM number', () => { + const selectedState = selectByImNumber(2, VehicleTypes.PSV).projector(defectList); + expect(selectedState).toEqual(defect2); + }); - it('should return filtered defect by deficiency ref', () => { - const selectedState = selectByDeficiencyRef('1.1.a', VehicleTypes.PSV).projector(defectList); - expect(selectedState).toEqual([mockDefect, item, deficiency]); - }); - }); + it('should return filtered defect by deficiency ref', () => { + const selectedState = selectByDeficiencyRef('1.1.a', VehicleTypes.PSV).projector(defectList); + expect(selectedState).toEqual([mockDefect, item, deficiency]); + }); + }); }); diff --git a/src/app/store/defects/selectors/defects.selectors.ts b/src/app/store/defects/selectors/defects.selectors.ts index 92baa9b415..72e90af203 100644 --- a/src/app/store/defects/selectors/defects.selectors.ts +++ b/src/app/store/defects/selectors/defects.selectors.ts @@ -11,53 +11,56 @@ const { selectAll } = defectsAdapter.getSelectors(); export const defects = createSelector(defectsFeatureState, (state) => selectAll(state)); export const filteredDefects = (type: VehicleTypes) => - createSelector(defects, (defectList) => { - return cloneDeep(defectList) - .filter((defect) => defect.forVehicleType.includes(type)) - .map((defect) => ({ - ...defect, - items: defect.items - .filter((item) => item.forVehicleType.includes(type)) - .map((item) => ({ - ...item, - deficiencies: item.deficiencies.filter((deficiency) => deficiency.forVehicleType.includes(type)), - })), - })); - }); + createSelector(defects, (defectList) => { + return cloneDeep(defectList) + .filter((defect) => defect.forVehicleType.includes(type)) + .map((defect) => ({ + ...defect, + items: defect.items + .filter((item) => item.forVehicleType.includes(type)) + .map((item) => ({ + ...item, + deficiencies: item.deficiencies.filter((deficiency) => deficiency.forVehicleType.includes(type)), + })), + })); + }); export const selectByImNumber = (imNumber: number, vehicleType: VehicleTypes) => - createSelector(filteredDefects(vehicleType), (defectsList) => defectsList.find((defect) => defect.imNumber === imNumber)); + createSelector(filteredDefects(vehicleType), (defectsList) => + defectsList.find((defect) => defect.imNumber === imNumber) + ); export const selectByDeficiencyRef = (deficiencyRef: string, vehicleType: VehicleTypes) => - createSelector(filteredDefects(vehicleType), (defectsList) => { - const deRef = deficiencyRef.split('.'); - const isAdvisory: boolean = deRef[2] === 'advisory'; - let defect: Defect | undefined; let item: Item | undefined; let - deficiency: Deficiency | undefined; + createSelector(filteredDefects(vehicleType), (defectsList) => { + const deRef = deficiencyRef.split('.'); + const isAdvisory: boolean = deRef[2] === 'advisory'; + let defect: Defect | undefined; + let item: Item | undefined; + let deficiency: Deficiency | undefined; - if (deRef) { - defect = defectsList.find((d) => d.imNumber === +deRef[0]); - const items = defect?.items.filter((i) => i.itemNumber === +deRef[1]); + if (deRef) { + defect = defectsList.find((d) => d.imNumber === +deRef[0]); + const items = defect?.items.filter((i) => i.itemNumber === +deRef[1]); - // eslint-disable-next-line @typescript-eslint/no-unused-expressions, no-unused-expressions - !isAdvisory - && items?.forEach((itm) => { - const defRef: Deficiency | undefined = itm.deficiencies.find((d) => d.ref === deficiencyRef); - if (defRef) { - item = itm; - deficiency = defRef; - } - }); + // eslint-disable-next-line @typescript-eslint/no-unused-expressions, no-unused-expressions + !isAdvisory && + items?.forEach((itm) => { + const defRef: Deficiency | undefined = itm.deficiencies.find((d) => d.ref === deficiencyRef); + if (defRef) { + item = itm; + deficiency = defRef; + } + }); - if (!deficiency && isAdvisory && deRef[3]) { - item = items?.[+deRef[3]]; - } else { - item = defect?.items.find((i) => i.itemNumber === +deRef[1]); - } - } + if (!deficiency && isAdvisory && deRef[3]) { + item = items?.[+deRef[3]]; + } else { + item = defect?.items.find((i) => i.itemNumber === +deRef[1]); + } + } - return [defect, item, deficiency]; - }); + return [defect, item, deficiency]; + }); export const psvDefects = filteredDefects(VehicleTypes.PSV); diff --git a/src/app/store/global-error/global-error-state.module.ts b/src/app/store/global-error/global-error-state.module.ts index ebed6b840e..6c9366a608 100644 --- a/src/app/store/global-error/global-error-state.module.ts +++ b/src/app/store/global-error/global-error-state.module.ts @@ -1,10 +1,13 @@ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { StoreModule } from '@ngrx/store'; -import { globalErrorReducer, STORE_FEATURE_GLOBAL_ERROR_KEY } from '@store/global-error/reducers/global-error-service.reducer'; +import { + STORE_FEATURE_GLOBAL_ERROR_KEY, + globalErrorReducer, +} from '@store/global-error/reducers/global-error-service.reducer'; @NgModule({ - declarations: [], - imports: [CommonModule, StoreModule.forFeature(STORE_FEATURE_GLOBAL_ERROR_KEY, globalErrorReducer)], + declarations: [], + imports: [CommonModule, StoreModule.forFeature(STORE_FEATURE_GLOBAL_ERROR_KEY, globalErrorReducer)], }) export class GlobalErrorStateModule {} diff --git a/src/app/store/global-error/reducers/global-error-service.reducer.spec.ts b/src/app/store/global-error/reducers/global-error-service.reducer.spec.ts index 75303f47ae..47d2af39a1 100644 --- a/src/app/store/global-error/reducers/global-error-service.reducer.spec.ts +++ b/src/app/store/global-error/reducers/global-error-service.reducer.spec.ts @@ -1,85 +1,98 @@ -import { routerNavigatedAction, RouterNavigatedPayload, SerializedRouterStateSnapshot } from '@ngrx/router-store'; -import { globalErrorReducer, GlobalErrorState, initialGlobalErrorState } from '@store/global-error/reducers/global-error-service.reducer'; +import { RouterNavigatedPayload, SerializedRouterStateSnapshot, routerNavigatedAction } from '@ngrx/router-store'; import { - fetchTestResults, fetchTestResultsBySystemNumber, fetchTestResultsBySystemNumberFailed, fetchTestResultsFailed, -} from '@store/test-records'; + GlobalErrorState, + globalErrorReducer, + initialGlobalErrorState, +} from '@store/global-error/reducers/global-error-service.reducer'; import { fetchSearchResultFailed } from '@store/tech-record-search/actions/tech-record-search.actions'; +import { + fetchTestResults, + fetchTestResultsBySystemNumber, + fetchTestResultsBySystemNumberFailed, + fetchTestResultsFailed, +} from '@store/test-records'; import { patchErrors, setErrors } from '../actions/global-error.actions'; describe('Global Error Reducer', () => { - describe('unknown action', () => { - it('should return the default state', () => { - const action = { - type: 'Unknown', - }; + describe('unknown action', () => { + it('should return the default state', () => { + const action = { + type: 'Unknown', + }; - const state = globalErrorReducer(initialGlobalErrorState, action); - expect(state).toBe(initialGlobalErrorState); - }); - }); + const state = globalErrorReducer(initialGlobalErrorState, action); + expect(state).toBe(initialGlobalErrorState); + }); + }); - describe('Fail action', () => { - it.each([fetchTestResultsBySystemNumberFailed, fetchTestResultsFailed, fetchSearchResultFailed])( - 'should return the error state', - (actionMethod) => { - const error = 'fetching test records failed'; - const newState: GlobalErrorState = { ...initialGlobalErrorState, errors: [{ error, anchorLink: undefined }] }; - const action = actionMethod({ error }); - const state = globalErrorReducer(initialGlobalErrorState, action); + describe('Fail action', () => { + it.each([fetchTestResultsBySystemNumberFailed, fetchTestResultsFailed, fetchSearchResultFailed])( + 'should return the error state', + (actionMethod) => { + const error = 'fetching test records failed'; + const newState: GlobalErrorState = { ...initialGlobalErrorState, errors: [{ error, anchorLink: undefined }] }; + const action = actionMethod({ error }); + const state = globalErrorReducer(initialGlobalErrorState, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }, - ); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + } + ); + }); - describe('Success action', () => { - it.each([fetchTestResultsBySystemNumber, fetchTestResults])('should reset the error state', (actionMethod) => { - const newState = { ...initialGlobalErrorState, errors: [] }; - // all props must be supplied here - const action = actionMethod({ systemNumber: '' }); - const state = globalErrorReducer(initialGlobalErrorState, action); + describe('Success action', () => { + it.each([fetchTestResultsBySystemNumber, fetchTestResults])('should reset the error state', (actionMethod) => { + const newState = { ...initialGlobalErrorState, errors: [] }; + // all props must be supplied here + const action = actionMethod({ systemNumber: '' }); + const state = globalErrorReducer(initialGlobalErrorState, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); - it.each([routerNavigatedAction])('should reset the error state', (actionMethod) => { - const newState = { ...initialGlobalErrorState, errors: [] }; - // all props must be supplied here - const action = actionMethod({ payload: >{} }); - const state = globalErrorReducer(initialGlobalErrorState, action); + it.each([routerNavigatedAction])('should reset the error state', (actionMethod) => { + const newState = { ...initialGlobalErrorState, errors: [] }; + // all props must be supplied here + const action = actionMethod({ payload: >{} }); + const state = globalErrorReducer(initialGlobalErrorState, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); - describe('setErrors', () => { - it('should replace existing errors with new ones', () => { - const newState = { ...initialGlobalErrorState, errors: [{ error: 'some error', anchorLink: '' }] }; - const action = setErrors({ errors: [{ error: 'some error', anchorLink: '' }] }); - const state = globalErrorReducer({ ...initialGlobalErrorState, errors: [{ error: 'old error', anchorLink: '' }] }, action); + describe('setErrors', () => { + it('should replace existing errors with new ones', () => { + const newState = { ...initialGlobalErrorState, errors: [{ error: 'some error', anchorLink: '' }] }; + const action = setErrors({ errors: [{ error: 'some error', anchorLink: '' }] }); + const state = globalErrorReducer( + { ...initialGlobalErrorState, errors: [{ error: 'old error', anchorLink: '' }] }, + action + ); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); - it('should add new errors after existing ones', () => { - const newState = { - ...initialGlobalErrorState, - errors: [ - { error: 'old error', anchorLink: '' }, - { error: 'new error', anchorLink: '' }, - ], - }; - const action = patchErrors({ - errors: [{ error: 'new error', anchorLink: '' }], - }); - const state = globalErrorReducer({ ...initialGlobalErrorState, errors: [{ error: 'old error', anchorLink: '' }] }, action); + it('should add new errors after existing ones', () => { + const newState = { + ...initialGlobalErrorState, + errors: [ + { error: 'old error', anchorLink: '' }, + { error: 'new error', anchorLink: '' }, + ], + }; + const action = patchErrors({ + errors: [{ error: 'new error', anchorLink: '' }], + }); + const state = globalErrorReducer( + { ...initialGlobalErrorState, errors: [{ error: 'old error', anchorLink: '' }] }, + action + ); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); }); diff --git a/src/app/store/global-error/reducers/global-error-service.reducer.ts b/src/app/store/global-error/reducers/global-error-service.reducer.ts index 163d2d3ac1..5591946fea 100644 --- a/src/app/store/global-error/reducers/global-error-service.reducer.ts +++ b/src/app/store/global-error/reducers/global-error-service.reducer.ts @@ -1,9 +1,10 @@ import { GlobalError } from '@core/components/global-error/global-error.interface'; import { routerNavigatedAction } from '@ngrx/router-store'; +import { createFeatureSelector, createReducer, createSelector, on } from '@ngrx/store'; import { - createFeatureSelector, createReducer, createSelector, on, -} from '@ngrx/store'; -import { fetchSearchResult, fetchSearchResultFailed } from '@store/tech-record-search/actions/tech-record-search.actions'; + fetchSearchResult, + fetchSearchResultFailed, +} from '@store/tech-record-search/actions/tech-record-search.actions'; // eslint-disable-next-line import/no-cycle import * as TestResultActions from '@store/test-records'; import _ from 'lodash'; @@ -15,11 +16,11 @@ import * as GlobalErrorActions from '../actions/global-error.actions'; export const STORE_FEATURE_GLOBAL_ERROR_KEY = 'globalError'; export interface GlobalErrorState { - errors: Array; + errors: Array; } export const initialGlobalErrorState: GlobalErrorState = { - errors: [], + errors: [], }; export const getGlobalErrorState = createFeatureSelector(STORE_FEATURE_GLOBAL_ERROR_KEY); @@ -27,49 +28,54 @@ export const getGlobalErrorState = createFeatureSelector(STORE export const globalErrorState = createSelector(getGlobalErrorState, (state) => state.errors); export const globalErrorReducer = createReducer( - initialGlobalErrorState, - on( - GlobalErrorActions.clearError, - TechnicalRecordServiceActions.updateTechRecord, - TestResultActions.fetchTestResults, - TestResultActions.fetchTestResultsBySystemNumber, - TestResultActions.fetchSelectedTestResult, - ReferenceDataActions.fetchReferenceData, - ReferenceDataActions.fetchReferenceDataByKey, - fetchSearchResult, - routerNavigatedAction, - successMethod, - ), + initialGlobalErrorState, + on( + GlobalErrorActions.clearError, + TechnicalRecordServiceActions.updateTechRecord, + TestResultActions.fetchTestResults, + TestResultActions.fetchTestResultsBySystemNumber, + TestResultActions.fetchSelectedTestResult, + ReferenceDataActions.fetchReferenceData, + ReferenceDataActions.fetchReferenceDataByKey, + fetchSearchResult, + routerNavigatedAction, + successMethod + ), - on( - GlobalErrorActions.addError, - TechnicalRecordServiceActions.updateTechRecordFailure, - TechnicalRecordServiceActions.generateLetterFailure, - TechnicalRecordServiceActions.generatePlateFailure, - TechnicalRecordServiceActions.generateADRCertificateFailure, - TechnicalRecordServiceActions.archiveTechRecordFailure, - TechnicalRecordServiceActions.unarchiveTechRecordFailure, - TestResultActions.fetchTestResultsFailed, - TestResultActions.fetchTestResultsBySystemNumberFailed, - TestResultActions.fetchSelectedTestResultFailed, - ReferenceDataActions.fetchReferenceDataFailed, - ReferenceDataActions.fetchReferenceDataByKeyFailed, - fetchSearchResultFailed, - failureMethod, - ), - on(GlobalErrorActions.setErrors, TestResultActions.updateTestResultFailed, TestResultActions.createTestResultFailed, (state, { errors }) => ({ - ...state, - errors: [...(_.uniqWith(errors, (a, b) => _.isEqual(a.error, b.error)))], - })), - on(GlobalErrorActions.patchErrors, (state, { errors }) => ({ ...state, errors: [...state.errors, ...errors] })), - on(createVehicleRecordFailure, (state, action) => ({ errors: [...state.errors, { error: action.error }] })), + on( + GlobalErrorActions.addError, + TechnicalRecordServiceActions.updateTechRecordFailure, + TechnicalRecordServiceActions.generateLetterFailure, + TechnicalRecordServiceActions.generatePlateFailure, + TechnicalRecordServiceActions.generateADRCertificateFailure, + TechnicalRecordServiceActions.archiveTechRecordFailure, + TechnicalRecordServiceActions.unarchiveTechRecordFailure, + TestResultActions.fetchTestResultsFailed, + TestResultActions.fetchTestResultsBySystemNumberFailed, + TestResultActions.fetchSelectedTestResultFailed, + ReferenceDataActions.fetchReferenceDataFailed, + ReferenceDataActions.fetchReferenceDataByKeyFailed, + fetchSearchResultFailed, + failureMethod + ), + on( + GlobalErrorActions.setErrors, + TestResultActions.updateTestResultFailed, + TestResultActions.createTestResultFailed, + (state, { errors }) => ({ + ...state, + errors: [..._.uniqWith(errors, (a, b) => _.isEqual(a.error, b.error))], + }) + ), + on(GlobalErrorActions.patchErrors, (state, { errors }) => ({ ...state, errors: [...state.errors, ...errors] })), + on(createVehicleRecordFailure, (state, action) => ({ errors: [...state.errors, { error: action.error }] })) ); function successMethod(state: GlobalErrorState) { - return { ...state, errors: [] }; + return { ...state, errors: [] }; } // eslint-disable-next-line @typescript-eslint/no-explicit-any function failureMethod(state: GlobalErrorState, errorMessage: { error: any; anchorLink?: any }) { - return { ...state, errors: [...state.errors, { error: errorMessage.error, anchorLink: errorMessage.anchorLink }] }; + return { ...state, errors: [...state.errors, { error: errorMessage.error, anchorLink: errorMessage.anchorLink }] }; } diff --git a/src/app/store/global-error/selectors/global-error.selectors.spec.ts b/src/app/store/global-error/selectors/global-error.selectors.spec.ts index 3a5c13eb0b..f92dff0ba5 100644 --- a/src/app/store/global-error/selectors/global-error.selectors.spec.ts +++ b/src/app/store/global-error/selectors/global-error.selectors.spec.ts @@ -2,11 +2,11 @@ import { GlobalErrorState, initialGlobalErrorState } from '@store/global-error/r import { getErrorMessage } from '@store/global-error/selectors/global-error.selectors'; describe('Global Error Selectors', () => { - describe('getErrorMessage', () => { - it('should return the correct error', () => { - const state: GlobalErrorState = { ...initialGlobalErrorState, errors: [{ error: 'err' }] }; - const selectedState = getErrorMessage.projector(state); - expect(selectedState).toEqual(state.errors); - }); - }); + describe('getErrorMessage', () => { + it('should return the correct error', () => { + const state: GlobalErrorState = { ...initialGlobalErrorState, errors: [{ error: 'err' }] }; + const selectedState = getErrorMessage.projector(state); + expect(selectedState).toEqual(state.errors); + }); + }); }); diff --git a/src/app/store/global-error/selectors/global-error.selectors.ts b/src/app/store/global-error/selectors/global-error.selectors.ts index 17d5d1975c..d55d836426 100644 --- a/src/app/store/global-error/selectors/global-error.selectors.ts +++ b/src/app/store/global-error/selectors/global-error.selectors.ts @@ -2,5 +2,5 @@ import { createSelector } from '@ngrx/store'; import { getGlobalErrorState } from '@store/global-error/reducers/global-error-service.reducer'; export const getErrorMessage = createSelector(getGlobalErrorState, (state) => { - return state.errors; + return state.errors; }); diff --git a/src/app/store/global-warning/actions/global-warning.actions.ts b/src/app/store/global-warning/actions/global-warning.actions.ts index 5a2baa8739..21a6d87d61 100644 --- a/src/app/store/global-warning/actions/global-warning.actions.ts +++ b/src/app/store/global-warning/actions/global-warning.actions.ts @@ -2,4 +2,7 @@ import { GlobalWarning } from '@core/components/global-warning/global-warning.in import { createAction, props } from '@ngrx/store'; export const clearWarning = createAction('[Global Warning Service] Clear Warning'); -export const setWarnings = createAction('[Global Warning Service] Set warnings', props<{ warnings: GlobalWarning[] }>()); +export const setWarnings = createAction( + '[Global Warning Service] Set warnings', + props<{ warnings: GlobalWarning[] }>() +); diff --git a/src/app/store/global-warning/global-warning-state.module.ts b/src/app/store/global-warning/global-warning-state.module.ts index 91df5c65c7..ce1567e72d 100644 --- a/src/app/store/global-warning/global-warning-state.module.ts +++ b/src/app/store/global-warning/global-warning-state.module.ts @@ -1,10 +1,13 @@ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { StoreModule } from '@ngrx/store'; -import { globalWarningReducer, STORE_FEATURE_GLOBAL_WARNING_KEY } from '@store/global-warning/reducers/global-warning-service.reducers'; +import { + STORE_FEATURE_GLOBAL_WARNING_KEY, + globalWarningReducer, +} from '@store/global-warning/reducers/global-warning-service.reducers'; @NgModule({ - declarations: [], - imports: [CommonModule, StoreModule.forFeature(STORE_FEATURE_GLOBAL_WARNING_KEY, globalWarningReducer)], + declarations: [], + imports: [CommonModule, StoreModule.forFeature(STORE_FEATURE_GLOBAL_WARNING_KEY, globalWarningReducer)], }) export class GlobalWarningStateModule {} diff --git a/src/app/store/global-warning/reducers/global-warning-service.reducer.spec.ts b/src/app/store/global-warning/reducers/global-warning-service.reducer.spec.ts index cab1a25cdb..7cab4b262b 100644 --- a/src/app/store/global-warning/reducers/global-warning-service.reducer.spec.ts +++ b/src/app/store/global-warning/reducers/global-warning-service.reducer.spec.ts @@ -1,49 +1,55 @@ -import { routerNavigatedAction, RouterNavigatedPayload, SerializedRouterStateSnapshot } from '@ngrx/router-store'; -import { globalWarningReducer, initialGlobalWarningState } from '@store/global-warning/reducers/global-warning-service.reducers'; -import { setWarnings, clearWarning } from '../actions/global-warning.actions'; +import { RouterNavigatedPayload, SerializedRouterStateSnapshot, routerNavigatedAction } from '@ngrx/router-store'; +import { + globalWarningReducer, + initialGlobalWarningState, +} from '@store/global-warning/reducers/global-warning-service.reducers'; +import { clearWarning, setWarnings } from '../actions/global-warning.actions'; describe('Global Warning Reducer', () => { - describe('unknown action', () => { - it('should return the default state', () => { - const action = { - type: 'Unknown', - }; - - const state = globalWarningReducer(initialGlobalWarningState, action); - expect(state).toBe(initialGlobalWarningState); - }); - }); - - describe('Success action', () => { - it.each([clearWarning])('should reset the warning state', (actionMethod) => { - const newState = { ...initialGlobalWarningState, warnings: [] }; - // all props must be supplied here - const action = actionMethod(); - const state = globalWarningReducer(initialGlobalWarningState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - - it.each([routerNavigatedAction])('should reset the warning state', (actionMethod) => { - const newState = { ...initialGlobalWarningState, warnings: [] }; - // all props must be supplied here - const action = actionMethod({ payload: >{} }); - const state = globalWarningReducer(initialGlobalWarningState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('setWarnings', () => { - it('should replace existing warnings with new ones', () => { - const newState = { ...initialGlobalWarningState, warnings: [{ warning: 'some warning', anchorLink: '' }] }; - const action = setWarnings({ warnings: [{ warning: 'some warning', anchorLink: '' }] }); - const state = globalWarningReducer({ ...initialGlobalWarningState, warnings: [{ warning: 'old warning', anchorLink: '' }] }, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); + describe('unknown action', () => { + it('should return the default state', () => { + const action = { + type: 'Unknown', + }; + + const state = globalWarningReducer(initialGlobalWarningState, action); + expect(state).toBe(initialGlobalWarningState); + }); + }); + + describe('Success action', () => { + it.each([clearWarning])('should reset the warning state', (actionMethod) => { + const newState = { ...initialGlobalWarningState, warnings: [] }; + // all props must be supplied here + const action = actionMethod(); + const state = globalWarningReducer(initialGlobalWarningState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + + it.each([routerNavigatedAction])('should reset the warning state', (actionMethod) => { + const newState = { ...initialGlobalWarningState, warnings: [] }; + // all props must be supplied here + const action = actionMethod({ payload: >{} }); + const state = globalWarningReducer(initialGlobalWarningState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('setWarnings', () => { + it('should replace existing warnings with new ones', () => { + const newState = { ...initialGlobalWarningState, warnings: [{ warning: 'some warning', anchorLink: '' }] }; + const action = setWarnings({ warnings: [{ warning: 'some warning', anchorLink: '' }] }); + const state = globalWarningReducer( + { ...initialGlobalWarningState, warnings: [{ warning: 'old warning', anchorLink: '' }] }, + action + ); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); }); diff --git a/src/app/store/global-warning/reducers/global-warning-service.reducers.ts b/src/app/store/global-warning/reducers/global-warning-service.reducers.ts index 71d18c2c29..92465c28cc 100644 --- a/src/app/store/global-warning/reducers/global-warning-service.reducers.ts +++ b/src/app/store/global-warning/reducers/global-warning-service.reducers.ts @@ -1,18 +1,16 @@ -import { routerNavigatedAction } from '@ngrx/router-store'; -import { - createFeatureSelector, createReducer, createSelector, on, -} from '@ngrx/store'; import { GlobalWarning } from '@core/components/global-warning/global-warning.interface'; +import { routerNavigatedAction } from '@ngrx/router-store'; +import { createFeatureSelector, createReducer, createSelector, on } from '@ngrx/store'; import * as GlobalWarningActions from '../actions/global-warning.actions'; export const STORE_FEATURE_GLOBAL_WARNING_KEY = 'globalWarning'; export interface GlobalWarningState { - warnings: Array; + warnings: Array; } export const initialGlobalWarningState: GlobalWarningState = { - warnings: [], + warnings: [], }; export const getGlobalWarningState = createFeatureSelector(STORE_FEATURE_GLOBAL_WARNING_KEY); @@ -20,20 +18,20 @@ export const getGlobalWarningState = createFeatureSelector(S export const globalWarningState = createSelector(getGlobalWarningState, (state) => state.warnings); export const globalWarningReducer = createReducer( - initialGlobalWarningState, - on( - GlobalWarningActions.clearWarning, - routerNavigatedAction, - - successMethod, - ), - - on(GlobalWarningActions.setWarnings, (state, { warnings }) => ({ - ...state, - warnings: [...warnings], - })), + initialGlobalWarningState, + on( + GlobalWarningActions.clearWarning, + routerNavigatedAction, + + successMethod + ), + + on(GlobalWarningActions.setWarnings, (state, { warnings }) => ({ + ...state, + warnings: [...warnings], + })) ); function successMethod(state: GlobalWarningState) { - return { ...state, warnings: [] }; + return { ...state, warnings: [] }; } diff --git a/src/app/store/index.ts b/src/app/store/index.ts index 1b7d8044cb..86b1c06b1c 100644 --- a/src/app/store/index.ts +++ b/src/app/store/index.ts @@ -1,88 +1,107 @@ import { ActionReducerMap } from '@ngrx/store'; // eslint-disable-next-line import/no-cycle import { - globalErrorReducer, - GlobalErrorState, - initialGlobalErrorState, - STORE_FEATURE_GLOBAL_ERROR_KEY, + GlobalErrorState, + STORE_FEATURE_GLOBAL_ERROR_KEY, + globalErrorReducer, + initialGlobalErrorState, } from '@store/global-error/reducers/global-error-service.reducer'; import { - initialSpinnerState, spinnerReducer, SpinnerState, STORE_FEATURE_SPINNER_KEY, + STORE_FEATURE_SPINNER_KEY, + SpinnerState, + initialSpinnerState, + spinnerReducer, } from '@store/spinner/reducers/spinner.reducer'; +import { DefectsState, STORE_FEATURE_DEFECTS_KEY, defectsReducer, initialDefectsState } from './defects'; import { - defectsReducer, DefectsState, initialDefectsState, STORE_FEATURE_DEFECTS_KEY, -} from './defects'; -import { - initialReferenceDataState, referenceDataReducer, ReferenceDataState, STORE_FEATURE_REFERENCE_DATA_KEY, + ReferenceDataState, + STORE_FEATURE_REFERENCE_DATA_KEY, + initialReferenceDataState, + referenceDataReducer, } from './reference-data'; import { - initialRequiredStandardsState, requiredStandardsReducer, RequiredStandardState, STORE_FEATURE_REQUIRED_STANDARDS_KEY, + RequiredStandardState, + STORE_FEATURE_REQUIRED_STANDARDS_KEY, + initialRequiredStandardsState, + requiredStandardsReducer, } from './required-standards/reducers/required-standards.reducer'; import { - initialTechSearchResultState, - SearchResultState, - STORE_FEATURE_SEARCH_TECH_RESULTS_KEY, - techSearchResultReducer, + STORE_FEATURE_SEARCH_TECH_RESULTS_KEY, + SearchResultState, + initialTechSearchResultState, + techSearchResultReducer, } from './tech-record-search/reducer/tech-record-search.reducer'; import { - initialState as initialTechnicalRecordsState, - STORE_FEATURE_TECHNICAL_RECORDS_KEY, - TechnicalRecordServiceState, - vehicleTechRecordReducer, + STORE_FEATURE_TECHNICAL_RECORDS_KEY, + TechnicalRecordServiceState, + initialState as initialTechnicalRecordsState, + vehicleTechRecordReducer, } from './technical-records/reducers/technical-record-service.reducer'; import { - initialTestResultsState, STORE_FEATURE_TEST_RESULTS_KEY, testResultsReducer, TestResultsState, + STORE_FEATURE_TEST_RESULTS_KEY, + TestResultsState, + initialTestResultsState, + testResultsReducer, } from './test-records'; import { - initialTestStationsState, STORE_FEATURE_TEST_STATIONS_KEY, testStationsReducer, TestStationsState, + STORE_FEATURE_TEST_STATIONS_KEY, + TestStationsState, + initialTestStationsState, + testStationsReducer, } from './test-stations'; import { - initialTestTypeState, STORE_FEATURE_TEST_TYPES_KEY, testTypesReducer, TestTypeState, + STORE_FEATURE_TEST_TYPES_KEY, + TestTypeState, + initialTestTypeState, + testTypesReducer, } from './test-types/reducers/test-types.reducer'; import { - initialState as initialUserState, STORE_FEATURE_USER_KEY, userServiceReducer, UserServiceState, + STORE_FEATURE_USER_KEY, + UserServiceState, + initialState as initialUserState, + userServiceReducer, } from './user/user-service.reducer'; export interface State { - [STORE_FEATURE_DEFECTS_KEY]: DefectsState; - [STORE_FEATURE_GLOBAL_ERROR_KEY]: GlobalErrorState; - [STORE_FEATURE_REFERENCE_DATA_KEY]: ReferenceDataState; - [STORE_FEATURE_SPINNER_KEY]: SpinnerState; - [STORE_FEATURE_TECHNICAL_RECORDS_KEY]: TechnicalRecordServiceState; - [STORE_FEATURE_TEST_RESULTS_KEY]: TestResultsState; - [STORE_FEATURE_TEST_STATIONS_KEY]: TestStationsState; - [STORE_FEATURE_TEST_TYPES_KEY]: TestTypeState; - [STORE_FEATURE_USER_KEY]: UserServiceState; - [STORE_FEATURE_SEARCH_TECH_RESULTS_KEY]: SearchResultState; - [STORE_FEATURE_REQUIRED_STANDARDS_KEY]: RequiredStandardState; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - router?: any; + [STORE_FEATURE_DEFECTS_KEY]: DefectsState; + [STORE_FEATURE_GLOBAL_ERROR_KEY]: GlobalErrorState; + [STORE_FEATURE_REFERENCE_DATA_KEY]: ReferenceDataState; + [STORE_FEATURE_SPINNER_KEY]: SpinnerState; + [STORE_FEATURE_TECHNICAL_RECORDS_KEY]: TechnicalRecordServiceState; + [STORE_FEATURE_TEST_RESULTS_KEY]: TestResultsState; + [STORE_FEATURE_TEST_STATIONS_KEY]: TestStationsState; + [STORE_FEATURE_TEST_TYPES_KEY]: TestTypeState; + [STORE_FEATURE_USER_KEY]: UserServiceState; + [STORE_FEATURE_SEARCH_TECH_RESULTS_KEY]: SearchResultState; + [STORE_FEATURE_REQUIRED_STANDARDS_KEY]: RequiredStandardState; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + router?: any; } export const initialAppState = { - [STORE_FEATURE_DEFECTS_KEY]: initialDefectsState, - [STORE_FEATURE_GLOBAL_ERROR_KEY]: initialGlobalErrorState, - [STORE_FEATURE_REFERENCE_DATA_KEY]: initialReferenceDataState, - [STORE_FEATURE_SPINNER_KEY]: initialSpinnerState, - [STORE_FEATURE_TECHNICAL_RECORDS_KEY]: initialTechnicalRecordsState, - [STORE_FEATURE_TEST_RESULTS_KEY]: initialTestResultsState, - [STORE_FEATURE_TEST_STATIONS_KEY]: initialTestStationsState, - [STORE_FEATURE_TEST_TYPES_KEY]: initialTestTypeState, - [STORE_FEATURE_USER_KEY]: initialUserState, - [STORE_FEATURE_SEARCH_TECH_RESULTS_KEY]: initialTechSearchResultState, - [STORE_FEATURE_REQUIRED_STANDARDS_KEY]: initialRequiredStandardsState, + [STORE_FEATURE_DEFECTS_KEY]: initialDefectsState, + [STORE_FEATURE_GLOBAL_ERROR_KEY]: initialGlobalErrorState, + [STORE_FEATURE_REFERENCE_DATA_KEY]: initialReferenceDataState, + [STORE_FEATURE_SPINNER_KEY]: initialSpinnerState, + [STORE_FEATURE_TECHNICAL_RECORDS_KEY]: initialTechnicalRecordsState, + [STORE_FEATURE_TEST_RESULTS_KEY]: initialTestResultsState, + [STORE_FEATURE_TEST_STATIONS_KEY]: initialTestStationsState, + [STORE_FEATURE_TEST_TYPES_KEY]: initialTestTypeState, + [STORE_FEATURE_USER_KEY]: initialUserState, + [STORE_FEATURE_SEARCH_TECH_RESULTS_KEY]: initialTechSearchResultState, + [STORE_FEATURE_REQUIRED_STANDARDS_KEY]: initialRequiredStandardsState, }; export const reducers: ActionReducerMap = { - [STORE_FEATURE_DEFECTS_KEY]: defectsReducer, - [STORE_FEATURE_GLOBAL_ERROR_KEY]: globalErrorReducer, - [STORE_FEATURE_REFERENCE_DATA_KEY]: referenceDataReducer, - [STORE_FEATURE_SPINNER_KEY]: spinnerReducer, - [STORE_FEATURE_TECHNICAL_RECORDS_KEY]: vehicleTechRecordReducer, - [STORE_FEATURE_TEST_RESULTS_KEY]: testResultsReducer, - [STORE_FEATURE_TEST_STATIONS_KEY]: testStationsReducer, - [STORE_FEATURE_TEST_TYPES_KEY]: testTypesReducer, - [STORE_FEATURE_USER_KEY]: userServiceReducer, - [STORE_FEATURE_SEARCH_TECH_RESULTS_KEY]: techSearchResultReducer, - [STORE_FEATURE_REQUIRED_STANDARDS_KEY]: requiredStandardsReducer, + [STORE_FEATURE_DEFECTS_KEY]: defectsReducer, + [STORE_FEATURE_GLOBAL_ERROR_KEY]: globalErrorReducer, + [STORE_FEATURE_REFERENCE_DATA_KEY]: referenceDataReducer, + [STORE_FEATURE_SPINNER_KEY]: spinnerReducer, + [STORE_FEATURE_TECHNICAL_RECORDS_KEY]: vehicleTechRecordReducer, + [STORE_FEATURE_TEST_RESULTS_KEY]: testResultsReducer, + [STORE_FEATURE_TEST_STATIONS_KEY]: testStationsReducer, + [STORE_FEATURE_TEST_TYPES_KEY]: testTypesReducer, + [STORE_FEATURE_USER_KEY]: userServiceReducer, + [STORE_FEATURE_SEARCH_TECH_RESULTS_KEY]: techSearchResultReducer, + [STORE_FEATURE_REQUIRED_STANDARDS_KEY]: requiredStandardsReducer, }; diff --git a/src/app/store/reference-data/actions/reference-data.actions.spec.ts b/src/app/store/reference-data/actions/reference-data.actions.spec.ts index 7e61988dd9..e70a535b9b 100644 --- a/src/app/store/reference-data/actions/reference-data.actions.spec.ts +++ b/src/app/store/reference-data/actions/reference-data.actions.spec.ts @@ -1,46 +1,54 @@ import { - fetchReferenceData, - fetchReferenceDataSuccess, - fetchReferenceDataFailed, - fetchReferenceDataByKey, - fetchReferenceDataByKeyFailed, - fetchReferenceDataByKeySuccess, - fetchReasonsForAbandoning, - fetchReferenceDataByKeySearch, - fetchReferenceDataByKeySearchFailed, - fetchReferenceDataByKeySearchSuccess, - fetchTyreReferenceDataByKeySearch, - fetchTyreReferenceDataByKeySearchFailed, - fetchTyreReferenceDataByKeySearchSuccess, - addSearchInformation, - fetchReferenceDataAudit, - fetchReferenceDataAuditSuccess, - fetchReferenceDataAuditFailed, + addSearchInformation, + fetchReasonsForAbandoning, + fetchReferenceData, + fetchReferenceDataAudit, + fetchReferenceDataAuditFailed, + fetchReferenceDataAuditSuccess, + fetchReferenceDataByKey, + fetchReferenceDataByKeyFailed, + fetchReferenceDataByKeySearch, + fetchReferenceDataByKeySearchFailed, + fetchReferenceDataByKeySearchSuccess, + fetchReferenceDataByKeySuccess, + fetchReferenceDataFailed, + fetchReferenceDataSuccess, + fetchTyreReferenceDataByKeySearch, + fetchTyreReferenceDataByKeySearchFailed, + fetchTyreReferenceDataByKeySearchSuccess, } from './reference-data.actions'; describe('Test Result Actions', () => { - it('should return correct types', () => { - expect(fetchReferenceData.type).toBe('[API/reference-data] Fetch all of ResourceType'); - expect(fetchReferenceDataSuccess.type).toBe('[API/reference-data] Fetch all of ResourceType Success'); - expect(fetchReferenceDataFailed.type).toBe('[API/reference-data] Fetch all of ResourceType Failed'); + it('should return correct types', () => { + expect(fetchReferenceData.type).toBe('[API/reference-data] Fetch all of ResourceType'); + expect(fetchReferenceDataSuccess.type).toBe('[API/reference-data] Fetch all of ResourceType Success'); + expect(fetchReferenceDataFailed.type).toBe('[API/reference-data] Fetch all of ResourceType Failed'); - expect(fetchReferenceDataAudit.type).toBe('[API/reference-data] Fetch all of Audit ResourceType'); - expect(fetchReferenceDataAuditSuccess.type).toBe('[API/reference-data] Fetch all of Audit ResourceType Success'); - expect(fetchReferenceDataAuditFailed.type).toBe('[API/reference-data] Fetch all of Audit ResourceType Failed'); + expect(fetchReferenceDataAudit.type).toBe('[API/reference-data] Fetch all of Audit ResourceType'); + expect(fetchReferenceDataAuditSuccess.type).toBe('[API/reference-data] Fetch all of Audit ResourceType Success'); + expect(fetchReferenceDataAuditFailed.type).toBe('[API/reference-data] Fetch all of Audit ResourceType Failed'); - expect(fetchReferenceDataByKey.type).toBe('[API/reference-data] Fetch ResourceType by Key'); - expect(fetchReferenceDataByKeySuccess.type).toBe('[API/reference-data] Fetch ResourceType by Key Success'); - expect(fetchReferenceDataByKeyFailed.type).toBe('[API/reference-data] Fetch ResourceType by Key Failed'); - expect(fetchReasonsForAbandoning.type).toBe('[API/reference-data] Fetch reasons for abandoning'); + expect(fetchReferenceDataByKey.type).toBe('[API/reference-data] Fetch ResourceType by Key'); + expect(fetchReferenceDataByKeySuccess.type).toBe('[API/reference-data] Fetch ResourceType by Key Success'); + expect(fetchReferenceDataByKeyFailed.type).toBe('[API/reference-data] Fetch ResourceType by Key Failed'); + expect(fetchReasonsForAbandoning.type).toBe('[API/reference-data] Fetch reasons for abandoning'); - expect(fetchReferenceDataByKeySearch.type).toBe('[API/reference-data] Fetch ResourceType by Key and Search'); - expect(fetchReferenceDataByKeySearchSuccess.type).toBe('[API/reference-data] Fetch ResourceType by Key and search Success'); - expect(fetchReferenceDataByKeySearchFailed.type).toBe('[API/reference-data] Fetch ResourceType by Key and search Failed'); + expect(fetchReferenceDataByKeySearch.type).toBe('[API/reference-data] Fetch ResourceType by Key and Search'); + expect(fetchReferenceDataByKeySearchSuccess.type).toBe( + '[API/reference-data] Fetch ResourceType by Key and search Success' + ); + expect(fetchReferenceDataByKeySearchFailed.type).toBe( + '[API/reference-data] Fetch ResourceType by Key and search Failed' + ); - expect(fetchTyreReferenceDataByKeySearch.type).toBe('[API/reference-data] Fetch tyre by filter and term'); - expect(fetchTyreReferenceDataByKeySearchSuccess.type).toBe('[API/reference-data] Fetch tyre by filter and term Success'); - expect(fetchTyreReferenceDataByKeySearchFailed.type).toBe('[API/reference-data] Fetch tyre by filter and term Failed'); + expect(fetchTyreReferenceDataByKeySearch.type).toBe('[API/reference-data] Fetch tyre by filter and term'); + expect(fetchTyreReferenceDataByKeySearchSuccess.type).toBe( + '[API/reference-data] Fetch tyre by filter and term Success' + ); + expect(fetchTyreReferenceDataByKeySearchFailed.type).toBe( + '[API/reference-data] Fetch tyre by filter and term Failed' + ); - expect(addSearchInformation.type).toBe('[API/reference-data] Add Search Information to state'); - }); + expect(addSearchInformation.type).toBe('[API/reference-data] Add Search Information to state'); + }); }); diff --git a/src/app/store/reference-data/actions/reference-data.actions.ts b/src/app/store/reference-data/actions/reference-data.actions.ts index 1522d33868..5b2090e20b 100644 --- a/src/app/store/reference-data/actions/reference-data.actions.ts +++ b/src/app/store/reference-data/actions/reference-data.actions.ts @@ -5,131 +5,155 @@ import { createAction, props } from '@ngrx/store'; const prefix = '[API/reference-data]'; interface featureError extends GlobalError { - resourceType: ReferenceDataResourceType; + resourceType: ReferenceDataResourceType; } export const fetchReferenceData = createAction( - '[API/reference-data] Fetch all of ResourceType', - props<{ resourceType: ReferenceDataResourceType; paginationToken?: string }>(), + '[API/reference-data] Fetch all of ResourceType', + props<{ resourceType: ReferenceDataResourceType; paginationToken?: string }>() ); export const fetchReferenceDataSuccess = createAction( - '[API/reference-data] Fetch all of ResourceType Success', - props<{ resourceType: ReferenceDataResourceType; payload: Array; paginated: boolean }>(), + '[API/reference-data] Fetch all of ResourceType Success', + props<{ resourceType: ReferenceDataResourceType; payload: Array; paginated: boolean }>() +); +export const fetchReferenceDataFailed = createAction( + '[API/reference-data] Fetch all of ResourceType Failed', + props() ); -export const fetchReferenceDataFailed = createAction('[API/reference-data] Fetch all of ResourceType Failed', props()); export const fetchReferenceDataAudit = createAction( - '[API/reference-data] Fetch all of Audit ResourceType', - props<{ resourceType: ReferenceDataResourceType; paginationToken?: string }>(), + '[API/reference-data] Fetch all of Audit ResourceType', + props<{ resourceType: ReferenceDataResourceType; paginationToken?: string }>() ); export const fetchReferenceDataAuditSuccess = createAction( - '[API/reference-data] Fetch all of Audit ResourceType Success', - props<{ resourceType: ReferenceDataResourceType; payload: Array; paginated: boolean }>(), + '[API/reference-data] Fetch all of Audit ResourceType Success', + props<{ resourceType: ReferenceDataResourceType; payload: Array; paginated: boolean }>() +); +export const fetchReferenceDataAuditFailed = createAction( + '[API/reference-data] Fetch all of Audit ResourceType Failed', + props() ); -export const fetchReferenceDataAuditFailed = createAction('[API/reference-data] Fetch all of Audit ResourceType Failed', props()); export const fetchReferenceDataByKey = createAction( - '[API/reference-data] Fetch ResourceType by Key', - props<{ resourceType: ReferenceDataResourceType; resourceKey: string | number }>(), + '[API/reference-data] Fetch ResourceType by Key', + props<{ resourceType: ReferenceDataResourceType; resourceKey: string | number }>() ); export const fetchReferenceDataByKeySuccess = createAction( - '[API/reference-data] Fetch ResourceType by Key Success', - props<{ - resourceType: ReferenceDataResourceType; - resourceKey: string | number; - payload: ReferenceDataModelBase; - }>(), -); -export const fetchReferenceDataByKeyFailed = createAction('[API/reference-data] Fetch ResourceType by Key Failed', props()); + '[API/reference-data] Fetch ResourceType by Key Success', + props<{ + resourceType: ReferenceDataResourceType; + resourceKey: string | number; + payload: ReferenceDataModelBase; + }>() +); +export const fetchReferenceDataByKeyFailed = createAction( + '[API/reference-data] Fetch ResourceType by Key Failed', + props() +); export const fetchReferenceDataByKeySearch = createAction( - '[API/reference-data] Fetch ResourceType by Key and Search', - props<{ resourceType: ReferenceDataResourceType; resourceKey: string | number }>(), + '[API/reference-data] Fetch ResourceType by Key and Search', + props<{ resourceType: ReferenceDataResourceType; resourceKey: string | number }>() ); export const fetchReferenceDataByKeySearchSuccess = createAction( - '[API/reference-data] Fetch ResourceType by Key and search Success', - props<{ - resourceType: ReferenceDataResourceType; - resourceKey: string | number; - payload: Array; - }>(), + '[API/reference-data] Fetch ResourceType by Key and search Success', + props<{ + resourceType: ReferenceDataResourceType; + resourceKey: string | number; + payload: Array; + }>() ); export const fetchReferenceDataByKeySearchFailed = createAction( - '[API/reference-data] Fetch ResourceType by Key and search Failed', - props(), + '[API/reference-data] Fetch ResourceType by Key and search Failed', + props() ); export const fetchTyreReferenceDataByKeySearch = createAction( - '[API/reference-data] Fetch tyre by filter and term', - props<{ searchFilter: string; searchTerm: string }>(), + '[API/reference-data] Fetch tyre by filter and term', + props<{ searchFilter: string; searchTerm: string }>() ); export const fetchTyreReferenceDataByKeySearchSuccess = createAction( - '[API/reference-data] Fetch tyre by filter and term Success', - props<{ - resourceType: ReferenceDataResourceType; - payload: Array; - }>(), + '[API/reference-data] Fetch tyre by filter and term Success', + props<{ + resourceType: ReferenceDataResourceType; + payload: Array; + }>() ); export const fetchTyreReferenceDataByKeySearchFailed = createAction( - '[API/reference-data] Fetch tyre by filter and term Failed', - props(), + '[API/reference-data] Fetch tyre by filter and term Failed', + props() ); export const addSearchInformation = createAction( - '[API/reference-data] Add Search Information to state', - props<{ - filter: string; - term: string; - }>(), + '[API/reference-data] Add Search Information to state', + props<{ + filter: string; + term: string; + }>() ); export const removeTyreSearch = createAction('[API/reference-data] Remove search return from state'); export const removeReferenceDataByKey = createAction( - '[API/reference-data] Remove item from state', - props<{ - resourceType: ReferenceDataResourceType; - resourceKey: string; - }>(), + '[API/reference-data] Remove item from state', + props<{ + resourceType: ReferenceDataResourceType; + resourceKey: string; + }>() ); export const fetchReasonsForAbandoning = createAction('[API/reference-data] Fetch reasons for abandoning'); export const createReferenceDataItem = createAction( - `${prefix} createReferenceDataItem`, - props<{ - resourceType: ReferenceDataResourceType; - resourceKey: string; - payload: ReferenceDataModelBase; - }>(), -); -export const createReferenceDataItemSuccess = createAction(`${prefix} createReferenceDataItemSuccess`, props<{ result: ReferenceDataModelBase }>()); -export const createReferenceDataItemFailure = createAction(`${prefix} createReferenceDataItemFailure`, props()); + `${prefix} createReferenceDataItem`, + props<{ + resourceType: ReferenceDataResourceType; + resourceKey: string; + payload: ReferenceDataModelBase; + }>() +); +export const createReferenceDataItemSuccess = createAction( + `${prefix} createReferenceDataItemSuccess`, + props<{ result: ReferenceDataModelBase }>() +); +export const createReferenceDataItemFailure = createAction( + `${prefix} createReferenceDataItemFailure`, + props() +); export const amendReferenceDataItem = createAction( - `${prefix} amendReferenceDataItem`, - props<{ - resourceType: ReferenceDataResourceType; - resourceKey: string; - payload: ReferenceDataModelBase; - }>(), -); -export const amendReferenceDataItemSuccess = createAction(`${prefix} amendReferenceDataItemSuccess`, props<{ result: ReferenceDataModelBase }>()); -export const amendReferenceDataItemFailure = createAction(`${prefix} amendReferenceDataItemFailure`, props()); + `${prefix} amendReferenceDataItem`, + props<{ + resourceType: ReferenceDataResourceType; + resourceKey: string; + payload: ReferenceDataModelBase; + }>() +); +export const amendReferenceDataItemSuccess = createAction( + `${prefix} amendReferenceDataItemSuccess`, + props<{ result: ReferenceDataModelBase }>() +); +export const amendReferenceDataItemFailure = createAction( + `${prefix} amendReferenceDataItemFailure`, + props() +); export const deleteReferenceDataItem = createAction( - `${prefix} deleteReferenceDataItem`, - props<{ - resourceType: ReferenceDataResourceType; - resourceKey: string; - reason: string; - }>(), + `${prefix} deleteReferenceDataItem`, + props<{ + resourceType: ReferenceDataResourceType; + resourceKey: string; + reason: string; + }>() ); export const deleteReferenceDataItemSuccess = createAction( - `${prefix} deleteReferenceDataItemSuccess`, - props<{ - resourceType: ReferenceDataResourceType; - resourceKey: string; - }>(), + `${prefix} deleteReferenceDataItemSuccess`, + props<{ + resourceType: ReferenceDataResourceType; + resourceKey: string; + }>() +); +export const deleteReferenceDataItemFailure = createAction( + `${prefix} deleteReferenceDataItemFailure`, + props() ); -export const deleteReferenceDataItemFailure = createAction(`${prefix} deleteReferenceDataItemFailure`, props()); diff --git a/src/app/store/reference-data/effects/operators/reference-data.operators.spec.ts b/src/app/store/reference-data/effects/operators/reference-data.operators.spec.ts index e84036102b..e06a55690b 100644 --- a/src/app/store/reference-data/effects/operators/reference-data.operators.spec.ts +++ b/src/app/store/reference-data/effects/operators/reference-data.operators.spec.ts @@ -3,51 +3,51 @@ import { of, take } from 'rxjs'; import { handleNotFound, sortReferenceData } from './reference-data.operators'; describe('Reference data operators', () => { - describe('handleNotFound.prototype.name', () => { - it('should emit source observable when there is data', (done) => { - of({ data: [{ resourceType: 'type', resourceKey: 'key' }] }) - .pipe(take(1), handleNotFound('test')) - .subscribe({ - next: (val) => { - expect(val).toEqual({ data: [{ resourceType: 'type', resourceKey: 'key' }] }); - done(); - }, - }); - }); - it('should throw an error if data is empty', (done) => { - of({ data: [] }) - .pipe(take(1), handleNotFound('test')) - .subscribe({ - error: (e) => { - expect(e.message).toBe('Reference data not found for resource type test'); - done(); - }, - }); - }); - }); + describe('handleNotFound.prototype.name', () => { + it('should emit source observable when there is data', (done) => { + of({ data: [{ resourceType: 'type', resourceKey: 'key' }] }) + .pipe(take(1), handleNotFound('test')) + .subscribe({ + next: (val) => { + expect(val).toEqual({ data: [{ resourceType: 'type', resourceKey: 'key' }] }); + done(); + }, + }); + }); + it('should throw an error if data is empty', (done) => { + of({ data: [] }) + .pipe(take(1), handleNotFound('test')) + .subscribe({ + error: (e) => { + expect(e.message).toBe('Reference data not found for resource type test'); + done(); + }, + }); + }); + }); - describe('sortReferenceData.prototype.name', () => { - it('should sort strings', (done) => { - of({ - data: [ - { resourceType: ReferenceDataResourceType.User, resourceKey: 2, name: 'last name' }, - { resourceType: ReferenceDataResourceType.User, resourceKey: 3, name: 'some name' }, - { resourceType: ReferenceDataResourceType.User, resourceKey: 1, name: 'a name' }, - ], - }) - .pipe(take(1), sortReferenceData(ReferenceDataResourceType.User)) - .subscribe({ - next: (val) => { - expect(val).toEqual({ - data: [ - { resourceType: ReferenceDataResourceType.User, resourceKey: 1, name: 'a name' }, - { resourceType: ReferenceDataResourceType.User, resourceKey: 2, name: 'last name' }, - { resourceType: ReferenceDataResourceType.User, resourceKey: 3, name: 'some name' }, - ], - }); - done(); - }, - }); - }); - }); + describe('sortReferenceData.prototype.name', () => { + it('should sort strings', (done) => { + of({ + data: [ + { resourceType: ReferenceDataResourceType.User, resourceKey: 2, name: 'last name' }, + { resourceType: ReferenceDataResourceType.User, resourceKey: 3, name: 'some name' }, + { resourceType: ReferenceDataResourceType.User, resourceKey: 1, name: 'a name' }, + ], + }) + .pipe(take(1), sortReferenceData(ReferenceDataResourceType.User)) + .subscribe({ + next: (val) => { + expect(val).toEqual({ + data: [ + { resourceType: ReferenceDataResourceType.User, resourceKey: 1, name: 'a name' }, + { resourceType: ReferenceDataResourceType.User, resourceKey: 2, name: 'last name' }, + { resourceType: ReferenceDataResourceType.User, resourceKey: 3, name: 'some name' }, + ], + }); + done(); + }, + }); + }); + }); }); diff --git a/src/app/store/reference-data/effects/operators/reference-data.operators.ts b/src/app/store/reference-data/effects/operators/reference-data.operators.ts index 3f94c6f08c..bb6b35415a 100644 --- a/src/app/store/reference-data/effects/operators/reference-data.operators.ts +++ b/src/app/store/reference-data/effects/operators/reference-data.operators.ts @@ -8,66 +8,66 @@ import { Observable } from 'rxjs'; * @returns emitted source value or error if response is equivalent to not found. */ export function handleNotFound(...args: unknown[]) { - // eslint-disable-next-line func-names - return function (source: Observable): Observable { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const isEmpty = (val: any) => !Object.keys(val).length || (Object.prototype.hasOwnProperty.call(val, 'data') && !val.data.length); - return new Observable((subscriber) => { - source.subscribe({ - next: (val) => { - if (val && isEmpty(val)) { - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - subscriber.error(new Error(`Reference data not found for resource type ${args}`)); - } + // eslint-disable-next-line func-names + return (source: Observable): Observable => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const isEmpty = (val: any) => + !Object.keys(val).length || (Object.prototype.hasOwnProperty.call(val, 'data') && !val.data.length); + return new Observable((subscriber) => { + source.subscribe({ + next: (val) => { + if (val && isEmpty(val)) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + subscriber.error(new Error(`Reference data not found for resource type ${args}`)); + } - subscriber.next(val); - }, - error: (e) => subscriber.error(e), - complete: () => subscriber.complete(), - }); - }); - }; + subscriber.next(val); + }, + error: (e) => subscriber.error(e), + complete: () => subscriber.complete(), + }); + }); + }; } export function sortReferenceData(resourceType: ReferenceDataResourceType) { - // eslint-disable-next-line func-names - return function (source: Observable): Observable { - return new Observable((subscriber) => { - source.subscribe({ - next: (val) => { - const { data } = val; - subscriber.next({ ...val, data: _sort(resourceType, data) }); - }, - error: (e) => subscriber.error(e), - complete: () => subscriber.complete(), - }); - }); - }; + // eslint-disable-next-line func-names + return (source: Observable): Observable => + new Observable((subscriber) => { + source.subscribe({ + next: (val) => { + const { data } = val; + subscriber.next({ ...val, data: _sort(resourceType, data) }); + }, + error: (e) => subscriber.error(e), + complete: () => subscriber.complete(), + }); + }); } // eslint-disable-next-line no-underscore-dangle function _sort(type: ReferenceDataResourceType, data: ReferenceDataItem[]) { - const dataToSort = [...(data as ReferenceData[])]; - switch (type) { - case ReferenceDataResourceType.User: - return dataToSort.sort(sorter('name')); - default: - return dataToSort; - } + const dataToSort = [...(data as ReferenceData[])]; + switch (type) { + case ReferenceDataResourceType.User: + return dataToSort.sort(sorter('name')); + default: + return dataToSort; + } } type ReferenceData = ReferenceDataItem & Record; function sorter(sortkey: keyof ReferenceData | undefined = 'description') { - // eslint-disable-next-line no-nested-ternary, @typescript-eslint/no-explicit-any - const compare = (a: any, b: any) => (typeof a === 'string' ? (a <= b ? (a < b ? -1 : 0) : 1) : a - b); - return (a: ReferenceData, b: ReferenceData) => { - let l; let - r; - if (sortkey && Object.prototype.hasOwnProperty.call(a, sortkey)) { - l = a[`${sortkey}`]; - r = b[`${sortkey}`]; - } + // eslint-disable-next-line no-nested-ternary, @typescript-eslint/no-explicit-any + const compare = (a: any, b: any) => (typeof a === 'string' ? (a <= b ? (a < b ? -1 : 0) : 1) : a - b); + return (a: ReferenceData, b: ReferenceData) => { + let l; + let r; + if (sortkey && Object.prototype.hasOwnProperty.call(a, sortkey)) { + l = a[`${sortkey}`]; + r = b[`${sortkey}`]; + } - return compare(l, r); - }; + return compare(l, r); + }; } diff --git a/src/app/store/reference-data/effects/reference-data.effects.spec.ts b/src/app/store/reference-data/effects/reference-data.effects.spec.ts index 57060d58b8..4c9c3adf57 100644 --- a/src/app/store/reference-data/effects/reference-data.effects.spec.ts +++ b/src/app/store/reference-data/effects/reference-data.effects.spec.ts @@ -14,515 +14,548 @@ import { testResultInEdit } from '@store/test-records'; import { Observable } from 'rxjs'; import { TestScheduler } from 'rxjs/testing'; import { - amendReferenceDataItem, - amendReferenceDataItemFailure, - amendReferenceDataItemSuccess, - createReferenceDataItem, - createReferenceDataItemFailure, - createReferenceDataItemSuccess, - deleteReferenceDataItem, - deleteReferenceDataItemFailure, - deleteReferenceDataItemSuccess, - fetchReasonsForAbandoning, - fetchReferenceData, - fetchReferenceDataAudit, - fetchReferenceDataAuditFailed, - fetchReferenceDataAuditSuccess, - fetchReferenceDataByKey, - fetchReferenceDataByKeyFailed, - fetchReferenceDataByKeySearch, - fetchReferenceDataByKeySearchFailed, - fetchReferenceDataByKeySearchSuccess, - fetchReferenceDataByKeySuccess, - fetchReferenceDataFailed, - fetchReferenceDataSuccess, - fetchTyreReferenceDataByKeySearch, - fetchTyreReferenceDataByKeySearchFailed, - fetchTyreReferenceDataByKeySearchSuccess, + amendReferenceDataItem, + amendReferenceDataItemFailure, + amendReferenceDataItemSuccess, + createReferenceDataItem, + createReferenceDataItemFailure, + createReferenceDataItemSuccess, + deleteReferenceDataItem, + deleteReferenceDataItemFailure, + deleteReferenceDataItemSuccess, + fetchReasonsForAbandoning, + fetchReferenceData, + fetchReferenceDataAudit, + fetchReferenceDataAuditFailed, + fetchReferenceDataAuditSuccess, + fetchReferenceDataByKey, + fetchReferenceDataByKeyFailed, + fetchReferenceDataByKeySearch, + fetchReferenceDataByKeySearchFailed, + fetchReferenceDataByKeySearchSuccess, + fetchReferenceDataByKeySuccess, + fetchReferenceDataFailed, + fetchReferenceDataSuccess, + fetchTyreReferenceDataByKeySearch, + fetchTyreReferenceDataByKeySearchFailed, + fetchTyreReferenceDataByKeySearchSuccess, } from '../actions/reference-data.actions'; import { testCases } from '../reference-data.test-cases'; import { ReferenceDataEffects } from './reference-data.effects'; describe('ReferenceDataEffects', () => { - let effects: ReferenceDataEffects; - let actions$ = new Observable(); - let testScheduler: TestScheduler; - let referenceDataService: ReferenceDataService; - let store: MockStore; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - provideMockActions(() => actions$), - provideMockStore({ initialState: initialAppState }), - ReferenceDataEffects, - ReferenceDataService, - { provide: UserService, useValue: {} }, - ], - }); - - effects = TestBed.inject(ReferenceDataEffects); - store = TestBed.inject(MockStore); - referenceDataService = TestBed.inject(ReferenceDataService); - }); - - beforeEach(() => { - testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - }); - - describe('fetchReferenceDataByType$', () => { - it.each(testCases)('should return fetchReferenceDataSuccess action on successful API call', (value) => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const { resourceType, payload } = value; - const apiResponse = { data: [...payload] }; - - // mock action to trigger effect - actions$ = hot('-a--', { a: fetchReferenceData({ resourceType }) }); - - // mock service call - jest.spyOn(referenceDataService, 'fetchReferenceData').mockReturnValue(cold('--a|', { a: apiResponse })); - - // expect effect to return success action - expectObservable(effects.fetchReferenceDataByType$).toBe('---b', { - b: fetchReferenceDataSuccess({ resourceType, payload, paginated: false }), - }); - }); - }); - - it.each(testCases)( - 'should return fetchReferenceDataSuccess and fetchReferenceData actions on successful API call with pagination token', - (value) => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const { resourceType, payload } = value; - const apiResponse = { data: [...payload], paginationToken: 'token' }; - - // mock action to trigger effect - actions$ = hot('-a--', { a: fetchReferenceData({ resourceType }) }); - - // mock service call - jest.spyOn(referenceDataService, 'fetchReferenceData').mockReturnValue(cold('--a|', { a: apiResponse })); - - // expect effect to return success action - expectObservable(effects.fetchReferenceDataByType$).toBe('---(bc)', { - b: fetchReferenceDataSuccess({ resourceType, payload, paginated: true }), - c: fetchReferenceData({ resourceType, paginationToken: 'token' }), - }); - }); - }, - ); - - it('should return fetchReferenceDataFailed action on API error', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - actions$ = hot('-a--', { a: fetchReferenceData({ resourceType: null as unknown as ReferenceDataResourceType }) }); - - const expectedError = new Error('Reference data resourceType is required'); - - jest.spyOn(referenceDataService, 'fetchReferenceData').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.fetchReferenceDataByType$).toBe('---b', { - b: fetchReferenceDataFailed({ - error: 'Reference data resourceType is required', - resourceType: null as unknown as ReferenceDataResourceType, - }), - }); - }); - }); - - it('should return fetchReferenceDataFailed action when data is not found', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - actions$ = hot('-a--', { a: fetchReferenceData({ resourceType: ReferenceDataResourceType.HgvMake }) }); - - jest.spyOn(referenceDataService, 'fetchReferenceData').mockReturnValue(cold('--a|', { a: { data: [] } })); - - expectObservable(effects.fetchReferenceDataByType$).toBe('---b', { - b: fetchReferenceDataFailed({ - error: `Reference data not found for resource type ${ReferenceDataResourceType.HgvMake}`, - resourceType: ReferenceDataResourceType.HgvMake, - }), - }); - }); - }); - }); - - describe('fetchReferenceDataByAuditType$', () => { - it.each(testCases)('should return fetchReferenceDataAuditSuccess action on successful API call', (value) => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const { resourceType, payload } = value; - const apiResponse = { data: [...payload] }; - - // mock action to trigger effect - actions$ = hot('-a--', { a: fetchReferenceDataAudit({ resourceType }) }); - - // mock service call - jest.spyOn(referenceDataService, 'fetchReferenceDataAudit').mockReturnValue(cold('--a|', { a: apiResponse })); - - // expect effect to return success action - expectObservable(effects.fetchReferenceDataByAuditType$).toBe('---b', { - b: fetchReferenceDataAuditSuccess({ resourceType, payload, paginated: false }), - }); - }); - }); - - it.each(testCases)( - 'should return fetchReferenceDataAuditSuccess and fetchReferenceDataAudit actions on successful API call with pagination token', - (value) => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const { resourceType, payload } = value; - const apiResponse = { data: [...payload], paginationToken: 'token' }; - - // mock action to trigger effect - actions$ = hot('-a--', { a: fetchReferenceDataAudit({ resourceType }) }); - - // mock service call - jest.spyOn(referenceDataService, 'fetchReferenceDataAudit').mockReturnValue(cold('--a|', { a: apiResponse })); - - // expect effect to return success action - expectObservable(effects.fetchReferenceDataByAuditType$).toBe('---(bc)', { - b: fetchReferenceDataAuditSuccess({ resourceType, payload, paginated: true }), - c: fetchReferenceDataAudit({ resourceType, paginationToken: 'token' }), - }); - }); - }, - ); - - it('should return fetchReferenceDataAuditFailed action on API error', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - actions$ = hot('-a--', { a: fetchReferenceDataAudit({ resourceType: null as unknown as ReferenceDataResourceType }) }); - - const expectedError = new Error('Reference data resourceType is required'); - - jest.spyOn(referenceDataService, 'fetchReferenceDataAudit').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.fetchReferenceDataByAuditType$).toBe('---b', { - b: fetchReferenceDataAuditFailed({ - error: 'Reference data resourceType is required', - resourceType: null as unknown as ReferenceDataResourceType, - }), - }); - }); - }); - - it('should return fetchReferenceDataAuditFailed action when data is not found', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - actions$ = hot('-a--', { a: fetchReferenceDataAudit({ resourceType: ReferenceDataResourceType.HgvMake }) }); - - jest.spyOn(referenceDataService, 'fetchReferenceDataAudit').mockReturnValue(cold('--a|', { a: { data: [] } })); - - expectObservable(effects.fetchReferenceDataByAuditType$).toBe('---b', { - b: fetchReferenceDataAuditFailed({ - error: `Reference data not found for resource type ${ReferenceDataResourceType.HgvMake}`, - resourceType: ReferenceDataResourceType.HgvMake, - }), - }); - }); - }); - }); - - describe('fetchReferenceDataByKey$', () => { - it.each(testCases)('should return fetchReferenceDataByKeySuccess action on successful API call', (value) => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const { resourceType, resourceKey, payload } = value; - - const entity = payload.find((p) => p.resourceKey === resourceKey) as ReferenceDataItem; - - // mock action to trigger effect - actions$ = hot('-a--', { a: fetchReferenceDataByKey({ resourceType, resourceKey }) }); - - // mock service call - jest.spyOn(referenceDataService, 'fetchReferenceDataByKey').mockReturnValue(cold('--a|', { a: entity })); - - // expect effect to return success action - expectObservable(effects.fetchReferenceDataByKey$).toBe('---b', { - b: fetchReferenceDataByKeySuccess({ resourceType, resourceKey, payload: entity as ReferenceDataModelBase }), - }); - }); - }); - - it.each(testCases)('should return fetchReferenceDataByKeyFailed action on API error', (value) => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const { resourceType } = value; - actions$ = hot('-a--', { a: fetchReferenceDataByKey({ resourceType, resourceKey: null as unknown as string | number }) }); - - const expectedError = new Error('Reference data resourceKey is required'); - - jest.spyOn(referenceDataService, 'fetchReferenceDataByKey').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.fetchReferenceDataByKey$).toBe('---b', { - b: fetchReferenceDataByKeyFailed({ error: 'Reference data resourceKey is required', resourceType }), - }); - }); - }); - - it.each(testCases)('should return fetchReferenceDataByKeyFailed action when resource not found', (value) => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const { resourceType } = value; - actions$ = hot('-a--', { a: fetchReferenceDataByKey({ resourceType, resourceKey: 'xx' }) }); - - jest.spyOn(referenceDataService, 'fetchReferenceDataByKey').mockReturnValue(cold('--a|', { a: {} })); - - expectObservable(effects.fetchReferenceDataByKey$).toBe('---b', { - b: fetchReferenceDataByKeyFailed({ error: `Reference data not found for resource type ${resourceType},xx`, resourceType }), - }); - }); - }); - }); - - describe('fetchReferenceDataByKeySearch', () => { - it('should return fetchReferenceDataByKeySearchSuccess on successful API call', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const resourceType = ReferenceDataResourceType.Tyres; - const resourceKey = '123'; - const value = { - payload: [ - { - tyreCode: '123', - resourceType: ReferenceDataResourceType.Tyres, - resourceKey: '123', - code: '123', - loadIndexSingleLoad: '102', - tyreSize: 'size', - dateTimeStamp: 'time', - userId: '1234', - loadIndexTwinLoad: '101', - plyRating: '18', - }, - ], - }; - const apiResponse = { data: [...value.payload] }; - - actions$ = hot('-a--', { a: fetchReferenceDataByKeySearch({ resourceType, resourceKey }) }); - - jest.spyOn(referenceDataService, 'fetchReferenceDataByKeySearch').mockReturnValue(cold('--a|', { a: apiResponse })); - - expectObservable(effects.fetchReferenceDataByKeySearch$).toBe('---b', { - b: fetchReferenceDataByKeySearchSuccess({ resourceType, resourceKey, payload: value.payload as ReferenceDataModelBase[] }), - }); - }); - }); - - it('should return fetchReferenceDataByKeySearchFailed on successful API call', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const resourceType = ReferenceDataResourceType.Tyres; - actions$ = hot('-a--', { a: fetchReferenceDataByKeySearch({ resourceType, resourceKey: null as unknown as string | number }) }); - - const expectedError = new Error('Reference data resourceKey is required'); - - jest.spyOn(referenceDataService, 'fetchReferenceDataByKeySearch').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.fetchReferenceDataByKeySearch$).toBe('---b', { - b: fetchReferenceDataByKeySearchFailed({ error: 'Reference data resourceKey is required', resourceType }), - }); - }); - }); - }); - - describe('fetchTyreReferenceDataByKeySearch', () => { - it('should return fetchTyreReferenceDataByKeySearchSuccess on successful API call', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const resourceType = ReferenceDataResourceType.Tyres; - const value = { - payload: [ - { - tyreCode: '123', - resourceType: ReferenceDataResourceType.Tyres, - resourceKey: '123', - code: '123', - loadIndexSingleLoad: '102', - tyreSize: 'size', - dateTimeStamp: 'time', - userId: '1234', - loadIndexTwinLoad: '101', - plyRating: '18', - }, - ], - }; - const apiResponse = { data: [...value.payload] }; - - actions$ = hot('-a--', { a: fetchTyreReferenceDataByKeySearch({ searchFilter: 'plyRating', searchTerm: '123' }) }); - - jest.spyOn(referenceDataService, 'fetchTyreReferenceDataByKeySearch').mockReturnValue(cold('--a|', { a: apiResponse })); - - expectObservable(effects.fetchTyreReferenceDataByKeySearch$).toBe('---b', { - b: fetchTyreReferenceDataByKeySearchSuccess({ resourceType, payload: value.payload as ReferenceDataModelBase[] }), - }); - }); - }); - - it('should return fetchTyreReferenceDataByKeySearchFailed on unsuccessful API call', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const resourceType = ReferenceDataResourceType.Tyres; - actions$ = hot('-a--', { - a: fetchTyreReferenceDataByKeySearch({ searchFilter: 'plyRating', searchTerm: null as unknown as string }), - }); - - const expectedError = new Error('Search term is required'); - - jest.spyOn(referenceDataService, 'fetchTyreReferenceDataByKeySearch').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.fetchTyreReferenceDataByKeySearch$).toBe('---b', { - b: fetchTyreReferenceDataByKeySearchFailed({ error: 'Search term is required', resourceType }), - }); - }); - }); - }); - - const vehicleTypeReasonsForAbandoning = [ - { - vehicleType: VehicleTypes.PSV, - resourceType: ReferenceDataResourceType.ReasonsForAbandoningPsv, - }, - { - vehicleType: VehicleTypes.TRL, - resourceType: ReferenceDataResourceType.ReasonsForAbandoningTrl, - }, - { - vehicleType: VehicleTypes.HGV, - resourceType: ReferenceDataResourceType.ReasonsForAbandoningHgv, - }, - ]; - it.each(vehicleTypeReasonsForAbandoning)('should dispatch the action to fetch the reasons for abandoning for the right vehicle', (values) => { - const { vehicleType, resourceType } = values; - const testResult = { vehicleType } as TestResultModel; - - testScheduler.run(({ hot, expectObservable }) => { - store.overrideSelector(testResultInEdit, testResult); - - actions$ = hot('-a', { - a: fetchReasonsForAbandoning(), - }); - - expectObservable(effects.fetchReasonsForAbandoning).toBe('-b', { - b: fetchReferenceData({ - resourceType, - }), - }); - }); - }); - - describe('createReferenceDataItem$', () => { - it('should return createReferenceDataItemSuccess on a successful call', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const resourceType = ReferenceDataResourceType.CountryOfRegistration; - const resourceKey = 'testKey'; - const body = { - description: 'test country', - }; - const apiResponse = { ...body, resourceType, resourceKey }; - - actions$ = hot('-a--', { - a: createReferenceDataItem({ resourceType, resourceKey, payload: body as ReferenceDataModelBase }), - }); - - jest.spyOn(referenceDataService, 'createReferenceDataItem').mockReturnValue(cold('--a|', { a: apiResponse })); - - expectObservable(effects.createReferenceDataItem$).toBe('---b', { - b: createReferenceDataItemSuccess({ result: apiResponse as ReferenceDataModelBase }), - }); - }); - }); - it('should return createReferenceDataItemFailure if an error is returned', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const resourceType = ReferenceDataResourceType.CountryOfRegistration; - const resourceKey = 'testKey'; - const body = { - description: 'test country', - }; - - actions$ = hot('-a--', { - a: createReferenceDataItem({ resourceType, resourceKey, payload: body as ReferenceDataModelBase }), - }); - - const expectedError = new Error('Something went wrong'); - - jest.spyOn(referenceDataService, 'createReferenceDataItem').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.createReferenceDataItem$).toBe('---b', { - b: createReferenceDataItemFailure({ error: 'Something went wrong' }), - }); - }); - }); - }); - - describe('amendReferenceDataItem$', () => { - it('should return amendReferenceDataI on a successful call', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const resourceType = ReferenceDataResourceType.CountryOfRegistration; - const resourceKey = 'testKey'; - const body = { - description: 'test country', - }; - const apiResponse = { ...body, resourceType, resourceKey }; - - actions$ = hot('-a--', { - a: amendReferenceDataItem({ resourceType, resourceKey, payload: body as ReferenceDataModelBase }), - }); - - jest.spyOn(referenceDataService, 'amendReferenceDataItem').mockReturnValue(cold('--a-|', { a: apiResponse })); - - expectObservable(effects.amendReferenceDataItem$).toBe('---b', { - b: amendReferenceDataItemSuccess({ result: apiResponse as ReferenceDataModelBase }), - }); - }); - }); - it('should return amendReferenceDataItemFailure if an error is returned', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const resourceType = ReferenceDataResourceType.CountryOfRegistration; - const resourceKey = 'testKey'; - const body = { - description: 'test country', - }; - - actions$ = hot('-a--', { - a: amendReferenceDataItem({ resourceType, resourceKey, payload: body as ReferenceDataModelBase }), - }); - - const expectedError = new Error('Something went wrong'); - - jest.spyOn(referenceDataService, 'amendReferenceDataItem').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.amendReferenceDataItem$).toBe('---b', { - b: amendReferenceDataItemFailure({ error: 'Something went wrong' }), - }); - }); - }); - }); - - describe('deleteReferenceDataItem$', () => { - it('should return deleteReferenceDataSuccess on a successful call', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const resourceType = ReferenceDataResourceType.CountryOfRegistration; - const resourceKey = 'testKey'; - const reason = 'for test'; - const apiResponse = { result: true }; - - actions$ = hot('-a--', { a: deleteReferenceDataItem({ resourceType, resourceKey, reason }) }); - - jest.spyOn(referenceDataService, 'deleteReferenceDataItem').mockReturnValue(cold('--a-|', { a: apiResponse as DeleteItem })); - - expectObservable(effects.deleteReferenceDataItem$).toBe('---b', { - b: deleteReferenceDataItemSuccess({ resourceType, resourceKey }), - }); - }); - }); - it('should return deleteReferenceDataFailure if an error is returned', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const resourceType = ReferenceDataResourceType.CountryOfRegistration; - const resourceKey = 'testKey'; - const reason = 'testing'; - - actions$ = hot('-a--', { a: deleteReferenceDataItem({ resourceType, resourceKey, reason }) }); - - const expectedError = new Error('Something went wrong'); - - jest.spyOn(referenceDataService, 'deleteReferenceDataItem').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.deleteReferenceDataItem$).toBe('---b', { - b: deleteReferenceDataItemFailure({ error: 'Something went wrong' }), - }); - }); - }); - }); + let effects: ReferenceDataEffects; + let actions$ = new Observable(); + let testScheduler: TestScheduler; + let referenceDataService: ReferenceDataService; + let store: MockStore; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + provideMockActions(() => actions$), + provideMockStore({ initialState: initialAppState }), + ReferenceDataEffects, + ReferenceDataService, + { provide: UserService, useValue: {} }, + ], + }); + + effects = TestBed.inject(ReferenceDataEffects); + store = TestBed.inject(MockStore); + referenceDataService = TestBed.inject(ReferenceDataService); + }); + + beforeEach(() => { + testScheduler = new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); + }); + }); + + describe('fetchReferenceDataByType$', () => { + it.each(testCases)('should return fetchReferenceDataSuccess action on successful API call', (value) => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const { resourceType, payload } = value; + const apiResponse = { data: [...payload] }; + + // mock action to trigger effect + actions$ = hot('-a--', { a: fetchReferenceData({ resourceType }) }); + + // mock service call + jest.spyOn(referenceDataService, 'fetchReferenceData').mockReturnValue(cold('--a|', { a: apiResponse })); + + // expect effect to return success action + expectObservable(effects.fetchReferenceDataByType$).toBe('---b', { + b: fetchReferenceDataSuccess({ resourceType, payload, paginated: false }), + }); + }); + }); + + it.each(testCases)( + 'should return fetchReferenceDataSuccess and fetchReferenceData actions on successful API call with pagination token', + (value) => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const { resourceType, payload } = value; + const apiResponse = { data: [...payload], paginationToken: 'token' }; + + // mock action to trigger effect + actions$ = hot('-a--', { a: fetchReferenceData({ resourceType }) }); + + // mock service call + jest.spyOn(referenceDataService, 'fetchReferenceData').mockReturnValue(cold('--a|', { a: apiResponse })); + + // expect effect to return success action + expectObservable(effects.fetchReferenceDataByType$).toBe('---(bc)', { + b: fetchReferenceDataSuccess({ resourceType, payload, paginated: true }), + c: fetchReferenceData({ resourceType, paginationToken: 'token' }), + }); + }); + } + ); + + it('should return fetchReferenceDataFailed action on API error', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + actions$ = hot('-a--', { + a: fetchReferenceData({ resourceType: null as unknown as ReferenceDataResourceType }), + }); + + const expectedError = new Error('Reference data resourceType is required'); + + jest.spyOn(referenceDataService, 'fetchReferenceData').mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.fetchReferenceDataByType$).toBe('---b', { + b: fetchReferenceDataFailed({ + error: 'Reference data resourceType is required', + resourceType: null as unknown as ReferenceDataResourceType, + }), + }); + }); + }); + + it('should return fetchReferenceDataFailed action when data is not found', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + actions$ = hot('-a--', { a: fetchReferenceData({ resourceType: ReferenceDataResourceType.HgvMake }) }); + + jest.spyOn(referenceDataService, 'fetchReferenceData').mockReturnValue(cold('--a|', { a: { data: [] } })); + + expectObservable(effects.fetchReferenceDataByType$).toBe('---b', { + b: fetchReferenceDataFailed({ + error: `Reference data not found for resource type ${ReferenceDataResourceType.HgvMake}`, + resourceType: ReferenceDataResourceType.HgvMake, + }), + }); + }); + }); + }); + + describe('fetchReferenceDataByAuditType$', () => { + it.each(testCases)('should return fetchReferenceDataAuditSuccess action on successful API call', (value) => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const { resourceType, payload } = value; + const apiResponse = { data: [...payload] }; + + // mock action to trigger effect + actions$ = hot('-a--', { a: fetchReferenceDataAudit({ resourceType }) }); + + // mock service call + jest.spyOn(referenceDataService, 'fetchReferenceDataAudit').mockReturnValue(cold('--a|', { a: apiResponse })); + + // expect effect to return success action + expectObservable(effects.fetchReferenceDataByAuditType$).toBe('---b', { + b: fetchReferenceDataAuditSuccess({ resourceType, payload, paginated: false }), + }); + }); + }); + + it.each(testCases)( + 'should return fetchReferenceDataAuditSuccess and fetchReferenceDataAudit actions on successful API call with pagination token', + (value) => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const { resourceType, payload } = value; + const apiResponse = { data: [...payload], paginationToken: 'token' }; + + // mock action to trigger effect + actions$ = hot('-a--', { a: fetchReferenceDataAudit({ resourceType }) }); + + // mock service call + jest.spyOn(referenceDataService, 'fetchReferenceDataAudit').mockReturnValue(cold('--a|', { a: apiResponse })); + + // expect effect to return success action + expectObservable(effects.fetchReferenceDataByAuditType$).toBe('---(bc)', { + b: fetchReferenceDataAuditSuccess({ resourceType, payload, paginated: true }), + c: fetchReferenceDataAudit({ resourceType, paginationToken: 'token' }), + }); + }); + } + ); + + it('should return fetchReferenceDataAuditFailed action on API error', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + actions$ = hot('-a--', { + a: fetchReferenceDataAudit({ resourceType: null as unknown as ReferenceDataResourceType }), + }); + + const expectedError = new Error('Reference data resourceType is required'); + + jest.spyOn(referenceDataService, 'fetchReferenceDataAudit').mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.fetchReferenceDataByAuditType$).toBe('---b', { + b: fetchReferenceDataAuditFailed({ + error: 'Reference data resourceType is required', + resourceType: null as unknown as ReferenceDataResourceType, + }), + }); + }); + }); + + it('should return fetchReferenceDataAuditFailed action when data is not found', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + actions$ = hot('-a--', { a: fetchReferenceDataAudit({ resourceType: ReferenceDataResourceType.HgvMake }) }); + + jest.spyOn(referenceDataService, 'fetchReferenceDataAudit').mockReturnValue(cold('--a|', { a: { data: [] } })); + + expectObservable(effects.fetchReferenceDataByAuditType$).toBe('---b', { + b: fetchReferenceDataAuditFailed({ + error: `Reference data not found for resource type ${ReferenceDataResourceType.HgvMake}`, + resourceType: ReferenceDataResourceType.HgvMake, + }), + }); + }); + }); + }); + + describe('fetchReferenceDataByKey$', () => { + it.each(testCases)('should return fetchReferenceDataByKeySuccess action on successful API call', (value) => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const { resourceType, resourceKey, payload } = value; + + const entity = payload.find((p) => p.resourceKey === resourceKey) as ReferenceDataItem; + + // mock action to trigger effect + actions$ = hot('-a--', { a: fetchReferenceDataByKey({ resourceType, resourceKey }) }); + + // mock service call + jest.spyOn(referenceDataService, 'fetchReferenceDataByKey').mockReturnValue(cold('--a|', { a: entity })); + + // expect effect to return success action + expectObservable(effects.fetchReferenceDataByKey$).toBe('---b', { + b: fetchReferenceDataByKeySuccess({ resourceType, resourceKey, payload: entity as ReferenceDataModelBase }), + }); + }); + }); + + it.each(testCases)('should return fetchReferenceDataByKeyFailed action on API error', (value) => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const { resourceType } = value; + actions$ = hot('-a--', { + a: fetchReferenceDataByKey({ resourceType, resourceKey: null as unknown as string | number }), + }); + + const expectedError = new Error('Reference data resourceKey is required'); + + jest.spyOn(referenceDataService, 'fetchReferenceDataByKey').mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.fetchReferenceDataByKey$).toBe('---b', { + b: fetchReferenceDataByKeyFailed({ error: 'Reference data resourceKey is required', resourceType }), + }); + }); + }); + + it.each(testCases)('should return fetchReferenceDataByKeyFailed action when resource not found', (value) => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const { resourceType } = value; + actions$ = hot('-a--', { a: fetchReferenceDataByKey({ resourceType, resourceKey: 'xx' }) }); + + jest.spyOn(referenceDataService, 'fetchReferenceDataByKey').mockReturnValue(cold('--a|', { a: {} })); + + expectObservable(effects.fetchReferenceDataByKey$).toBe('---b', { + b: fetchReferenceDataByKeyFailed({ + error: `Reference data not found for resource type ${resourceType},xx`, + resourceType, + }), + }); + }); + }); + }); + + describe('fetchReferenceDataByKeySearch', () => { + it('should return fetchReferenceDataByKeySearchSuccess on successful API call', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const resourceType = ReferenceDataResourceType.Tyres; + const resourceKey = '123'; + const value = { + payload: [ + { + tyreCode: '123', + resourceType: ReferenceDataResourceType.Tyres, + resourceKey: '123', + code: '123', + loadIndexSingleLoad: '102', + tyreSize: 'size', + dateTimeStamp: 'time', + userId: '1234', + loadIndexTwinLoad: '101', + plyRating: '18', + }, + ], + }; + const apiResponse = { data: [...value.payload] }; + + actions$ = hot('-a--', { a: fetchReferenceDataByKeySearch({ resourceType, resourceKey }) }); + + jest + .spyOn(referenceDataService, 'fetchReferenceDataByKeySearch') + .mockReturnValue(cold('--a|', { a: apiResponse })); + + expectObservable(effects.fetchReferenceDataByKeySearch$).toBe('---b', { + b: fetchReferenceDataByKeySearchSuccess({ + resourceType, + resourceKey, + payload: value.payload as ReferenceDataModelBase[], + }), + }); + }); + }); + + it('should return fetchReferenceDataByKeySearchFailed on successful API call', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const resourceType = ReferenceDataResourceType.Tyres; + actions$ = hot('-a--', { + a: fetchReferenceDataByKeySearch({ resourceType, resourceKey: null as unknown as string | number }), + }); + + const expectedError = new Error('Reference data resourceKey is required'); + + jest + .spyOn(referenceDataService, 'fetchReferenceDataByKeySearch') + .mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.fetchReferenceDataByKeySearch$).toBe('---b', { + b: fetchReferenceDataByKeySearchFailed({ error: 'Reference data resourceKey is required', resourceType }), + }); + }); + }); + }); + + describe('fetchTyreReferenceDataByKeySearch', () => { + it('should return fetchTyreReferenceDataByKeySearchSuccess on successful API call', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const resourceType = ReferenceDataResourceType.Tyres; + const value = { + payload: [ + { + tyreCode: '123', + resourceType: ReferenceDataResourceType.Tyres, + resourceKey: '123', + code: '123', + loadIndexSingleLoad: '102', + tyreSize: 'size', + dateTimeStamp: 'time', + userId: '1234', + loadIndexTwinLoad: '101', + plyRating: '18', + }, + ], + }; + const apiResponse = { data: [...value.payload] }; + + actions$ = hot('-a--', { + a: fetchTyreReferenceDataByKeySearch({ searchFilter: 'plyRating', searchTerm: '123' }), + }); + + jest + .spyOn(referenceDataService, 'fetchTyreReferenceDataByKeySearch') + .mockReturnValue(cold('--a|', { a: apiResponse })); + + expectObservable(effects.fetchTyreReferenceDataByKeySearch$).toBe('---b', { + b: fetchTyreReferenceDataByKeySearchSuccess({ + resourceType, + payload: value.payload as ReferenceDataModelBase[], + }), + }); + }); + }); + + it('should return fetchTyreReferenceDataByKeySearchFailed on unsuccessful API call', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const resourceType = ReferenceDataResourceType.Tyres; + actions$ = hot('-a--', { + a: fetchTyreReferenceDataByKeySearch({ searchFilter: 'plyRating', searchTerm: null as unknown as string }), + }); + + const expectedError = new Error('Search term is required'); + + jest + .spyOn(referenceDataService, 'fetchTyreReferenceDataByKeySearch') + .mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.fetchTyreReferenceDataByKeySearch$).toBe('---b', { + b: fetchTyreReferenceDataByKeySearchFailed({ error: 'Search term is required', resourceType }), + }); + }); + }); + }); + + const vehicleTypeReasonsForAbandoning = [ + { + vehicleType: VehicleTypes.PSV, + resourceType: ReferenceDataResourceType.ReasonsForAbandoningPsv, + }, + { + vehicleType: VehicleTypes.TRL, + resourceType: ReferenceDataResourceType.ReasonsForAbandoningTrl, + }, + { + vehicleType: VehicleTypes.HGV, + resourceType: ReferenceDataResourceType.ReasonsForAbandoningHgv, + }, + ]; + it.each(vehicleTypeReasonsForAbandoning)( + 'should dispatch the action to fetch the reasons for abandoning for the right vehicle', + (values) => { + const { vehicleType, resourceType } = values; + const testResult = { vehicleType } as TestResultModel; + + testScheduler.run(({ hot, expectObservable }) => { + store.overrideSelector(testResultInEdit, testResult); + + actions$ = hot('-a', { + a: fetchReasonsForAbandoning(), + }); + + expectObservable(effects.fetchReasonsForAbandoning).toBe('-b', { + b: fetchReferenceData({ + resourceType, + }), + }); + }); + } + ); + + describe('createReferenceDataItem$', () => { + it('should return createReferenceDataItemSuccess on a successful call', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const resourceType = ReferenceDataResourceType.CountryOfRegistration; + const resourceKey = 'testKey'; + const body = { + description: 'test country', + }; + const apiResponse = { ...body, resourceType, resourceKey }; + + actions$ = hot('-a--', { + a: createReferenceDataItem({ resourceType, resourceKey, payload: body as ReferenceDataModelBase }), + }); + + jest.spyOn(referenceDataService, 'createReferenceDataItem').mockReturnValue(cold('--a|', { a: apiResponse })); + + expectObservable(effects.createReferenceDataItem$).toBe('---b', { + b: createReferenceDataItemSuccess({ result: apiResponse as ReferenceDataModelBase }), + }); + }); + }); + it('should return createReferenceDataItemFailure if an error is returned', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const resourceType = ReferenceDataResourceType.CountryOfRegistration; + const resourceKey = 'testKey'; + const body = { + description: 'test country', + }; + + actions$ = hot('-a--', { + a: createReferenceDataItem({ resourceType, resourceKey, payload: body as ReferenceDataModelBase }), + }); + + const expectedError = new Error('Something went wrong'); + + jest.spyOn(referenceDataService, 'createReferenceDataItem').mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.createReferenceDataItem$).toBe('---b', { + b: createReferenceDataItemFailure({ error: 'Something went wrong' }), + }); + }); + }); + }); + + describe('amendReferenceDataItem$', () => { + it('should return amendReferenceDataI on a successful call', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const resourceType = ReferenceDataResourceType.CountryOfRegistration; + const resourceKey = 'testKey'; + const body = { + description: 'test country', + }; + const apiResponse = { ...body, resourceType, resourceKey }; + + actions$ = hot('-a--', { + a: amendReferenceDataItem({ resourceType, resourceKey, payload: body as ReferenceDataModelBase }), + }); + + jest.spyOn(referenceDataService, 'amendReferenceDataItem').mockReturnValue(cold('--a-|', { a: apiResponse })); + + expectObservable(effects.amendReferenceDataItem$).toBe('---b', { + b: amendReferenceDataItemSuccess({ result: apiResponse as ReferenceDataModelBase }), + }); + }); + }); + it('should return amendReferenceDataItemFailure if an error is returned', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const resourceType = ReferenceDataResourceType.CountryOfRegistration; + const resourceKey = 'testKey'; + const body = { + description: 'test country', + }; + + actions$ = hot('-a--', { + a: amendReferenceDataItem({ resourceType, resourceKey, payload: body as ReferenceDataModelBase }), + }); + + const expectedError = new Error('Something went wrong'); + + jest.spyOn(referenceDataService, 'amendReferenceDataItem').mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.amendReferenceDataItem$).toBe('---b', { + b: amendReferenceDataItemFailure({ error: 'Something went wrong' }), + }); + }); + }); + }); + + describe('deleteReferenceDataItem$', () => { + it('should return deleteReferenceDataSuccess on a successful call', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const resourceType = ReferenceDataResourceType.CountryOfRegistration; + const resourceKey = 'testKey'; + const reason = 'for test'; + const apiResponse = { result: true }; + + actions$ = hot('-a--', { a: deleteReferenceDataItem({ resourceType, resourceKey, reason }) }); + + jest + .spyOn(referenceDataService, 'deleteReferenceDataItem') + .mockReturnValue(cold('--a-|', { a: apiResponse as DeleteItem })); + + expectObservable(effects.deleteReferenceDataItem$).toBe('---b', { + b: deleteReferenceDataItemSuccess({ resourceType, resourceKey }), + }); + }); + }); + it('should return deleteReferenceDataFailure if an error is returned', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const resourceType = ReferenceDataResourceType.CountryOfRegistration; + const resourceKey = 'testKey'; + const reason = 'testing'; + + actions$ = hot('-a--', { a: deleteReferenceDataItem({ resourceType, resourceKey, reason }) }); + + const expectedError = new Error('Something went wrong'); + + jest.spyOn(referenceDataService, 'deleteReferenceDataItem').mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.deleteReferenceDataItem$).toBe('---b', { + b: deleteReferenceDataItemFailure({ error: 'Something went wrong' }), + }); + }); + }); + }); }); diff --git a/src/app/store/reference-data/effects/reference-data.effects.ts b/src/app/store/reference-data/effects/reference-data.effects.ts index 3b7ef5fd2a..0ccc4e06cb 100644 --- a/src/app/store/reference-data/effects/reference-data.effects.ts +++ b/src/app/store/reference-data/effects/reference-data.effects.ts @@ -3,184 +3,234 @@ import { ReferenceDataApiResponse, ReferenceDataApiResponseWithPagination } from import { ReferenceDataModelBase, ReferenceDataResourceType } from '@models/reference-data.model'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { select, Store } from '@ngrx/store'; +import { Store, select } from '@ngrx/store'; import { ReferenceDataService } from '@services/reference-data/reference-data.service'; import { UserService } from '@services/user-service/user-service'; import { State } from '@store/.'; import { testResultInEdit } from '@store/test-records'; +import { catchError, map, mergeMap, of, switchMap, take } from 'rxjs'; import { - catchError, map, mergeMap, of, switchMap, take, -} from 'rxjs'; -import { - amendReferenceDataItem, - amendReferenceDataItemFailure, - amendReferenceDataItemSuccess, - createReferenceDataItem, - createReferenceDataItemFailure, - createReferenceDataItemSuccess, - deleteReferenceDataItem, - deleteReferenceDataItemFailure, - deleteReferenceDataItemSuccess, - fetchReasonsForAbandoning, - fetchReferenceData, - fetchReferenceDataAudit, - fetchReferenceDataAuditFailed, - fetchReferenceDataAuditSuccess, - fetchReferenceDataByKey, - fetchReferenceDataByKeyFailed, - fetchReferenceDataByKeySearch, - fetchReferenceDataByKeySearchFailed, - fetchReferenceDataByKeySearchSuccess, - fetchReferenceDataByKeySuccess, - fetchReferenceDataFailed, - fetchReferenceDataSuccess, - fetchTyreReferenceDataByKeySearch, - fetchTyreReferenceDataByKeySearchFailed, - fetchTyreReferenceDataByKeySearchSuccess, + amendReferenceDataItem, + amendReferenceDataItemFailure, + amendReferenceDataItemSuccess, + createReferenceDataItem, + createReferenceDataItemFailure, + createReferenceDataItemSuccess, + deleteReferenceDataItem, + deleteReferenceDataItemFailure, + deleteReferenceDataItemSuccess, + fetchReasonsForAbandoning, + fetchReferenceData, + fetchReferenceDataAudit, + fetchReferenceDataAuditFailed, + fetchReferenceDataAuditSuccess, + fetchReferenceDataByKey, + fetchReferenceDataByKeyFailed, + fetchReferenceDataByKeySearch, + fetchReferenceDataByKeySearchFailed, + fetchReferenceDataByKeySearchSuccess, + fetchReferenceDataByKeySuccess, + fetchReferenceDataFailed, + fetchReferenceDataSuccess, + fetchTyreReferenceDataByKeySearch, + fetchTyreReferenceDataByKeySearchFailed, + fetchTyreReferenceDataByKeySearchSuccess, } from '../actions/reference-data.actions'; import { handleNotFound, sortReferenceData } from './operators'; @Injectable() export class ReferenceDataEffects { - constructor( - private actions$: Actions, - private userService: UserService, - private referenceDataService: ReferenceDataService, - private store: Store, - ) {} + constructor( + private actions$: Actions, + private userService: UserService, + private referenceDataService: ReferenceDataService, + private store: Store + ) {} - fetchReferenceDataByType$ = createEffect(() => - this.actions$.pipe( - ofType(fetchReferenceData), - mergeMap(({ resourceType, paginationToken }) => - this.referenceDataService.fetchReferenceData(resourceType, paginationToken).pipe( - handleNotFound(resourceType), - sortReferenceData(resourceType), - switchMap((data) => { - if (isPaginated(data)) { - return of( - fetchReferenceDataSuccess({ resourceType, payload: data.data as ReferenceDataModelBase[], paginated: true }), - fetchReferenceData({ resourceType, paginationToken: data.paginationToken }), - ); - } - return of(fetchReferenceDataSuccess({ resourceType, payload: data.data as ReferenceDataModelBase[], paginated: false })); - }), - catchError((e) => of(fetchReferenceDataFailed({ error: e.message, resourceType }))), - )), - )); + fetchReferenceDataByType$ = createEffect(() => + this.actions$.pipe( + ofType(fetchReferenceData), + mergeMap(({ resourceType, paginationToken }) => + this.referenceDataService.fetchReferenceData(resourceType, paginationToken).pipe( + handleNotFound(resourceType), + sortReferenceData(resourceType), + switchMap((data) => { + if (isPaginated(data)) { + return of( + fetchReferenceDataSuccess({ + resourceType, + payload: data.data as ReferenceDataModelBase[], + paginated: true, + }), + fetchReferenceData({ resourceType, paginationToken: data.paginationToken }) + ); + } + return of( + fetchReferenceDataSuccess({ + resourceType, + payload: data.data as ReferenceDataModelBase[], + paginated: false, + }) + ); + }), + catchError((e) => of(fetchReferenceDataFailed({ error: e.message, resourceType }))) + ) + ) + ) + ); - fetchReferenceDataByAuditType$ = createEffect(() => - this.actions$.pipe( - ofType(fetchReferenceDataAudit), - mergeMap(({ resourceType, paginationToken }) => - this.referenceDataService.fetchReferenceDataAudit(resourceType, paginationToken).pipe( - handleNotFound(resourceType), - sortReferenceData(resourceType), - switchMap((data) => { - if (isPaginated(data)) { - return of( - fetchReferenceDataAuditSuccess({ resourceType, payload: data.data as ReferenceDataModelBase[], paginated: true }), - fetchReferenceDataAudit({ resourceType, paginationToken: data.paginationToken }), - ); - } - return of(fetchReferenceDataAuditSuccess({ resourceType, payload: data.data as ReferenceDataModelBase[], paginated: false })); - }), - catchError((e) => of(fetchReferenceDataAuditFailed({ error: e.message, resourceType }))), - )), - )); + fetchReferenceDataByAuditType$ = createEffect(() => + this.actions$.pipe( + ofType(fetchReferenceDataAudit), + mergeMap(({ resourceType, paginationToken }) => + this.referenceDataService.fetchReferenceDataAudit(resourceType, paginationToken).pipe( + handleNotFound(resourceType), + sortReferenceData(resourceType), + switchMap((data) => { + if (isPaginated(data)) { + return of( + fetchReferenceDataAuditSuccess({ + resourceType, + payload: data.data as ReferenceDataModelBase[], + paginated: true, + }), + fetchReferenceDataAudit({ resourceType, paginationToken: data.paginationToken }) + ); + } + return of( + fetchReferenceDataAuditSuccess({ + resourceType, + payload: data.data as ReferenceDataModelBase[], + paginated: false, + }) + ); + }), + catchError((e) => of(fetchReferenceDataAuditFailed({ error: e.message, resourceType }))) + ) + ) + ) + ); - fetchReferenceDataByKey$ = createEffect(() => - this.actions$.pipe( - ofType(fetchReferenceDataByKey), - mergeMap(({ resourceType, resourceKey }) => - this.referenceDataService.fetchReferenceDataByKey(resourceType, resourceKey).pipe( - handleNotFound(resourceType, resourceKey), - map((data) => fetchReferenceDataByKeySuccess({ resourceType, resourceKey, payload: data as ReferenceDataModelBase })), - catchError((e) => of(fetchReferenceDataByKeyFailed({ error: e.message, resourceType }))), - )), - )); + fetchReferenceDataByKey$ = createEffect(() => + this.actions$.pipe( + ofType(fetchReferenceDataByKey), + mergeMap(({ resourceType, resourceKey }) => + this.referenceDataService.fetchReferenceDataByKey(resourceType, resourceKey).pipe( + handleNotFound(resourceType, resourceKey), + map((data) => + fetchReferenceDataByKeySuccess({ resourceType, resourceKey, payload: data as ReferenceDataModelBase }) + ), + catchError((e) => of(fetchReferenceDataByKeyFailed({ error: e.message, resourceType }))) + ) + ) + ) + ); - fetchReferenceDataByKeySearch$ = createEffect(() => - this.actions$.pipe( - ofType(fetchReferenceDataByKeySearch), - mergeMap(({ resourceType, resourceKey }) => - this.referenceDataService.fetchReferenceDataByKeySearch(resourceType, resourceKey).pipe( - map((data) => fetchReferenceDataByKeySearchSuccess({ resourceType, resourceKey, payload: data.data as ReferenceDataModelBase[] })), - catchError((e) => of(fetchReferenceDataByKeySearchFailed({ error: e.message, resourceType }))), - )), - )); + fetchReferenceDataByKeySearch$ = createEffect(() => + this.actions$.pipe( + ofType(fetchReferenceDataByKeySearch), + mergeMap(({ resourceType, resourceKey }) => + this.referenceDataService.fetchReferenceDataByKeySearch(resourceType, resourceKey).pipe( + map((data) => + fetchReferenceDataByKeySearchSuccess({ + resourceType, + resourceKey, + payload: data.data as ReferenceDataModelBase[], + }) + ), + catchError((e) => of(fetchReferenceDataByKeySearchFailed({ error: e.message, resourceType }))) + ) + ) + ) + ); - fetchTyreReferenceDataByKeySearch$ = createEffect(() => - this.actions$.pipe( - ofType(fetchTyreReferenceDataByKeySearch), - mergeMap(({ searchFilter, searchTerm }) => - this.referenceDataService.fetchTyreReferenceDataByKeySearch(searchFilter, searchTerm).pipe( - map((data) => - fetchTyreReferenceDataByKeySearchSuccess({ - resourceType: ReferenceDataResourceType.Tyres, - payload: data.data as ReferenceDataModelBase[], - })), - catchError((e) => of(fetchTyreReferenceDataByKeySearchFailed({ error: e.message, resourceType: ReferenceDataResourceType.Tyres }))), - )), - )); + fetchTyreReferenceDataByKeySearch$ = createEffect(() => + this.actions$.pipe( + ofType(fetchTyreReferenceDataByKeySearch), + mergeMap(({ searchFilter, searchTerm }) => + this.referenceDataService.fetchTyreReferenceDataByKeySearch(searchFilter, searchTerm).pipe( + map((data) => + fetchTyreReferenceDataByKeySearchSuccess({ + resourceType: ReferenceDataResourceType.Tyres, + payload: data.data as ReferenceDataModelBase[], + }) + ), + catchError((e) => + of( + fetchTyreReferenceDataByKeySearchFailed({ + error: e.message, + resourceType: ReferenceDataResourceType.Tyres, + }) + ) + ) + ) + ) + ) + ); - fetchReasonsForAbandoning = createEffect(() => - this.actions$.pipe( - ofType(fetchReasonsForAbandoning), - mergeMap(() => this.store.pipe(select(testResultInEdit), take(1))), - map((testResult) => { - switch (testResult?.vehicleType) { - case VehicleTypes.PSV: - return fetchReferenceData({ resourceType: ReferenceDataResourceType.ReasonsForAbandoningPsv }); - case VehicleTypes.HGV: - return fetchReferenceData({ resourceType: ReferenceDataResourceType.ReasonsForAbandoningHgv }); - case VehicleTypes.TRL: - return fetchReferenceData({ resourceType: ReferenceDataResourceType.ReasonsForAbandoningTrl }); - default: - throw new Error('Unexpected vehicle type'); - } - }), - )); + fetchReasonsForAbandoning = createEffect(() => + this.actions$.pipe( + ofType(fetchReasonsForAbandoning), + mergeMap(() => this.store.pipe(select(testResultInEdit), take(1))), + map((testResult) => { + switch (testResult?.vehicleType) { + case VehicleTypes.PSV: + return fetchReferenceData({ resourceType: ReferenceDataResourceType.ReasonsForAbandoningPsv }); + case VehicleTypes.HGV: + return fetchReferenceData({ resourceType: ReferenceDataResourceType.ReasonsForAbandoningHgv }); + case VehicleTypes.TRL: + return fetchReferenceData({ resourceType: ReferenceDataResourceType.ReasonsForAbandoningTrl }); + default: + throw new Error('Unexpected vehicle type'); + } + }) + ) + ); - createReferenceDataItem$ = createEffect(() => - this.actions$.pipe( - ofType(createReferenceDataItem), - switchMap(({ resourceType, resourceKey, payload }) => { - payload = { ...payload }; - return this.referenceDataService.createReferenceDataItem(resourceType, resourceKey, payload).pipe( - map((result) => createReferenceDataItemSuccess({ result: result as ReferenceDataModelBase })), - catchError((error) => of(createReferenceDataItemFailure({ error: error.message }))), - ); - }), - )); + createReferenceDataItem$ = createEffect(() => + this.actions$.pipe( + ofType(createReferenceDataItem), + switchMap(({ resourceType, resourceKey, payload }) => { + payload = { ...payload }; + return this.referenceDataService.createReferenceDataItem(resourceType, resourceKey, payload).pipe( + map((result) => createReferenceDataItemSuccess({ result: result as ReferenceDataModelBase })), + catchError((error) => of(createReferenceDataItemFailure({ error: error.message }))) + ); + }) + ) + ); - // The amend effect will work when the referenceData.service.ts is amended on line 395 from to + // The amend effect will work when the referenceData.service.ts is amended on line 395 from to - amendReferenceDataItem$ = createEffect(() => - this.actions$.pipe( - ofType(amendReferenceDataItem), - switchMap(({ resourceType, resourceKey, payload }) => { - payload = { ...payload }; - return this.referenceDataService.amendReferenceDataItem(resourceType, resourceKey, payload).pipe( - map((result) => amendReferenceDataItemSuccess({ result: result as ReferenceDataModelBase })), - catchError((error) => of(amendReferenceDataItemFailure({ error: error.message }))), - ); - }), - )); + amendReferenceDataItem$ = createEffect(() => + this.actions$.pipe( + ofType(amendReferenceDataItem), + switchMap(({ resourceType, resourceKey, payload }) => { + payload = { ...payload }; + return this.referenceDataService.amendReferenceDataItem(resourceType, resourceKey, payload).pipe( + map((result) => amendReferenceDataItemSuccess({ result: result as ReferenceDataModelBase })), + catchError((error) => of(amendReferenceDataItemFailure({ error: error.message }))) + ); + }) + ) + ); - deleteReferenceDataItem$ = createEffect(() => - this.actions$.pipe( - ofType(deleteReferenceDataItem), - switchMap(({ resourceType, resourceKey, reason }) => { - const payload = { reason }; - return this.referenceDataService.deleteReferenceDataItem(resourceType, resourceKey, payload).pipe( - map(() => deleteReferenceDataItemSuccess({ resourceType, resourceKey })), - catchError((error) => of(deleteReferenceDataItemFailure({ error: error.message }))), - ); - }), - )); + deleteReferenceDataItem$ = createEffect(() => + this.actions$.pipe( + ofType(deleteReferenceDataItem), + switchMap(({ resourceType, resourceKey, reason }) => { + const payload = { reason }; + return this.referenceDataService.deleteReferenceDataItem(resourceType, resourceKey, payload).pipe( + map(() => deleteReferenceDataItemSuccess({ resourceType, resourceKey })), + catchError((error) => of(deleteReferenceDataItemFailure({ error: error.message }))) + ); + }) + ) + ); } -function isPaginated(referenceDataApiResponse: ReferenceDataApiResponse): referenceDataApiResponse is ReferenceDataApiResponseWithPagination { - return Object.prototype.hasOwnProperty.call(referenceDataApiResponse, 'paginationToken'); +function isPaginated( + referenceDataApiResponse: ReferenceDataApiResponse +): referenceDataApiResponse is ReferenceDataApiResponseWithPagination { + return Object.prototype.hasOwnProperty.call(referenceDataApiResponse, 'paginationToken'); } diff --git a/src/app/store/reference-data/reducers/reference-data.reducer.spec.ts b/src/app/store/reference-data/reducers/reference-data.reducer.spec.ts index 54bf8cf505..9c6c511e00 100644 --- a/src/app/store/reference-data/reducers/reference-data.reducer.spec.ts +++ b/src/app/store/reference-data/reducers/reference-data.reducer.spec.ts @@ -3,493 +3,511 @@ import { ReferenceDataModelBase, ReferenceDataResourceType } from '@models/refer import { Dictionary } from '@ngrx/entity'; import cloneDeep from 'lodash.clonedeep'; import { - addSearchInformation, - amendReferenceDataItemSuccess, - createReferenceDataItemSuccess, - deleteReferenceDataItemSuccess, - fetchReferenceData, - fetchReferenceDataAudit, - fetchReferenceDataAuditFailed, - fetchReferenceDataAuditSuccess, - fetchReferenceDataByKey, - fetchReferenceDataByKeyFailed, - fetchReferenceDataByKeySearch, - fetchReferenceDataByKeySearchFailed, - fetchReferenceDataByKeySearchSuccess, - fetchReferenceDataByKeySuccess, - fetchReferenceDataFailed, - fetchReferenceDataSuccess, - fetchTyreReferenceDataByKeySearch, - fetchTyreReferenceDataByKeySearchFailed, - fetchTyreReferenceDataByKeySearchSuccess, - removeTyreSearch, + addSearchInformation, + amendReferenceDataItemSuccess, + createReferenceDataItemSuccess, + deleteReferenceDataItemSuccess, + fetchReferenceData, + fetchReferenceDataAudit, + fetchReferenceDataAuditFailed, + fetchReferenceDataAuditSuccess, + fetchReferenceDataByKey, + fetchReferenceDataByKeyFailed, + fetchReferenceDataByKeySearch, + fetchReferenceDataByKeySearchFailed, + fetchReferenceDataByKeySearchSuccess, + fetchReferenceDataByKeySuccess, + fetchReferenceDataFailed, + fetchReferenceDataSuccess, + fetchTyreReferenceDataByKeySearch, + fetchTyreReferenceDataByKeySearchFailed, + fetchTyreReferenceDataByKeySearchSuccess, + removeTyreSearch, } from '../actions/reference-data.actions'; import { testCases } from '../reference-data.test-cases'; import { ReferenceDataState, initialReferenceDataState, referenceDataReducer } from './reference-data.reducer'; describe('Reference Data Reducer', () => { - describe('unknown action', () => { - it('should return the default state', () => { - const action = { - type: 'Unknown', - }; - const state = referenceDataReducer(initialReferenceDataState, action); - - expect(state).toBe(initialReferenceDataState); - }); - }); - - describe('fetchReferenceData', () => { - it('should set loading to true', () => { - const newState: ReferenceDataState = { - ...initialReferenceDataState, - [ReferenceDataResourceType.CountryOfRegistration]: { - ...initialReferenceDataState[ReferenceDataResourceType.CountryOfRegistration], - loading: true, - }, - }; - const action = fetchReferenceData({ resourceType: ReferenceDataResourceType.CountryOfRegistration }); - const state = referenceDataReducer(initialReferenceDataState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('fetchReferenceDataSuccess', () => { - it.each(testCases)('should set all reference data on success', (value) => { - const { resourceType, payload } = value; - const ids = payload.map((v) => v.resourceKey); - const entities: Dictionary = payload.reduce( - (acc, v) => ({ ...acc, [v.resourceKey]: v }), - {} as { [V in ReferenceDataModelBase as V['resourceKey']]: V }, - ); - const newState: ReferenceDataState = { - ...initialReferenceDataState, - [resourceType]: { ids, entities, loading: false }, - }; - const action = fetchReferenceDataSuccess({ resourceType, payload: [...payload], paginated: false }); - const state = referenceDataReducer(initialReferenceDataState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('fetchReferenceDataFailed', () => { - it('should set error state', () => { - const newState = { ...initialReferenceDataState }; - const action = fetchReferenceDataFailed({ error: 'unit testing error message', resourceType: ReferenceDataResourceType.CountryOfRegistration }); - const state = referenceDataReducer({ ...initialReferenceDataState }, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('fetchReferenceDataAudit', () => { - it('should set loading to true', () => { - const newState: ReferenceDataState = { - ...initialReferenceDataState, - [ReferenceDataResourceType.CountryOfRegistration]: { - ...initialReferenceDataState[ReferenceDataResourceType.CountryOfRegistration], - loading: true, - }, - }; - const action = fetchReferenceDataAudit({ resourceType: ReferenceDataResourceType.CountryOfRegistration }); - const state = referenceDataReducer(initialReferenceDataState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('fetchReferenceDataAuditSuccess', () => { - it.each(testCases)('should set the the resource data item based on the type', (value) => { - const { resourceType } = value; - const newState: ReferenceDataState = { - ...initialReferenceDataState, - [resourceType]: { ...initialReferenceDataState[`${resourceType}`], searchReturn: value.payload, loading: false }, - }; - - const action = fetchReferenceDataAuditSuccess({ resourceType, payload: value.payload, paginated: false }); - const state = referenceDataReducer(initialReferenceDataState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('fetchReferenceDataAuditFailed', () => { - it('should set error state', () => { - const newState = { ...initialReferenceDataState }; - const action = fetchReferenceDataAuditFailed({ - error: 'unit testing error message', - resourceType: ReferenceDataResourceType.CountryOfRegistration, - }); - const state = referenceDataReducer({ ...initialReferenceDataState }, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('fetchReferenceDataByKey actions', () => { - it('should set loading to true', () => { - const newState: ReferenceDataState = { - ...initialReferenceDataState, - [ReferenceDataResourceType.CountryOfRegistration]: { - ...initialReferenceDataState[ReferenceDataResourceType.CountryOfRegistration], - loading: true, - }, - }; - const action = fetchReferenceDataByKey({ - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: mockCountriesOfRegistration[0].resourceKey, - }); - const state = referenceDataReducer(initialReferenceDataState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - - describe('fetchReferenceDataByKeySuccess', () => { - it.each(testCases)('should set the the resource data item based on the type and key', (value) => { - const { resourceType, resourceKey, payload } = value; - - const entity = payload.find((p) => p.resourceKey === resourceKey) as ReferenceDataModelBase; - const ids = [resourceKey]; - const entities: Dictionary = { [resourceKey]: entity }; - const newState: ReferenceDataState = { - ...initialReferenceDataState, - [resourceType]: { ids, entities, loading: false }, - }; - - const action = fetchReferenceDataByKeySuccess({ resourceType, resourceKey, payload: entity }); - const state = referenceDataReducer(initialReferenceDataState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('fetchReferenceDataByKeyFailed', () => { - it('should set error state', () => { - const newState = { ...initialReferenceDataState }; - const action = fetchReferenceDataByKeyFailed({ - error: 'unit testing error message by key', - resourceType: ReferenceDataResourceType.CountryOfRegistration, - }); - const inputState = { - ...initialReferenceDataState, - [ReferenceDataResourceType.CountryOfRegistration]: { - ...initialReferenceDataState[ReferenceDataResourceType.CountryOfRegistration], - loading: true, - }, - }; - const state = referenceDataReducer(inputState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - }); - - describe('fetchReferenceDataByKeySearch actions', () => { - it('should set loading to true', () => { - const newState: ReferenceDataState = { - ...initialReferenceDataState, - [ReferenceDataResourceType.Tyres]: { - ...initialReferenceDataState[ReferenceDataResourceType.Tyres], - searchReturn: null, - loading: true, - }, - }; - const action = fetchReferenceDataByKeySearch({ - resourceType: ReferenceDataResourceType.Tyres, - resourceKey: '101', - }); - const state = referenceDataReducer(initialReferenceDataState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - - describe('fetchReferenceDataByKeySearchSuccess', () => { - it('should set the the resource data item based on the type and key', () => { - const resourceType = ReferenceDataResourceType.Tyres; - const resourceKey = '123'; - const value = { - payload: [ - { - tyreCode: '123', - resourceType: ReferenceDataResourceType.Tyres, - resourceKey: '123', - code: '123', - loadIndexSingleLoad: '102', - tyreSize: 'size', - dateTimeStamp: 'time', - userId: '1234', - loadIndexTwinLoad: '101', - plyRating: '18', - }, - ], - }; - const newState: ReferenceDataState = { - ...initialReferenceDataState, - [resourceType]: { ...initialReferenceDataState[`${resourceType}`], searchReturn: value.payload, loading: false }, - }; - - const action = fetchReferenceDataByKeySearchSuccess({ resourceType, resourceKey, payload: value.payload }); - const state = referenceDataReducer(initialReferenceDataState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('fetchReferenceDataByKeySearchFailed', () => { - it('should set error state', () => { - const newState = { - ...initialReferenceDataState, - [ReferenceDataResourceType.Tyres]: { - ...initialReferenceDataState[ReferenceDataResourceType.Tyres], - searchReturn: null, - loading: false, - filter: null, - term: null, - }, - }; - const action = fetchReferenceDataByKeySearchFailed({ - error: 'unit testing error message by key', - resourceType: ReferenceDataResourceType.Tyres, - }); - const inputState = { - ...initialReferenceDataState, - [ReferenceDataResourceType.Tyres]: { - ...initialReferenceDataState[ReferenceDataResourceType.Tyres], - loading: true, - }, - }; - const state = referenceDataReducer(inputState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - }); - - describe('fetchTyreReferenceDataByKeySearch actions', () => { - it('should set loading to true', () => { - const newState: ReferenceDataState = { - ...initialReferenceDataState, - [ReferenceDataResourceType.Tyres]: { - ...initialReferenceDataState[ReferenceDataResourceType.Tyres], - searchReturn: null, - loading: true, - }, - }; - const action = fetchTyreReferenceDataByKeySearch({ - searchTerm: 'plyrating', - searchFilter: '101', - }); - const state = referenceDataReducer(initialReferenceDataState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - - describe('fetchTyreReferenceDataByKeySearchSuccess', () => { - it('should set the the resource data item based on the type and key', () => { - const resourceType = ReferenceDataResourceType.Tyres; - const value = { - payload: [ - { - tyreCode: '123', - resourceType: ReferenceDataResourceType.Tyres, - resourceKey: '123', - code: '123', - loadIndexSingleLoad: '102', - tyreSize: 'size', - dateTimeStamp: 'time', - userId: '1234', - loadIndexTwinLoad: '101', - plyRating: '18', - }, - ], - }; - const newState: ReferenceDataState = { - ...initialReferenceDataState, - [resourceType]: { ...initialReferenceDataState[`${resourceType}`], searchReturn: value.payload, loading: false }, - }; - - const action = fetchTyreReferenceDataByKeySearchSuccess({ resourceType, payload: value.payload }); - const state = referenceDataReducer(initialReferenceDataState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('addSearchInformation', () => { - it('should update state term and filter', () => { - const newState = { - ...initialReferenceDataState, - [ReferenceDataResourceType.Tyres]: { - ...initialReferenceDataState[ReferenceDataResourceType.Tyres], - loading: false, - filter: 'code', - term: '103', - }, - }; - - const filter = 'code'; - const term = '103'; - const action = addSearchInformation({ filter, term }); - const state = referenceDataReducer(initialReferenceDataState, action); - - expect(state.TYRES).toStrictEqual(newState.TYRES); - }); - }); - - describe('removeTyreSearch', () => { - it('should null search return', () => { - const action = removeTyreSearch(); - const state = referenceDataReducer(initialReferenceDataState, action); - - expect(state.TYRES).toStrictEqual({ - ids: [], - entities: {}, - loading: false, - searchReturn: null, - filter: null, - term: null, - }); - }); - }); - - describe('fetchTyreReferenceDataByKeySearchFailed', () => { - it('should set error state', () => { - const newState = { - ...initialReferenceDataState, - [ReferenceDataResourceType.Tyres]: { - ...initialReferenceDataState[ReferenceDataResourceType.Tyres], - searchReturn: null, - loading: false, - filter: null, - term: null, - }, - }; - const action = fetchTyreReferenceDataByKeySearchFailed({ - error: 'unit testing error message by key', - resourceType: ReferenceDataResourceType.Tyres, - }); - const inputState = { - ...initialReferenceDataState, - [ReferenceDataResourceType.Tyres]: { - ...initialReferenceDataState[ReferenceDataResourceType.Tyres], - loading: true, - }, - }; - const state = referenceDataReducer(inputState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - }); - describe('deleteReferenceDataItemSuccess', () => { - it('should remove the specified item from the reference data state', () => { - const newItem = { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'test', - description: 'test', - }; - const inputState = cloneDeep(initialReferenceDataState); - - inputState[ReferenceDataResourceType.CountryOfRegistration].entities['test'] = newItem; - inputState[ReferenceDataResourceType.CountryOfRegistration].ids = ['test']; - const action = deleteReferenceDataItemSuccess({ - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'test', - }); - - const reducer = referenceDataReducer(inputState, action); - expect(reducer).toEqual(initialReferenceDataState); - }); - it('should leave any unspecified items in state', () => { - const newItem = { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'test', - description: 'test', - }; - const newItem2 = { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'test2', - description: 'test2', - }; - const inputState = cloneDeep(initialReferenceDataState); - - inputState[ReferenceDataResourceType.CountryOfRegistration].entities['test'] = newItem; - inputState[ReferenceDataResourceType.CountryOfRegistration].ids = ['test']; - inputState[ReferenceDataResourceType.CountryOfRegistration].entities['test2'] = newItem2; - inputState[ReferenceDataResourceType.CountryOfRegistration].ids = ['test2']; - - const action = deleteReferenceDataItemSuccess({ - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'test', - }); - - const reducer = referenceDataReducer(inputState, action); - - expect(reducer).not.toEqual(initialReferenceDataState); - expect(reducer[ReferenceDataResourceType.CountryOfRegistration].entities).toEqual({ test2: newItem2 }); - expect(reducer[ReferenceDataResourceType.CountryOfRegistration].ids).toEqual(['test2']); - }); - }); - describe('createReferenceDataItemSuccess', () => { - it('should insert the new item into the reference data state', () => { - const testItem = { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'test', - description: 'test', - }; - const testItem2 = { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'test2', - description: 'test2', - }; - const inputState = cloneDeep(initialReferenceDataState); - inputState[ReferenceDataResourceType.CountryOfRegistration].entities = { test2: testItem2 }; - inputState[ReferenceDataResourceType.CountryOfRegistration].ids = ['test2']; - - const action = createReferenceDataItemSuccess({ result: testItem }); - const reducer = referenceDataReducer(inputState, action); - expect(reducer[ReferenceDataResourceType.CountryOfRegistration].entities).toEqual({ test: testItem, test2: testItem2 }); - expect(reducer[ReferenceDataResourceType.CountryOfRegistration].ids).toEqual(['test2', 'test']); - }); - }); - describe('amendReferenceDataItemSuccess', () => { - it('should insert the new item into the reference data state', () => { - const itemToAmend = { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'test', - description: 'test', - }; - const amendedItem = { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'test', - description: 'this has been amended', - }; - const inputState = cloneDeep(initialReferenceDataState); - inputState[ReferenceDataResourceType.CountryOfRegistration].entities = { test: itemToAmend }; - inputState[ReferenceDataResourceType.CountryOfRegistration].ids = ['test']; - - const action = amendReferenceDataItemSuccess({ result: amendedItem }); - const reducer = referenceDataReducer(inputState, action); - - expect(reducer[ReferenceDataResourceType.CountryOfRegistration].entities).toEqual({ test: amendedItem }); - expect(reducer[ReferenceDataResourceType.CountryOfRegistration].ids).toEqual(['test']); - }); - }); + describe('unknown action', () => { + it('should return the default state', () => { + const action = { + type: 'Unknown', + }; + const state = referenceDataReducer(initialReferenceDataState, action); + + expect(state).toBe(initialReferenceDataState); + }); + }); + + describe('fetchReferenceData', () => { + it('should set loading to true', () => { + const newState: ReferenceDataState = { + ...initialReferenceDataState, + [ReferenceDataResourceType.CountryOfRegistration]: { + ...initialReferenceDataState[ReferenceDataResourceType.CountryOfRegistration], + loading: true, + }, + }; + const action = fetchReferenceData({ resourceType: ReferenceDataResourceType.CountryOfRegistration }); + const state = referenceDataReducer(initialReferenceDataState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('fetchReferenceDataSuccess', () => { + it.each(testCases)('should set all reference data on success', (value) => { + const { resourceType, payload } = value; + const ids = payload.map((v) => v.resourceKey); + const entities: Dictionary = payload.reduce( + (acc, v) => ({ ...acc, [v.resourceKey]: v }), + {} as { [V in ReferenceDataModelBase as V['resourceKey']]: V } + ); + const newState: ReferenceDataState = { + ...initialReferenceDataState, + [resourceType]: { ids, entities, loading: false }, + }; + const action = fetchReferenceDataSuccess({ resourceType, payload: [...payload], paginated: false }); + const state = referenceDataReducer(initialReferenceDataState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('fetchReferenceDataFailed', () => { + it('should set error state', () => { + const newState = { ...initialReferenceDataState }; + const action = fetchReferenceDataFailed({ + error: 'unit testing error message', + resourceType: ReferenceDataResourceType.CountryOfRegistration, + }); + const state = referenceDataReducer({ ...initialReferenceDataState }, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('fetchReferenceDataAudit', () => { + it('should set loading to true', () => { + const newState: ReferenceDataState = { + ...initialReferenceDataState, + [ReferenceDataResourceType.CountryOfRegistration]: { + ...initialReferenceDataState[ReferenceDataResourceType.CountryOfRegistration], + loading: true, + }, + }; + const action = fetchReferenceDataAudit({ resourceType: ReferenceDataResourceType.CountryOfRegistration }); + const state = referenceDataReducer(initialReferenceDataState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('fetchReferenceDataAuditSuccess', () => { + it.each(testCases)('should set the the resource data item based on the type', (value) => { + const { resourceType } = value; + const newState: ReferenceDataState = { + ...initialReferenceDataState, + [resourceType]: { + ...initialReferenceDataState[`${resourceType}`], + searchReturn: value.payload, + loading: false, + }, + }; + + const action = fetchReferenceDataAuditSuccess({ resourceType, payload: value.payload, paginated: false }); + const state = referenceDataReducer(initialReferenceDataState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('fetchReferenceDataAuditFailed', () => { + it('should set error state', () => { + const newState = { ...initialReferenceDataState }; + const action = fetchReferenceDataAuditFailed({ + error: 'unit testing error message', + resourceType: ReferenceDataResourceType.CountryOfRegistration, + }); + const state = referenceDataReducer({ ...initialReferenceDataState }, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('fetchReferenceDataByKey actions', () => { + it('should set loading to true', () => { + const newState: ReferenceDataState = { + ...initialReferenceDataState, + [ReferenceDataResourceType.CountryOfRegistration]: { + ...initialReferenceDataState[ReferenceDataResourceType.CountryOfRegistration], + loading: true, + }, + }; + const action = fetchReferenceDataByKey({ + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: mockCountriesOfRegistration[0].resourceKey, + }); + const state = referenceDataReducer(initialReferenceDataState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + + describe('fetchReferenceDataByKeySuccess', () => { + it.each(testCases)('should set the the resource data item based on the type and key', (value) => { + const { resourceType, resourceKey, payload } = value; + + const entity = payload.find((p) => p.resourceKey === resourceKey) as ReferenceDataModelBase; + const ids = [resourceKey]; + const entities: Dictionary = { [resourceKey]: entity }; + const newState: ReferenceDataState = { + ...initialReferenceDataState, + [resourceType]: { ids, entities, loading: false }, + }; + + const action = fetchReferenceDataByKeySuccess({ resourceType, resourceKey, payload: entity }); + const state = referenceDataReducer(initialReferenceDataState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('fetchReferenceDataByKeyFailed', () => { + it('should set error state', () => { + const newState = { ...initialReferenceDataState }; + const action = fetchReferenceDataByKeyFailed({ + error: 'unit testing error message by key', + resourceType: ReferenceDataResourceType.CountryOfRegistration, + }); + const inputState = { + ...initialReferenceDataState, + [ReferenceDataResourceType.CountryOfRegistration]: { + ...initialReferenceDataState[ReferenceDataResourceType.CountryOfRegistration], + loading: true, + }, + }; + const state = referenceDataReducer(inputState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + }); + + describe('fetchReferenceDataByKeySearch actions', () => { + it('should set loading to true', () => { + const newState: ReferenceDataState = { + ...initialReferenceDataState, + [ReferenceDataResourceType.Tyres]: { + ...initialReferenceDataState[ReferenceDataResourceType.Tyres], + searchReturn: null, + loading: true, + }, + }; + const action = fetchReferenceDataByKeySearch({ + resourceType: ReferenceDataResourceType.Tyres, + resourceKey: '101', + }); + const state = referenceDataReducer(initialReferenceDataState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + + describe('fetchReferenceDataByKeySearchSuccess', () => { + it('should set the the resource data item based on the type and key', () => { + const resourceType = ReferenceDataResourceType.Tyres; + const resourceKey = '123'; + const value = { + payload: [ + { + tyreCode: '123', + resourceType: ReferenceDataResourceType.Tyres, + resourceKey: '123', + code: '123', + loadIndexSingleLoad: '102', + tyreSize: 'size', + dateTimeStamp: 'time', + userId: '1234', + loadIndexTwinLoad: '101', + plyRating: '18', + }, + ], + }; + const newState: ReferenceDataState = { + ...initialReferenceDataState, + [resourceType]: { + ...initialReferenceDataState[`${resourceType}`], + searchReturn: value.payload, + loading: false, + }, + }; + + const action = fetchReferenceDataByKeySearchSuccess({ resourceType, resourceKey, payload: value.payload }); + const state = referenceDataReducer(initialReferenceDataState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('fetchReferenceDataByKeySearchFailed', () => { + it('should set error state', () => { + const newState = { + ...initialReferenceDataState, + [ReferenceDataResourceType.Tyres]: { + ...initialReferenceDataState[ReferenceDataResourceType.Tyres], + searchReturn: null, + loading: false, + filter: null, + term: null, + }, + }; + const action = fetchReferenceDataByKeySearchFailed({ + error: 'unit testing error message by key', + resourceType: ReferenceDataResourceType.Tyres, + }); + const inputState = { + ...initialReferenceDataState, + [ReferenceDataResourceType.Tyres]: { + ...initialReferenceDataState[ReferenceDataResourceType.Tyres], + loading: true, + }, + }; + const state = referenceDataReducer(inputState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + }); + + describe('fetchTyreReferenceDataByKeySearch actions', () => { + it('should set loading to true', () => { + const newState: ReferenceDataState = { + ...initialReferenceDataState, + [ReferenceDataResourceType.Tyres]: { + ...initialReferenceDataState[ReferenceDataResourceType.Tyres], + searchReturn: null, + loading: true, + }, + }; + const action = fetchTyreReferenceDataByKeySearch({ + searchTerm: 'plyrating', + searchFilter: '101', + }); + const state = referenceDataReducer(initialReferenceDataState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + + describe('fetchTyreReferenceDataByKeySearchSuccess', () => { + it('should set the the resource data item based on the type and key', () => { + const resourceType = ReferenceDataResourceType.Tyres; + const value = { + payload: [ + { + tyreCode: '123', + resourceType: ReferenceDataResourceType.Tyres, + resourceKey: '123', + code: '123', + loadIndexSingleLoad: '102', + tyreSize: 'size', + dateTimeStamp: 'time', + userId: '1234', + loadIndexTwinLoad: '101', + plyRating: '18', + }, + ], + }; + const newState: ReferenceDataState = { + ...initialReferenceDataState, + [resourceType]: { + ...initialReferenceDataState[`${resourceType}`], + searchReturn: value.payload, + loading: false, + }, + }; + + const action = fetchTyreReferenceDataByKeySearchSuccess({ resourceType, payload: value.payload }); + const state = referenceDataReducer(initialReferenceDataState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('addSearchInformation', () => { + it('should update state term and filter', () => { + const newState = { + ...initialReferenceDataState, + [ReferenceDataResourceType.Tyres]: { + ...initialReferenceDataState[ReferenceDataResourceType.Tyres], + loading: false, + filter: 'code', + term: '103', + }, + }; + + const filter = 'code'; + const term = '103'; + const action = addSearchInformation({ filter, term }); + const state = referenceDataReducer(initialReferenceDataState, action); + + expect(state.TYRES).toStrictEqual(newState.TYRES); + }); + }); + + describe('removeTyreSearch', () => { + it('should null search return', () => { + const action = removeTyreSearch(); + const state = referenceDataReducer(initialReferenceDataState, action); + + expect(state.TYRES).toStrictEqual({ + ids: [], + entities: {}, + loading: false, + searchReturn: null, + filter: null, + term: null, + }); + }); + }); + + describe('fetchTyreReferenceDataByKeySearchFailed', () => { + it('should set error state', () => { + const newState = { + ...initialReferenceDataState, + [ReferenceDataResourceType.Tyres]: { + ...initialReferenceDataState[ReferenceDataResourceType.Tyres], + searchReturn: null, + loading: false, + filter: null, + term: null, + }, + }; + const action = fetchTyreReferenceDataByKeySearchFailed({ + error: 'unit testing error message by key', + resourceType: ReferenceDataResourceType.Tyres, + }); + const inputState = { + ...initialReferenceDataState, + [ReferenceDataResourceType.Tyres]: { + ...initialReferenceDataState[ReferenceDataResourceType.Tyres], + loading: true, + }, + }; + const state = referenceDataReducer(inputState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + }); + describe('deleteReferenceDataItemSuccess', () => { + it('should remove the specified item from the reference data state', () => { + const newItem = { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'test', + description: 'test', + }; + const inputState = cloneDeep(initialReferenceDataState); + + inputState[ReferenceDataResourceType.CountryOfRegistration].entities['test'] = newItem; + inputState[ReferenceDataResourceType.CountryOfRegistration].ids = ['test']; + const action = deleteReferenceDataItemSuccess({ + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'test', + }); + + const reducer = referenceDataReducer(inputState, action); + expect(reducer).toEqual(initialReferenceDataState); + }); + it('should leave any unspecified items in state', () => { + const newItem = { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'test', + description: 'test', + }; + const newItem2 = { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'test2', + description: 'test2', + }; + const inputState = cloneDeep(initialReferenceDataState); + + inputState[ReferenceDataResourceType.CountryOfRegistration].entities['test'] = newItem; + inputState[ReferenceDataResourceType.CountryOfRegistration].ids = ['test']; + inputState[ReferenceDataResourceType.CountryOfRegistration].entities['test2'] = newItem2; + inputState[ReferenceDataResourceType.CountryOfRegistration].ids = ['test2']; + + const action = deleteReferenceDataItemSuccess({ + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'test', + }); + + const reducer = referenceDataReducer(inputState, action); + + expect(reducer).not.toEqual(initialReferenceDataState); + expect(reducer[ReferenceDataResourceType.CountryOfRegistration].entities).toEqual({ test2: newItem2 }); + expect(reducer[ReferenceDataResourceType.CountryOfRegistration].ids).toEqual(['test2']); + }); + }); + describe('createReferenceDataItemSuccess', () => { + it('should insert the new item into the reference data state', () => { + const testItem = { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'test', + description: 'test', + }; + const testItem2 = { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'test2', + description: 'test2', + }; + const inputState = cloneDeep(initialReferenceDataState); + inputState[ReferenceDataResourceType.CountryOfRegistration].entities = { test2: testItem2 }; + inputState[ReferenceDataResourceType.CountryOfRegistration].ids = ['test2']; + + const action = createReferenceDataItemSuccess({ result: testItem }); + const reducer = referenceDataReducer(inputState, action); + expect(reducer[ReferenceDataResourceType.CountryOfRegistration].entities).toEqual({ + test: testItem, + test2: testItem2, + }); + expect(reducer[ReferenceDataResourceType.CountryOfRegistration].ids).toEqual(['test2', 'test']); + }); + }); + describe('amendReferenceDataItemSuccess', () => { + it('should insert the new item into the reference data state', () => { + const itemToAmend = { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'test', + description: 'test', + }; + const amendedItem = { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'test', + description: 'this has been amended', + }; + const inputState = cloneDeep(initialReferenceDataState); + inputState[ReferenceDataResourceType.CountryOfRegistration].entities = { test: itemToAmend }; + inputState[ReferenceDataResourceType.CountryOfRegistration].ids = ['test']; + + const action = amendReferenceDataItemSuccess({ result: amendedItem }); + const reducer = referenceDataReducer(inputState, action); + + expect(reducer[ReferenceDataResourceType.CountryOfRegistration].entities).toEqual({ test: amendedItem }); + expect(reducer[ReferenceDataResourceType.CountryOfRegistration].ids).toEqual(['test']); + }); + }); }); diff --git a/src/app/store/reference-data/reducers/reference-data.reducer.ts b/src/app/store/reference-data/reducers/reference-data.reducer.ts index eddbdb819a..f52e8dae0d 100644 --- a/src/app/store/reference-data/reducers/reference-data.reducer.ts +++ b/src/app/store/reference-data/reducers/reference-data.reducer.ts @@ -1,195 +1,253 @@ import { ReferenceDataModelBase, ReferenceDataResourceType } from '@models/reference-data.model'; -import { createEntityAdapter, EntityAdapter, EntityState } from '@ngrx/entity'; +import { EntityAdapter, EntityState, createEntityAdapter } from '@ngrx/entity'; import { createFeatureSelector, createReducer, on } from '@ngrx/store'; import cloneDeep from 'lodash.clonedeep'; import { - addSearchInformation, - amendReferenceDataItemSuccess, - createReferenceDataItemSuccess, - deleteReferenceDataItemSuccess, - fetchReferenceData, - fetchReferenceDataAudit, - fetchReferenceDataAuditFailed, - fetchReferenceDataAuditSuccess, - fetchReferenceDataByKey, - fetchReferenceDataByKeyFailed, - fetchReferenceDataByKeySearch, - fetchReferenceDataByKeySearchFailed, - fetchReferenceDataByKeySearchSuccess, - fetchReferenceDataByKeySuccess, - fetchReferenceDataFailed, - fetchReferenceDataSuccess, - fetchTyreReferenceDataByKeySearch, - fetchTyreReferenceDataByKeySearchFailed, - fetchTyreReferenceDataByKeySearchSuccess, - removeTyreSearch, + addSearchInformation, + amendReferenceDataItemSuccess, + createReferenceDataItemSuccess, + deleteReferenceDataItemSuccess, + fetchReferenceData, + fetchReferenceDataAudit, + fetchReferenceDataAuditFailed, + fetchReferenceDataAuditSuccess, + fetchReferenceDataByKey, + fetchReferenceDataByKeyFailed, + fetchReferenceDataByKeySearch, + fetchReferenceDataByKeySearchFailed, + fetchReferenceDataByKeySearchSuccess, + fetchReferenceDataByKeySuccess, + fetchReferenceDataFailed, + fetchReferenceDataSuccess, + fetchTyreReferenceDataByKeySearch, + fetchTyreReferenceDataByKeySearchFailed, + fetchTyreReferenceDataByKeySearchSuccess, + removeTyreSearch, } from '../actions/reference-data.actions'; export const STORE_FEATURE_REFERENCE_DATA_KEY = 'referenceData'; const selectResourceKey = (a: ReferenceDataModelBase): string | number => { - return a.resourceKey; + return a.resourceKey; }; interface ReferenceDataEntityState extends EntityState { - loading: boolean; + loading: boolean; } export interface ReferenceDataEntityStateSearch extends EntityState { - loading: boolean; - searchReturn: ReferenceDataModelBase[] | null; - term: string | null; - filter: string | null; + loading: boolean; + searchReturn: ReferenceDataModelBase[] | null; + term: string | null; + filter: string | null; } -export type ReferenceDataState = Record; +export type ReferenceDataState = Record< + ReferenceDataResourceType, + ReferenceDataEntityState | ReferenceDataEntityStateSearch +>; function createAdapter() { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return createEntityAdapter({ selectId: selectResourceKey as any }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return createEntityAdapter({ selectId: selectResourceKey as any }); } function getInitialState(resourceType: ReferenceDataResourceType) { - return resourceTypeAdapters[`${resourceType}`].getInitialState({ loading: false }); + return resourceTypeAdapters[`${resourceType}`].getInitialState({ loading: false }); } export const resourceTypeAdapters: Record> = { - [ReferenceDataResourceType.Brakes]: createAdapter(), - [ReferenceDataResourceType.CountryOfRegistration]: createAdapter(), - [ReferenceDataResourceType.HgvMake]: createAdapter(), - [ReferenceDataResourceType.PsvMake]: createAdapter(), - [ReferenceDataResourceType.ReasonsForAbandoningHgv]: createAdapter(), - [ReferenceDataResourceType.ReasonsForAbandoningPsv]: createAdapter(), - [ReferenceDataResourceType.ReasonsForAbandoningTrl]: createAdapter(), - [ReferenceDataResourceType.ReferenceDataAdminType]: createAdapter(), - [ReferenceDataResourceType.SpecialistReasonsForAbandoning]: createAdapter(), - [ReferenceDataResourceType.TirReasonsForAbandoning]: createAdapter(), - [ReferenceDataResourceType.TrlMake]: createAdapter(), - [ReferenceDataResourceType.Tyres]: createAdapter(), - [ReferenceDataResourceType.User]: createAdapter(), - [ReferenceDataResourceType.TyreLoadIndex]: createAdapter(), + [ReferenceDataResourceType.Brakes]: createAdapter(), + [ReferenceDataResourceType.CountryOfRegistration]: createAdapter(), + [ReferenceDataResourceType.HgvMake]: createAdapter(), + [ReferenceDataResourceType.PsvMake]: createAdapter(), + [ReferenceDataResourceType.ReasonsForAbandoningHgv]: createAdapter(), + [ReferenceDataResourceType.ReasonsForAbandoningPsv]: createAdapter(), + [ReferenceDataResourceType.ReasonsForAbandoningTrl]: createAdapter(), + [ReferenceDataResourceType.ReferenceDataAdminType]: createAdapter(), + [ReferenceDataResourceType.SpecialistReasonsForAbandoning]: createAdapter(), + [ReferenceDataResourceType.TirReasonsForAbandoning]: createAdapter(), + [ReferenceDataResourceType.TrlMake]: createAdapter(), + [ReferenceDataResourceType.Tyres]: createAdapter(), + [ReferenceDataResourceType.User]: createAdapter(), + [ReferenceDataResourceType.TyreLoadIndex]: createAdapter(), }; // IMPORTANT: Ensure the keys in initialReferenceDataState call get the initial state from the matching resourceType export const initialReferenceDataState: ReferenceDataState = { - [ReferenceDataResourceType.Brakes]: getInitialState(ReferenceDataResourceType.Brakes), - [ReferenceDataResourceType.CountryOfRegistration]: getInitialState(ReferenceDataResourceType.CountryOfRegistration), - [ReferenceDataResourceType.HgvMake]: getInitialState(ReferenceDataResourceType.HgvMake), - [ReferenceDataResourceType.PsvMake]: getInitialState(ReferenceDataResourceType.PsvMake), - [ReferenceDataResourceType.ReasonsForAbandoningTrl]: getInitialState(ReferenceDataResourceType.ReasonsForAbandoningTrl), - [ReferenceDataResourceType.ReasonsForAbandoningHgv]: getInitialState(ReferenceDataResourceType.ReasonsForAbandoningHgv), - [ReferenceDataResourceType.ReasonsForAbandoningPsv]: getInitialState(ReferenceDataResourceType.ReasonsForAbandoningPsv), - [ReferenceDataResourceType.ReferenceDataAdminType]: getInitialState(ReferenceDataResourceType.ReferenceDataAdminType), - [ReferenceDataResourceType.SpecialistReasonsForAbandoning]: getInitialState(ReferenceDataResourceType.SpecialistReasonsForAbandoning), - [ReferenceDataResourceType.TirReasonsForAbandoning]: getInitialState(ReferenceDataResourceType.TirReasonsForAbandoning), - [ReferenceDataResourceType.TrlMake]: getInitialState(ReferenceDataResourceType.TrlMake), - [ReferenceDataResourceType.Tyres]: getInitialState(ReferenceDataResourceType.Tyres), - [ReferenceDataResourceType.User]: getInitialState(ReferenceDataResourceType.User), - [ReferenceDataResourceType.TyreLoadIndex]: getInitialState(ReferenceDataResourceType.TyreLoadIndex), + [ReferenceDataResourceType.Brakes]: getInitialState(ReferenceDataResourceType.Brakes), + [ReferenceDataResourceType.CountryOfRegistration]: getInitialState(ReferenceDataResourceType.CountryOfRegistration), + [ReferenceDataResourceType.HgvMake]: getInitialState(ReferenceDataResourceType.HgvMake), + [ReferenceDataResourceType.PsvMake]: getInitialState(ReferenceDataResourceType.PsvMake), + [ReferenceDataResourceType.ReasonsForAbandoningTrl]: getInitialState( + ReferenceDataResourceType.ReasonsForAbandoningTrl + ), + [ReferenceDataResourceType.ReasonsForAbandoningHgv]: getInitialState( + ReferenceDataResourceType.ReasonsForAbandoningHgv + ), + [ReferenceDataResourceType.ReasonsForAbandoningPsv]: getInitialState( + ReferenceDataResourceType.ReasonsForAbandoningPsv + ), + [ReferenceDataResourceType.ReferenceDataAdminType]: getInitialState(ReferenceDataResourceType.ReferenceDataAdminType), + [ReferenceDataResourceType.SpecialistReasonsForAbandoning]: getInitialState( + ReferenceDataResourceType.SpecialistReasonsForAbandoning + ), + [ReferenceDataResourceType.TirReasonsForAbandoning]: getInitialState( + ReferenceDataResourceType.TirReasonsForAbandoning + ), + [ReferenceDataResourceType.TrlMake]: getInitialState(ReferenceDataResourceType.TrlMake), + [ReferenceDataResourceType.Tyres]: getInitialState(ReferenceDataResourceType.Tyres), + [ReferenceDataResourceType.User]: getInitialState(ReferenceDataResourceType.User), + [ReferenceDataResourceType.TyreLoadIndex]: getInitialState(ReferenceDataResourceType.TyreLoadIndex), }; export const referenceDataReducer = createReducer( - initialReferenceDataState, - on(fetchReferenceData, (state, action) => ({ ...state, [action.resourceType]: { ...state[action.resourceType], loading: true } })), - on(fetchReferenceDataSuccess, (state, action) => { - const { resourceType, payload, paginated } = action; - return { - ...state, - [resourceType]: { ...resourceTypeAdapters[`${resourceType}`]?.upsertMany(payload, state[`${resourceType}`]), loading: paginated }, - }; - }), - on(fetchReferenceDataFailed, (state, action) => ({ ...state, [action.resourceType]: { ...state[action.resourceType], loading: false } })), - on(fetchReferenceDataAudit, (state, action) => ({ ...state, [action.resourceType]: { ...state[action.resourceType], loading: true } })), - on(fetchReferenceDataAuditSuccess, (state, action) => { - const { resourceType, payload, paginated } = action; - return { - ...state, - [resourceType]: { ...state[action.resourceType], searchReturn: payload, loading: paginated }, - }; - }), - on(fetchReferenceDataAuditFailed, (state, action) => ({ ...state, [action.resourceType]: { ...state[action.resourceType], loading: false } })), - on(fetchReferenceDataByKey, (state, action) => ({ ...state, [action.resourceType]: { ...state[action.resourceType], loading: true } })), - on(fetchReferenceDataByKeySuccess, (state, action) => { - const { resourceType, payload } = action; - return { - ...state, - [resourceType]: { ...resourceTypeAdapters[`${resourceType}`].upsertOne(payload, state[`${resourceType}`]), loading: false }, - }; - }), - on(fetchReferenceDataByKeyFailed, (state, action) => ({ ...state, [action.resourceType]: { ...state[action.resourceType], loading: false } })), - on(fetchReferenceDataByKeySearch, (state, action) => ({ - ...state, - [action.resourceType]: { ...state[action.resourceType], searchReturn: null, loading: true }, - })), - on(fetchReferenceDataByKeySearchSuccess, (state, action) => { - const { resourceType, payload } = action; - return { - ...state, - [resourceType]: { ...state[action.resourceType], searchReturn: payload, loading: false }, - }; - }), - on(fetchReferenceDataByKeySearchFailed, (state, action) => ({ - ...state, - [action.resourceType]: { - ...state[action.resourceType], searchReturn: null, loading: false, filter: null, term: null, - }, - })), - on(fetchTyreReferenceDataByKeySearch, (state) => ({ - ...state, - [ReferenceDataResourceType.Tyres]: { ...state[ReferenceDataResourceType.Tyres], searchReturn: null, loading: true }, - })), - on(fetchTyreReferenceDataByKeySearchSuccess, (state, action) => { - const { resourceType, payload } = action; - return { - ...state, - [resourceType]: { ...state[`${resourceType}`], searchReturn: payload, loading: false }, - }; - }), - on(fetchTyreReferenceDataByKeySearchFailed, (state, action) => ({ - ...state, - [action.resourceType]: { - ...state[action.resourceType], searchReturn: null, loading: false, filter: null, term: null, - }, - })), - on(removeTyreSearch, (state) => ({ - ...state, - [ReferenceDataResourceType.Tyres]: { - ...state[ReferenceDataResourceType.Tyres], searchReturn: null, filter: null, term: null, - }, - })), - on(deleteReferenceDataItemSuccess, (state, action) => { - const { resourceType, resourceKey } = action; - const currentState = cloneDeep(state); - - currentState[`${resourceType}`] = resourceTypeAdapters[`${resourceType}`].removeOne(resourceKey, currentState[`${resourceType}`]); - - return currentState; - }), - on(amendReferenceDataItemSuccess, (state, action) => { - const { result } = action; - const { resourceKey, resourceType } = result; - const currentState = cloneDeep(state); - - currentState[`${resourceType}`] = resourceTypeAdapters[`${resourceType}`].updateOne( - { id: resourceKey.toString(), changes: result }, - currentState[`${resourceType}`], - ); - - return currentState; - }), - on(createReferenceDataItemSuccess, (state, action) => { - const { result } = action; - const { resourceType } = result; - const currentState = cloneDeep(state); - - currentState[`${resourceType}`] = resourceTypeAdapters[`${resourceType}`].addOne(result, currentState[`${resourceType}`]); - - return currentState; - }), - on(addSearchInformation, (state, action) => ({ - ...state, - [ReferenceDataResourceType.Tyres]: { ...state[ReferenceDataResourceType.Tyres], filter: action.filter, term: action.term }, - })), + initialReferenceDataState, + on(fetchReferenceData, (state, action) => ({ + ...state, + [action.resourceType]: { ...state[action.resourceType], loading: true }, + })), + on(fetchReferenceDataSuccess, (state, action) => { + const { resourceType, payload, paginated } = action; + return { + ...state, + [resourceType]: { + ...resourceTypeAdapters[`${resourceType}`]?.upsertMany(payload, state[`${resourceType}`]), + loading: paginated, + }, + }; + }), + on(fetchReferenceDataFailed, (state, action) => ({ + ...state, + [action.resourceType]: { ...state[action.resourceType], loading: false }, + })), + on(fetchReferenceDataAudit, (state, action) => ({ + ...state, + [action.resourceType]: { ...state[action.resourceType], loading: true }, + })), + on(fetchReferenceDataAuditSuccess, (state, action) => { + const { resourceType, payload, paginated } = action; + return { + ...state, + [resourceType]: { ...state[action.resourceType], searchReturn: payload, loading: paginated }, + }; + }), + on(fetchReferenceDataAuditFailed, (state, action) => ({ + ...state, + [action.resourceType]: { ...state[action.resourceType], loading: false }, + })), + on(fetchReferenceDataByKey, (state, action) => ({ + ...state, + [action.resourceType]: { ...state[action.resourceType], loading: true }, + })), + on(fetchReferenceDataByKeySuccess, (state, action) => { + const { resourceType, payload } = action; + return { + ...state, + [resourceType]: { + ...resourceTypeAdapters[`${resourceType}`].upsertOne(payload, state[`${resourceType}`]), + loading: false, + }, + }; + }), + on(fetchReferenceDataByKeyFailed, (state, action) => ({ + ...state, + [action.resourceType]: { ...state[action.resourceType], loading: false }, + })), + on(fetchReferenceDataByKeySearch, (state, action) => ({ + ...state, + [action.resourceType]: { ...state[action.resourceType], searchReturn: null, loading: true }, + })), + on(fetchReferenceDataByKeySearchSuccess, (state, action) => { + const { resourceType, payload } = action; + return { + ...state, + [resourceType]: { ...state[action.resourceType], searchReturn: payload, loading: false }, + }; + }), + on(fetchReferenceDataByKeySearchFailed, (state, action) => ({ + ...state, + [action.resourceType]: { + ...state[action.resourceType], + searchReturn: null, + loading: false, + filter: null, + term: null, + }, + })), + on(fetchTyreReferenceDataByKeySearch, (state) => ({ + ...state, + [ReferenceDataResourceType.Tyres]: { ...state[ReferenceDataResourceType.Tyres], searchReturn: null, loading: true }, + })), + on(fetchTyreReferenceDataByKeySearchSuccess, (state, action) => { + const { resourceType, payload } = action; + return { + ...state, + [resourceType]: { ...state[`${resourceType}`], searchReturn: payload, loading: false }, + }; + }), + on(fetchTyreReferenceDataByKeySearchFailed, (state, action) => ({ + ...state, + [action.resourceType]: { + ...state[action.resourceType], + searchReturn: null, + loading: false, + filter: null, + term: null, + }, + })), + on(removeTyreSearch, (state) => ({ + ...state, + [ReferenceDataResourceType.Tyres]: { + ...state[ReferenceDataResourceType.Tyres], + searchReturn: null, + filter: null, + term: null, + }, + })), + on(deleteReferenceDataItemSuccess, (state, action) => { + const { resourceType, resourceKey } = action; + const currentState = cloneDeep(state); + + currentState[`${resourceType}`] = resourceTypeAdapters[`${resourceType}`].removeOne( + resourceKey, + currentState[`${resourceType}`] + ); + + return currentState; + }), + on(amendReferenceDataItemSuccess, (state, action) => { + const { result } = action; + const { resourceKey, resourceType } = result; + const currentState = cloneDeep(state); + + currentState[`${resourceType}`] = resourceTypeAdapters[`${resourceType}`].updateOne( + { id: resourceKey.toString(), changes: result }, + currentState[`${resourceType}`] + ); + + return currentState; + }), + on(createReferenceDataItemSuccess, (state, action) => { + const { result } = action; + const { resourceType } = result; + const currentState = cloneDeep(state); + + currentState[`${resourceType}`] = resourceTypeAdapters[`${resourceType}`].addOne( + result, + currentState[`${resourceType}`] + ); + + return currentState; + }), + on(addSearchInformation, (state, action) => ({ + ...state, + [ReferenceDataResourceType.Tyres]: { + ...state[ReferenceDataResourceType.Tyres], + filter: action.filter, + term: action.term, + }, + })) ); export const referenceDataFeatureState = createFeatureSelector(STORE_FEATURE_REFERENCE_DATA_KEY); diff --git a/src/app/store/reference-data/reference-data.module.ts b/src/app/store/reference-data/reference-data.module.ts index 37e336fe46..6b6de199cd 100644 --- a/src/app/store/reference-data/reference-data.module.ts +++ b/src/app/store/reference-data/reference-data.module.ts @@ -6,11 +6,11 @@ import { ReferenceDataEffects } from './effects/reference-data.effects'; import { STORE_FEATURE_REFERENCE_DATA_KEY, referenceDataReducer } from './reducers/reference-data.reducer'; @NgModule({ - declarations: [], - imports: [ - CommonModule, - StoreModule.forFeature(STORE_FEATURE_REFERENCE_DATA_KEY, referenceDataReducer), - EffectsModule.forFeature([ReferenceDataEffects]), - ], + declarations: [], + imports: [ + CommonModule, + StoreModule.forFeature(STORE_FEATURE_REFERENCE_DATA_KEY, referenceDataReducer), + EffectsModule.forFeature([ReferenceDataEffects]), + ], }) export class ReferenceDataStateModule {} diff --git a/src/app/store/reference-data/reference-data.test-cases.ts b/src/app/store/reference-data/reference-data.test-cases.ts index 118e231c94..2a7319932c 100644 --- a/src/app/store/reference-data/reference-data.test-cases.ts +++ b/src/app/store/reference-data/reference-data.test-cases.ts @@ -2,9 +2,9 @@ import { mockCountriesOfRegistration } from '@mocks/reference-data/mock-countrie import { ReferenceDataResourceType } from '@models/reference-data.model'; export const testCases = [ - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: mockCountriesOfRegistration[0].resourceKey, - payload: mockCountriesOfRegistration, - }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: mockCountriesOfRegistration[0].resourceKey, + payload: mockCountriesOfRegistration, + }, ]; diff --git a/src/app/store/reference-data/selectors/reference-data.selectors.spec.ts b/src/app/store/reference-data/selectors/reference-data.selectors.spec.ts index c672a6be45..73975c54b1 100644 --- a/src/app/store/reference-data/selectors/reference-data.selectors.spec.ts +++ b/src/app/store/reference-data/selectors/reference-data.selectors.spec.ts @@ -7,166 +7,199 @@ import { testCases } from '../reference-data.test-cases'; import * as referenceDataSelectors from './reference-data.selectors'; describe('Reference Data Selectors', () => { - describe('selectAllReferenceDataByResourceType', () => { - it.each(testCases)('should return all of the reference data for given resource type', (value) => { - const { resourceType, payload } = value; - const ids = payload.map((v) => v.resourceKey); - const entities: Dictionary = payload.reduce( - (acc, v) => ({ ...acc, [v.resourceKey]: v }), - {} as { [V in ReferenceDataModelBase as V['resourceKey']]: V }, - ); - const state: ReferenceDataState = { ...initialReferenceDataState, [resourceType]: { ids, entities } }; + describe('selectAllReferenceDataByResourceType', () => { + it.each(testCases)('should return all of the reference data for given resource type', (value) => { + const { resourceType, payload } = value; + const ids = payload.map((v) => v.resourceKey); + const entities: Dictionary = payload.reduce( + (acc, v) => ({ ...acc, [v.resourceKey]: v }), + {} as { [V in ReferenceDataModelBase as V['resourceKey']]: V } + ); + const state: ReferenceDataState = { ...initialReferenceDataState, [resourceType]: { ids, entities } }; - const expectedState = referenceDataSelectors.selectAllReferenceDataByResourceType(resourceType).projector(state[`${resourceType}`]); - expect(expectedState).toHaveLength(mockCountriesOfRegistration.length); - expect(expectedState).toEqual(payload); - }); - }); + const expectedState = referenceDataSelectors + .selectAllReferenceDataByResourceType(resourceType) + .projector(state[`${resourceType}`]); + expect(expectedState).toHaveLength(mockCountriesOfRegistration.length); + expect(expectedState).toEqual(payload); + }); + }); - describe('selectReferenceDataByResourceKey', () => { - it.each(testCases)('should return one specific reference data by type and key', (value) => { - const { resourceType, payload } = value; - const ids: string[] = payload.map((v) => v.resourceKey as string); - const entities: Dictionary = payload.reduce( - (acc, v) => ({ ...acc, [v.resourceKey]: v }), - {} as { [V in ReferenceDataModelBase as V['resourceKey']]: V }, - ); - const state: ReferenceDataState = { ...initialReferenceDataState, COUNTRY_OF_REGISTRATION: { ids, entities, loading: false } }; + describe('selectReferenceDataByResourceKey', () => { + it.each(testCases)('should return one specific reference data by type and key', (value) => { + const { resourceType, payload } = value; + const ids: string[] = payload.map((v) => v.resourceKey as string); + const entities: Dictionary = payload.reduce( + (acc, v) => ({ ...acc, [v.resourceKey]: v }), + {} as { [V in ReferenceDataModelBase as V['resourceKey']]: V } + ); + const state: ReferenceDataState = { + ...initialReferenceDataState, + COUNTRY_OF_REGISTRATION: { ids, entities, loading: false }, + }; - const key = ids[Math.floor(Math.random() * ids.length)]; // select a random key + const key = ids[Math.floor(Math.random() * ids.length)]; // select a random key - const expectedState = referenceDataSelectors.selectReferenceDataByResourceKey(resourceType, key).projector(state); - expect(expectedState).toBe(mockCountriesOfRegistration.find((r) => r.resourceKey === key)); - }); - }); + const expectedState = referenceDataSelectors.selectReferenceDataByResourceKey(resourceType, key).projector(state); + expect(expectedState).toBe(mockCountriesOfRegistration.find((r) => r.resourceKey === key)); + }); + }); - describe('selectTyreSearchReturn', () => { - it('should return the search return state to the user', () => { - const value = { - payload: [ - { - tyreCode: '123', - resourceType: ReferenceDataResourceType.Tyres, - resourceKey: '123', - code: '123', - loadIndexSingleLoad: '102', - tyreSize: 'size', - dateTimeStamp: 'time', - userId: '1234', - loadIndexTwinLoad: '101', - plyRating: '18', - }, - ], - }; + describe('selectTyreSearchReturn', () => { + it('should return the search return state to the user', () => { + const value = { + payload: [ + { + tyreCode: '123', + resourceType: ReferenceDataResourceType.Tyres, + resourceKey: '123', + code: '123', + loadIndexSingleLoad: '102', + tyreSize: 'size', + dateTimeStamp: 'time', + userId: '1234', + loadIndexTwinLoad: '101', + plyRating: '18', + }, + ], + }; - const state: ReferenceDataState = { - ...initialReferenceDataState, - [ReferenceDataResourceType.Tyres]: { - ...initialReferenceDataState[ReferenceDataResourceType.Tyres], - loading: false, - searchReturn: value.payload, - }, - }; + const state: ReferenceDataState = { + ...initialReferenceDataState, + [ReferenceDataResourceType.Tyres]: { + ...initialReferenceDataState[ReferenceDataResourceType.Tyres], + loading: false, + searchReturn: value.payload, + }, + }; - const expectedState = referenceDataSelectors.selectSearchReturn(ReferenceDataResourceType.Tyres).projector(state); - expect(expectedState).toBe(value.payload); - }); - }); - describe('selectTyreSearchCriteria', () => { - it('should return the filter and term state to the user', () => { - const value = { - payload: [ - { - tyreCode: '123', - resourceType: ReferenceDataResourceType.Tyres, - resourceKey: '123', - code: '123', - loadIndexSingleLoad: '102', - tyreSize: 'size', - dateTimeStamp: 'time', - userId: '1234', - loadIndexTwinLoad: '101', - plyRating: '18', - }, - ], - }; + const expectedState = referenceDataSelectors.selectSearchReturn(ReferenceDataResourceType.Tyres).projector(state); + expect(expectedState).toBe(value.payload); + }); + }); + describe('selectTyreSearchCriteria', () => { + it('should return the filter and term state to the user', () => { + const value = { + payload: [ + { + tyreCode: '123', + resourceType: ReferenceDataResourceType.Tyres, + resourceKey: '123', + code: '123', + loadIndexSingleLoad: '102', + tyreSize: 'size', + dateTimeStamp: 'time', + userId: '1234', + loadIndexTwinLoad: '101', + plyRating: '18', + }, + ], + }; - const state: ReferenceDataState = { - ...initialReferenceDataState, - [ReferenceDataResourceType.Tyres]: { - ...initialReferenceDataState[ReferenceDataResourceType.Tyres], - loading: false, - searchReturn: value.payload, - filter: 'cake', - term: 'lies', - }, - }; + const state: ReferenceDataState = { + ...initialReferenceDataState, + [ReferenceDataResourceType.Tyres]: { + ...initialReferenceDataState[ReferenceDataResourceType.Tyres], + loading: false, + searchReturn: value.payload, + filter: 'cake', + term: 'lies', + }, + }; - const expectedState = referenceDataSelectors.selectTyreSearchCriteria.projector(state); - expect(expectedState.filter).toBe('cake'); - expect(expectedState.term).toBe('lies'); - }); - }); + const expectedState = referenceDataSelectors.selectTyreSearchCriteria.projector(state); + expect(expectedState.filter).toBe('cake'); + expect(expectedState.term).toBe('lies'); + }); + }); - it('should return true if any feature is loading state', () => { - const state: ReferenceDataState = { ...initialReferenceDataState }; - state.HGV_MAKE.loading = true; - const selectedState = referenceDataSelectors.referenceDataLoadingState.projector(state); - expect(selectedState).toBe(true); - }); + it('should return true if any feature is loading state', () => { + const state: ReferenceDataState = { ...initialReferenceDataState }; + state.HGV_MAKE.loading = true; + const selectedState = referenceDataSelectors.referenceDataLoadingState.projector(state); + expect(selectedState).toBe(true); + }); - it('should return the reasons for abandoning for the right vehicle type', () => { - const selectorSpy = jest.spyOn(referenceDataSelectors, 'selectAllReferenceDataByResourceType'); - referenceDataSelectors.selectReasonsForAbandoning(VehicleTypes.PSV); - expect(selectorSpy).toHaveBeenLastCalledWith(ReferenceDataResourceType.ReasonsForAbandoningPsv); - referenceDataSelectors.selectReasonsForAbandoning(VehicleTypes.HGV); - expect(selectorSpy).toHaveBeenLastCalledWith(ReferenceDataResourceType.ReasonsForAbandoningHgv); - referenceDataSelectors.selectReasonsForAbandoning(VehicleTypes.TRL); - expect(selectorSpy).toHaveBeenLastCalledWith(ReferenceDataResourceType.ReasonsForAbandoningTrl); - }); + it('should return the reasons for abandoning for the right vehicle type', () => { + const selectorSpy = jest.spyOn(referenceDataSelectors, 'selectAllReferenceDataByResourceType'); + referenceDataSelectors.selectReasonsForAbandoning(VehicleTypes.PSV); + expect(selectorSpy).toHaveBeenLastCalledWith(ReferenceDataResourceType.ReasonsForAbandoningPsv); + referenceDataSelectors.selectReasonsForAbandoning(VehicleTypes.HGV); + expect(selectorSpy).toHaveBeenLastCalledWith(ReferenceDataResourceType.ReasonsForAbandoningHgv); + referenceDataSelectors.selectReasonsForAbandoning(VehicleTypes.TRL); + expect(selectorSpy).toHaveBeenLastCalledWith(ReferenceDataResourceType.ReasonsForAbandoningTrl); + }); - describe('selectRefDataBySearchTerm', () => { - let state: ReferenceDataState; - beforeEach(() => { - state = { - ...initialReferenceDataState, - [ReferenceDataResourceType.Tyres]: { - ...initialReferenceDataState[ReferenceDataResourceType.Tyres], - loading: false, - ids: [1, 11, 111, 101, 2], - entities: { - 1: { resourceKey: 1, brakeCode: 1, resourceType: ReferenceDataResourceType.Tyres } as ReferenceDataModelBase, - 11: { resourceKey: 11, brakeCode: 11, resourceType: ReferenceDataResourceType.Tyres } as ReferenceDataModelBase, - 111: { resourceKey: 111, brakeCode: 111, resourceType: ReferenceDataResourceType.Tyres } as ReferenceDataModelBase, - 101: { resourceKey: 101, brakeCode: 101, resourceType: ReferenceDataResourceType.Tyres } as ReferenceDataModelBase, - 2: { resourceKey: 2, brakeCode: 2, resourceType: ReferenceDataResourceType.Tyres } as ReferenceDataModelBase, - }, - }, - }; - }); - it('should return only items that contain the search term 1', () => { - const expectedState = referenceDataSelectors.selectRefDataBySearchTerm('1', ReferenceDataResourceType.Tyres, 'brakeCode').projector(state); - expect(expectedState).toEqual([ - { resourceKey: 1, brakeCode: 1, resourceType: ReferenceDataResourceType.Tyres }, - { resourceKey: 11, brakeCode: 11, resourceType: ReferenceDataResourceType.Tyres }, - { resourceKey: 111, brakeCode: 111, resourceType: ReferenceDataResourceType.Tyres }, - { resourceKey: 101, brakeCode: 101, resourceType: ReferenceDataResourceType.Tyres }, - ]); - }); - it('should return only items that contain the search term 11', () => { - const expectedState = referenceDataSelectors.selectRefDataBySearchTerm('11', ReferenceDataResourceType.Tyres, 'brakeCode').projector(state); - expect(expectedState).toEqual([ - { resourceKey: 11, brakeCode: 11, resourceType: ReferenceDataResourceType.Tyres }, - { resourceKey: 111, brakeCode: 111, resourceType: ReferenceDataResourceType.Tyres }, - ]); - }); - it('should return only items that contain the search term 2', () => { - const expectedState = referenceDataSelectors.selectRefDataBySearchTerm('2', ReferenceDataResourceType.Tyres, 'brakeCode').projector(state); - expect(expectedState).toEqual([{ resourceKey: 2, brakeCode: 2, resourceType: ReferenceDataResourceType.Tyres }]); - }); - it('should return an empty array if there are no items to return', () => { - const expectedState = referenceDataSelectors.selectRefDataBySearchTerm('3', ReferenceDataResourceType.Tyres, 'brakeCode').projector(state); - expect(expectedState).toEqual([]); - }); - }); + describe('selectRefDataBySearchTerm', () => { + let state: ReferenceDataState; + beforeEach(() => { + state = { + ...initialReferenceDataState, + [ReferenceDataResourceType.Tyres]: { + ...initialReferenceDataState[ReferenceDataResourceType.Tyres], + loading: false, + ids: [1, 11, 111, 101, 2], + entities: { + 1: { + resourceKey: 1, + brakeCode: 1, + resourceType: ReferenceDataResourceType.Tyres, + } as ReferenceDataModelBase, + 11: { + resourceKey: 11, + brakeCode: 11, + resourceType: ReferenceDataResourceType.Tyres, + } as ReferenceDataModelBase, + 111: { + resourceKey: 111, + brakeCode: 111, + resourceType: ReferenceDataResourceType.Tyres, + } as ReferenceDataModelBase, + 101: { + resourceKey: 101, + brakeCode: 101, + resourceType: ReferenceDataResourceType.Tyres, + } as ReferenceDataModelBase, + 2: { + resourceKey: 2, + brakeCode: 2, + resourceType: ReferenceDataResourceType.Tyres, + } as ReferenceDataModelBase, + }, + }, + }; + }); + it('should return only items that contain the search term 1', () => { + const expectedState = referenceDataSelectors + .selectRefDataBySearchTerm('1', ReferenceDataResourceType.Tyres, 'brakeCode') + .projector(state); + expect(expectedState).toEqual([ + { resourceKey: 1, brakeCode: 1, resourceType: ReferenceDataResourceType.Tyres }, + { resourceKey: 11, brakeCode: 11, resourceType: ReferenceDataResourceType.Tyres }, + { resourceKey: 111, brakeCode: 111, resourceType: ReferenceDataResourceType.Tyres }, + { resourceKey: 101, brakeCode: 101, resourceType: ReferenceDataResourceType.Tyres }, + ]); + }); + it('should return only items that contain the search term 11', () => { + const expectedState = referenceDataSelectors + .selectRefDataBySearchTerm('11', ReferenceDataResourceType.Tyres, 'brakeCode') + .projector(state); + expect(expectedState).toEqual([ + { resourceKey: 11, brakeCode: 11, resourceType: ReferenceDataResourceType.Tyres }, + { resourceKey: 111, brakeCode: 111, resourceType: ReferenceDataResourceType.Tyres }, + ]); + }); + it('should return only items that contain the search term 2', () => { + const expectedState = referenceDataSelectors + .selectRefDataBySearchTerm('2', ReferenceDataResourceType.Tyres, 'brakeCode') + .projector(state); + expect(expectedState).toEqual([{ resourceKey: 2, brakeCode: 2, resourceType: ReferenceDataResourceType.Tyres }]); + }); + it('should return an empty array if there are no items to return', () => { + const expectedState = referenceDataSelectors + .selectRefDataBySearchTerm('3', ReferenceDataResourceType.Tyres, 'brakeCode') + .projector(state); + expect(expectedState).toEqual([]); + }); + }); }); diff --git a/src/app/store/reference-data/selectors/reference-data.selectors.ts b/src/app/store/reference-data/selectors/reference-data.selectors.ts index 2432ffb249..63a25e3229 100644 --- a/src/app/store/reference-data/selectors/reference-data.selectors.ts +++ b/src/app/store/reference-data/selectors/reference-data.selectors.ts @@ -1,79 +1,95 @@ -import { - Brake, ReferenceDataResourceType, ReferenceDataResourceTypeAudit, -} from '@models/reference-data.model'; +import { Brake, ReferenceDataResourceType, ReferenceDataResourceTypeAudit } from '@models/reference-data.model'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { createSelector } from '@ngrx/store'; -import { ReferenceDataEntityStateSearch, referenceDataFeatureState, resourceTypeAdapters } from '../reducers/reference-data.reducer'; +import { + ReferenceDataEntityStateSearch, + referenceDataFeatureState, + resourceTypeAdapters, +} from '../reducers/reference-data.reducer'; -const resourceTypeSelector = (resourceType: ReferenceDataResourceType) => createSelector( - referenceDataFeatureState, - (state) => state[`${resourceType}`], -); +const resourceTypeSelector = (resourceType: ReferenceDataResourceType) => + createSelector(referenceDataFeatureState, (state) => state[`${resourceType}`]); export const selectAllReferenceDataByResourceType = (resourceType: ReferenceDataResourceType) => - createSelector(resourceTypeSelector(resourceType), (state) => - isResourceType(resourceType) ? resourceTypeAdapters[`${resourceType}`].getSelectors().selectAll(state) : undefined); + createSelector(resourceTypeSelector(resourceType), (state) => + isResourceType(resourceType) ? resourceTypeAdapters[`${resourceType}`].getSelectors().selectAll(state) : undefined + ); -export const selectReferenceDataByResourceKey = (resourceType: ReferenceDataResourceType, resourceKey: string | number) => - createSelector(referenceDataFeatureState, (state) => (isResourceType(resourceType) - ? state[`${resourceType}`].entities[`${resourceKey}`] - : undefined)); +export const selectReferenceDataByResourceKey = ( + resourceType: ReferenceDataResourceType, + resourceKey: string | number +) => + createSelector(referenceDataFeatureState, (state) => + isResourceType(resourceType) ? state[`${resourceType}`].entities[`${resourceKey}`] : undefined + ); -export const referenceDataLoadingState = createSelector( - referenceDataFeatureState, - (state) => Object.values(state).some((feature) => feature.loading), +export const referenceDataLoadingState = createSelector(referenceDataFeatureState, (state) => + Object.values(state).some((feature) => feature.loading) ); -export const referencePsvMakeLoadingState = createSelector(referenceDataFeatureState, (state) => state.PSV_MAKE.loading); +export const referencePsvMakeLoadingState = createSelector( + referenceDataFeatureState, + (state) => state.PSV_MAKE.loading +); export const selectBrakeByCode = (code: string) => - createSelector(referenceDataFeatureState, (state) => state[ReferenceDataResourceType.Brakes].entities[`${code}`] as Brake); + createSelector( + referenceDataFeatureState, + (state) => state[ReferenceDataResourceType.Brakes].entities[`${code}`] as Brake + ); export const selectReasonsForAbandoning = (vehicleType: VehicleTypes) => { - switch (vehicleType) { - case VehicleTypes.PSV: - return selectAllReferenceDataByResourceType(ReferenceDataResourceType.ReasonsForAbandoningPsv); - case VehicleTypes.HGV: - return selectAllReferenceDataByResourceType(ReferenceDataResourceType.ReasonsForAbandoningHgv); - case VehicleTypes.TRL: - return selectAllReferenceDataByResourceType(ReferenceDataResourceType.ReasonsForAbandoningTrl); - default: - throw new Error('Unknown Vehicle Type'); - } + switch (vehicleType) { + case VehicleTypes.PSV: + return selectAllReferenceDataByResourceType(ReferenceDataResourceType.ReasonsForAbandoningPsv); + case VehicleTypes.HGV: + return selectAllReferenceDataByResourceType(ReferenceDataResourceType.ReasonsForAbandoningHgv); + case VehicleTypes.TRL: + return selectAllReferenceDataByResourceType(ReferenceDataResourceType.ReasonsForAbandoningTrl); + default: + throw new Error('Unknown Vehicle Type'); + } }; export const selectSearchReturn = (type: ReferenceDataResourceTypeAudit) => - createSelector(referenceDataFeatureState, (state) => { - const data = (state[type as ReferenceDataResourceType] as ReferenceDataEntityStateSearch)?.searchReturn; - return data?.sort((a, b) => b.resourceKey.toString().localeCompare(a.resourceKey.toString())); - }); + createSelector(referenceDataFeatureState, (state) => { + const data = (state[type as ReferenceDataResourceType] as ReferenceDataEntityStateSearch)?.searchReturn; + return data?.sort((a, b) => b.resourceKey.toString().localeCompare(a.resourceKey.toString())); + }); export const selectTyreSearchCriteria = createSelector( - referenceDataFeatureState, - (state) => state[ReferenceDataResourceType.Tyres] as ReferenceDataEntityStateSearch, + referenceDataFeatureState, + (state) => state[ReferenceDataResourceType.Tyres] as ReferenceDataEntityStateSearch ); -export const selectRefDataBySearchTerm = (searchTerm: string, referenceDataType: ReferenceDataResourceType, filter: string) => - createSelector(referenceDataFeatureState, (state) => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const searchItem: Array = []; +export const selectRefDataBySearchTerm = ( + searchTerm: string, + referenceDataType: ReferenceDataResourceType, + filter: string +) => + createSelector(referenceDataFeatureState, (state) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const searchItem: Array = []; - state[`${referenceDataType}`].ids.forEach((key) => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const obj = state[`${referenceDataType}`].entities[`${key}`] as any; - if (obj[`${filter}`].toString().toUpperCase().includes(searchTerm.toString().toUpperCase())) { - searchItem.push(obj); - } - }); - if (searchTerm.length > 0) { - return searchItem; - } - return undefined; - }); + state[`${referenceDataType}`].ids.forEach((key) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const obj = state[`${referenceDataType}`].entities[`${key}`] as any; + if (obj[`${filter}`].toString().toUpperCase().includes(searchTerm.toString().toUpperCase())) { + searchItem.push(obj); + } + }); + if (searchTerm.length > 0) { + return searchItem; + } + return undefined; + }); export const selectUserByResourceKey = (resourceKey: string) => - createSelector(referenceDataFeatureState, (state) => state[ReferenceDataResourceType.User].entities[`${resourceKey}`]); + createSelector( + referenceDataFeatureState, + (state) => state[ReferenceDataResourceType.User].entities[`${resourceKey}`] + ); export const isResourceType = (resourceType: string): resourceType is ReferenceDataResourceType => { - return Object.values(ReferenceDataResourceType).includes(resourceType as ReferenceDataResourceType); + return Object.values(ReferenceDataResourceType).includes(resourceType as ReferenceDataResourceType); }; diff --git a/src/app/store/required-standards/actions/required-standards.actions.spec.ts b/src/app/store/required-standards/actions/required-standards.actions.spec.ts index 09be66345f..d8a40e7d8a 100644 --- a/src/app/store/required-standards/actions/required-standards.actions.spec.ts +++ b/src/app/store/required-standards/actions/required-standards.actions.spec.ts @@ -1,9 +1,13 @@ -import { getRequiredStandards, getRequiredStandardsFailure, getRequiredStandardsSuccess } from './required-standards.actions'; +import { + getRequiredStandards, + getRequiredStandardsFailure, + getRequiredStandardsSuccess, +} from './required-standards.actions'; describe('Required Standards Actions', () => { - it('should return correct types', () => { - expect(getRequiredStandards.type).toBe('[Required Standards] getRequiredStandards'); - expect(getRequiredStandardsSuccess.type).toBe('[Required Standards] getRequiredStandards Success'); - expect(getRequiredStandardsFailure.type).toBe('[Required Standards] getRequiredStandards Failure'); - }); + it('should return correct types', () => { + expect(getRequiredStandards.type).toBe('[Required Standards] getRequiredStandards'); + expect(getRequiredStandardsSuccess.type).toBe('[Required Standards] getRequiredStandards Success'); + expect(getRequiredStandardsFailure.type).toBe('[Required Standards] getRequiredStandards Failure'); + }); }); diff --git a/src/app/store/required-standards/actions/required-standards.actions.ts b/src/app/store/required-standards/actions/required-standards.actions.ts index 23231f2133..298f122c15 100644 --- a/src/app/store/required-standards/actions/required-standards.actions.ts +++ b/src/app/store/required-standards/actions/required-standards.actions.ts @@ -4,9 +4,12 @@ import { createAction, props } from '@ngrx/store'; const prefix = '[Required Standards]'; -export const getRequiredStandards = createAction(`${prefix} getRequiredStandards`, props<{ euVehicleCategory: string }>()); +export const getRequiredStandards = createAction( + `${prefix} getRequiredStandards`, + props<{ euVehicleCategory: string }>() +); export const getRequiredStandardsSuccess = createAction( - `${prefix} getRequiredStandards Success`, - props<{ requiredStandards: DefectGETRequiredStandards }>(), + `${prefix} getRequiredStandards Success`, + props<{ requiredStandards: DefectGETRequiredStandards }>() ); export const getRequiredStandardsFailure = createAction(`${prefix} getRequiredStandards Failure`, props()); diff --git a/src/app/store/required-standards/effects/required-standards.effects.spec.ts b/src/app/store/required-standards/effects/required-standards.effects.spec.ts index 7220b53a61..1bb68f8bc5 100644 --- a/src/app/store/required-standards/effects/required-standards.effects.spec.ts +++ b/src/app/store/required-standards/effects/required-standards.effects.spec.ts @@ -8,77 +8,82 @@ import { RequiredStandardsService } from '@services/required-standards/required- import { initialAppState } from '@store/index'; import { Observable } from 'rxjs'; import { TestScheduler } from 'rxjs/testing'; -import { getRequiredStandards, getRequiredStandardsFailure, getRequiredStandardsSuccess } from '../actions/required-standards.actions'; +import { + getRequiredStandards, + getRequiredStandardsFailure, + getRequiredStandardsSuccess, +} from '../actions/required-standards.actions'; import { RequiredStandardsEffects } from './required-standards.effects'; describe('RequiredStandardEffects', () => { - let effects: RequiredStandardsEffects; - let actions$ = new Observable(); - let testScheduler: TestScheduler; - let service: RequiredStandardsService; + let effects: RequiredStandardsEffects; + let actions$ = new Observable(); + let testScheduler: TestScheduler; + let service: RequiredStandardsService; - const testCases = [ - { - requiredStandards: [{ - rsNumber: 1, - }] as unknown as DefectGETRequiredStandards, - }, - ]; + const testCases = [ + { + requiredStandards: [ + { + rsNumber: 1, + }, + ] as unknown as DefectGETRequiredStandards, + }, + ]; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - RequiredStandardsEffects, - provideMockActions(() => actions$), - RequiredStandardsService, - provideMockStore({ - initialState: initialAppState, - }), - ], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + RequiredStandardsEffects, + provideMockActions(() => actions$), + RequiredStandardsService, + provideMockStore({ + initialState: initialAppState, + }), + ], + }); - effects = TestBed.inject(RequiredStandardsEffects); - service = TestBed.inject(RequiredStandardsService); - }); + effects = TestBed.inject(RequiredStandardsEffects); + service = TestBed.inject(RequiredStandardsService); + }); - beforeEach(() => { - testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - }); + beforeEach(() => { + testScheduler = new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); + }); + }); - describe('getRequiredStandards$', () => { - it.each(testCases)('should return requiredStandardsSuccess action on successful API call', (value) => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const { requiredStandards } = value; + describe('getRequiredStandards$', () => { + it.each(testCases)('should return requiredStandardsSuccess action on successful API call', (value) => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const { requiredStandards } = value; - // mock action to trigger effect - actions$ = hot('-a--', { a: getRequiredStandards({ euVehicleCategory: 'm1' }) }); + // mock action to trigger effect + actions$ = hot('-a--', { a: getRequiredStandards({ euVehicleCategory: 'm1' }) }); - // mock service call - jest.spyOn(service, 'getRequiredStandards').mockReturnValue(cold('--a|', { a: requiredStandards })); + // mock service call + jest.spyOn(service, 'getRequiredStandards').mockReturnValue(cold('--a|', { a: requiredStandards })); - // expect effect to return success action - expectObservable(effects.getRequiredStandards$).toBe('---b', { - b: getRequiredStandardsSuccess({ requiredStandards }), - }); - }); - }); + // expect effect to return success action + expectObservable(effects.getRequiredStandards$).toBe('---b', { + b: getRequiredStandardsSuccess({ requiredStandards }), + }); + }); + }); - it.each(testCases)('should return getRequiredStandardsFailed action on API error', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - actions$ = hot('-a--', { a: getRequiredStandards({ euVehicleCategory: 'm1' }) }); + it.each(testCases)('should return getRequiredStandardsFailed action on API error', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + actions$ = hot('-a--', { a: getRequiredStandards({ euVehicleCategory: 'm1' }) }); - const expectedError = new Error('No required standards found'); + const expectedError = new Error('No required standards found'); - jest.spyOn(service, 'getRequiredStandards').mockReturnValue(cold('--#|', {}, expectedError)); + jest.spyOn(service, 'getRequiredStandards').mockReturnValue(cold('--#|', {}, expectedError)); - expectObservable(effects.getRequiredStandards$).toBe( - '---b', - { b: getRequiredStandardsFailure({ error: 'No required standards found' }) }, - ); - }); - }); - }); + expectObservable(effects.getRequiredStandards$).toBe('---b', { + b: getRequiredStandardsFailure({ error: 'No required standards found' }), + }); + }); + }); + }); }); diff --git a/src/app/store/required-standards/effects/required-standards.effects.ts b/src/app/store/required-standards/effects/required-standards.effects.ts index fbc926c935..059dc52168 100644 --- a/src/app/store/required-standards/effects/required-standards.effects.ts +++ b/src/app/store/required-standards/effects/required-standards.effects.ts @@ -1,21 +1,29 @@ import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { RequiredStandardsService } from '@services/required-standards/required-standards.service'; +import { catchError, map, mergeMap, of } from 'rxjs'; import { - catchError, map, mergeMap, of, -} from 'rxjs'; -import { getRequiredStandards, getRequiredStandardsFailure, getRequiredStandardsSuccess } from '../actions/required-standards.actions'; + getRequiredStandards, + getRequiredStandardsFailure, + getRequiredStandardsSuccess, +} from '../actions/required-standards.actions'; @Injectable() export class RequiredStandardsEffects { - getRequiredStandards$ = createEffect(() => - this.actions$.pipe( - ofType(getRequiredStandards), - mergeMap(({ euVehicleCategory }) => this.requiredStandardsService.getRequiredStandards(euVehicleCategory).pipe( - map((requiredStandards) => getRequiredStandardsSuccess({ requiredStandards })), - catchError((e) => of(getRequiredStandardsFailure({ error: e.message }))), - )), - )); + getRequiredStandards$ = createEffect(() => + this.actions$.pipe( + ofType(getRequiredStandards), + mergeMap(({ euVehicleCategory }) => + this.requiredStandardsService.getRequiredStandards(euVehicleCategory).pipe( + map((requiredStandards) => getRequiredStandardsSuccess({ requiredStandards })), + catchError((e) => of(getRequiredStandardsFailure({ error: e.message }))) + ) + ) + ) + ); - constructor(private actions$: Actions, private requiredStandardsService: RequiredStandardsService) {} + constructor( + private actions$: Actions, + private requiredStandardsService: RequiredStandardsService + ) {} } diff --git a/src/app/store/required-standards/reducers/required-standards.reducer.spec.ts b/src/app/store/required-standards/reducers/required-standards.reducer.spec.ts index 55637609e5..32a9d5152d 100644 --- a/src/app/store/required-standards/reducers/required-standards.reducer.spec.ts +++ b/src/app/store/required-standards/reducers/required-standards.reducer.spec.ts @@ -1,58 +1,68 @@ import { DefectGETRequiredStandards } from '@dvsa/cvs-type-definitions/types/required-standards/defects/get'; -import { getRequiredStandards, getRequiredStandardsFailure, getRequiredStandardsSuccess } from '../actions/required-standards.actions'; -import { RequiredStandardState, initialRequiredStandardsState, requiredStandardsReducer } from './required-standards.reducer'; +import { + getRequiredStandards, + getRequiredStandardsFailure, + getRequiredStandardsSuccess, +} from '../actions/required-standards.actions'; +import { + RequiredStandardState, + initialRequiredStandardsState, + requiredStandardsReducer, +} from './required-standards.reducer'; describe('Required Standards Reducer', () => { - const expectedRequiredStandards = { - basic: [], - normal: [], - euVehicleCategories: ['m1'], - }; - - describe('unknown action', () => { - it('should return the default state', () => { - const action = { - type: 'Unknown', - }; - const state = requiredStandardsReducer(initialRequiredStandardsState, action); - - expect(state).toBe(initialRequiredStandardsState); - }); - }); - - describe('requiredStandards actions', () => { - it('should set loading to true', () => { - const newState: RequiredStandardState = { ...initialRequiredStandardsState, loading: true }; - const action = getRequiredStandards({ euVehicleCategory: 'm1' }); - const state = requiredStandardsReducer(initialRequiredStandardsState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - - describe('getRequiredStandardsSuccess', () => { - it('should set all test result records', () => { - const newState: RequiredStandardState = { - ...initialRequiredStandardsState, - requiredStandards: expectedRequiredStandards as unknown as DefectGETRequiredStandards, - }; - const action = getRequiredStandardsSuccess({ requiredStandards: expectedRequiredStandards as unknown as DefectGETRequiredStandards }); - const state = requiredStandardsReducer(initialRequiredStandardsState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - - describe('getRequiredStandardsFailure', () => { - it('should set error state', () => { - const newState = { ...initialRequiredStandardsState, loading: false }; - const action = getRequiredStandardsFailure({ error: 'unit testing error message' }); - const state = requiredStandardsReducer({ ...initialRequiredStandardsState, loading: true }, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - }); - }); + const expectedRequiredStandards = { + basic: [], + normal: [], + euVehicleCategories: ['m1'], + }; + + describe('unknown action', () => { + it('should return the default state', () => { + const action = { + type: 'Unknown', + }; + const state = requiredStandardsReducer(initialRequiredStandardsState, action); + + expect(state).toBe(initialRequiredStandardsState); + }); + }); + + describe('requiredStandards actions', () => { + it('should set loading to true', () => { + const newState: RequiredStandardState = { ...initialRequiredStandardsState, loading: true }; + const action = getRequiredStandards({ euVehicleCategory: 'm1' }); + const state = requiredStandardsReducer(initialRequiredStandardsState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + + describe('getRequiredStandardsSuccess', () => { + it('should set all test result records', () => { + const newState: RequiredStandardState = { + ...initialRequiredStandardsState, + requiredStandards: expectedRequiredStandards as unknown as DefectGETRequiredStandards, + }; + const action = getRequiredStandardsSuccess({ + requiredStandards: expectedRequiredStandards as unknown as DefectGETRequiredStandards, + }); + const state = requiredStandardsReducer(initialRequiredStandardsState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + + describe('getRequiredStandardsFailure', () => { + it('should set error state', () => { + const newState = { ...initialRequiredStandardsState, loading: false }; + const action = getRequiredStandardsFailure({ error: 'unit testing error message' }); + const state = requiredStandardsReducer({ ...initialRequiredStandardsState, loading: true }, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + }); + }); }); diff --git a/src/app/store/required-standards/reducers/required-standards.reducer.ts b/src/app/store/required-standards/reducers/required-standards.reducer.ts index cf3a39b6ea..bf2a0bab5c 100644 --- a/src/app/store/required-standards/reducers/required-standards.reducer.ts +++ b/src/app/store/required-standards/reducers/required-standards.reducer.ts @@ -1,47 +1,55 @@ import { DefectGETRequiredStandards } from '@dvsa/cvs-type-definitions/types/required-standards/defects/get'; import { createFeatureSelector, createReducer, on } from '@ngrx/store'; -import { getRequiredStandards, getRequiredStandardsFailure, getRequiredStandardsSuccess } from '../actions/required-standards.actions'; +import { + getRequiredStandards, + getRequiredStandardsFailure, + getRequiredStandardsSuccess, +} from '../actions/required-standards.actions'; export interface RequiredStandardState { - loading: boolean; - error: string; - requiredStandards: DefectGETRequiredStandards + loading: boolean; + error: string; + requiredStandards: DefectGETRequiredStandards; } export const STORE_FEATURE_REQUIRED_STANDARDS_KEY = 'RequiredStandards'; -export const requiredStandardsFeatureState = createFeatureSelector(STORE_FEATURE_REQUIRED_STANDARDS_KEY); +export const requiredStandardsFeatureState = createFeatureSelector( + STORE_FEATURE_REQUIRED_STANDARDS_KEY +); export const initialRequiredStandardsState: RequiredStandardState = { - loading: false, - error: '', - requiredStandards: { - basic: [], - normal: [], - euVehicleCategories: [], - }, - + loading: false, + error: '', + requiredStandards: { + basic: [], + normal: [], + euVehicleCategories: [], + }, }; export const requiredStandardsReducer = createReducer( - initialRequiredStandardsState, - - on(getRequiredStandards, (state) => ({ ...state, loading: true })), - on(getRequiredStandardsSuccess, (state, action) => ({ - ...state, - requiredStandards: orderRequiredStandards(action.requiredStandards), - loading: false, - })), - on(getRequiredStandardsFailure, (state) => ({ ...state, loading: false })), - + initialRequiredStandardsState, + + on(getRequiredStandards, (state) => ({ ...state, loading: true })), + on(getRequiredStandardsSuccess, (state, action) => ({ + ...state, + requiredStandards: orderRequiredStandards(action.requiredStandards), + loading: false, + })), + on(getRequiredStandardsFailure, (state) => ({ ...state, loading: false })) ); function orderRequiredStandards(requiredStandards: DefectGETRequiredStandards) { - if (requiredStandards.basic.length) { - requiredStandards.basic.sort((current, next) => current.sectionNumber.localeCompare(next.sectionNumber, 'en', { numeric: true })); - } - if (requiredStandards.normal.length) { - requiredStandards.normal.sort((current, next) => current.sectionNumber.localeCompare(next.sectionNumber, 'en', { numeric: true })); - } - return requiredStandards; + if (requiredStandards.basic.length) { + requiredStandards.basic.sort((current, next) => + current.sectionNumber.localeCompare(next.sectionNumber, 'en', { numeric: true }) + ); + } + if (requiredStandards.normal.length) { + requiredStandards.normal.sort((current, next) => + current.sectionNumber.localeCompare(next.sectionNumber, 'en', { numeric: true }) + ); + } + return requiredStandards; } diff --git a/src/app/store/required-standards/required-standards.module.ts b/src/app/store/required-standards/required-standards.module.ts index 8d4678cdcf..bfdbbffae8 100644 --- a/src/app/store/required-standards/required-standards.module.ts +++ b/src/app/store/required-standards/required-standards.module.ts @@ -6,8 +6,11 @@ import { RequiredStandardsEffects } from './effects/required-standards.effects'; import { STORE_FEATURE_REQUIRED_STANDARDS_KEY, requiredStandardsReducer } from './reducers/required-standards.reducer'; @NgModule({ - declarations: [], - imports: [CommonModule, StoreModule.forFeature(STORE_FEATURE_REQUIRED_STANDARDS_KEY, requiredStandardsReducer), - EffectsModule.forFeature([RequiredStandardsEffects])], + declarations: [], + imports: [ + CommonModule, + StoreModule.forFeature(STORE_FEATURE_REQUIRED_STANDARDS_KEY, requiredStandardsReducer), + EffectsModule.forFeature([RequiredStandardsEffects]), + ], }) export class RequiredStandardsStateModule {} diff --git a/src/app/store/required-standards/selectors/required-standards.selector.spec.ts b/src/app/store/required-standards/selectors/required-standards.selector.spec.ts index 022dc05299..5866352b7b 100644 --- a/src/app/store/required-standards/selectors/required-standards.selector.spec.ts +++ b/src/app/store/required-standards/selectors/required-standards.selector.spec.ts @@ -2,74 +2,85 @@ import { EUVehicleCategory } from '@dvsa/cvs-type-definitions/types/required-sta import { DefectGETRequiredStandards } from '@dvsa/cvs-type-definitions/types/required-standards/defects/get'; import { INSPECTION_TYPE } from '@models/test-results/test-result-required-standard.model'; import { RequiredStandardState, initialRequiredStandardsState } from '../reducers/required-standards.reducer'; -import { getRequiredStandardFromTypeAndRef, getRequiredStandardsState, requiredStandardsLoadingState } from './required-standards.selector'; +import { + getRequiredStandardFromTypeAndRef, + getRequiredStandardsState, + requiredStandardsLoadingState, +} from './required-standards.selector'; describe('RequiredStandardsLoadingState', () => { - it('should return loading state', () => { - const state: RequiredStandardState = { ...initialRequiredStandardsState, loading: true }; - const selectedState = requiredStandardsLoadingState.projector(state); - expect(selectedState).toBeTruthy(); - }); + it('should return loading state', () => { + const state: RequiredStandardState = { ...initialRequiredStandardsState, loading: true }; + const selectedState = requiredStandardsLoadingState.projector(state); + expect(selectedState).toBeTruthy(); + }); - describe('getRequiredStandardsState', () => { - it('should return me the required standards state', () => { - const state: RequiredStandardState = { ...initialRequiredStandardsState, loading: false }; - const selectedState = getRequiredStandardsState.projector(state); - expect(selectedState).toBeTruthy(); - }); - }); - - describe('getRequiredStandardFromTypeAndRef', () => { - it('should return me the required standards state when given a inspection type and ref', () => { - const requiredStandard = { - rsNumber: 1, - requiredStandard: 'rs', - refCalculation: '01.1', - additionalInfo: false, - inspectionTypes: [INSPECTION_TYPE.NORMAL], - }; - const requiredStandards: DefectGETRequiredStandards = { - normal: [{ - sectionNumber: '01', - sectionDescription: 'desc', - requiredStandards: [{ - rsNumber: 1, - requiredStandard: 'rs', - refCalculation: '01.1', - additionalInfo: false, - inspectionTypes: [INSPECTION_TYPE.NORMAL], - }], - }], - basic: [], - euVehicleCategories: [EUVehicleCategory.M1], - }; - initialRequiredStandardsState.requiredStandards = requiredStandards; - const state: RequiredStandardState = { ...initialRequiredStandardsState, loading: false }; - const selectedState = getRequiredStandardFromTypeAndRef(INSPECTION_TYPE.NORMAL, '01.1').projector(state); - expect(selectedState).toBeTruthy(); - expect(selectedState).toStrictEqual({ ...requiredStandard, sectionNumber: '01', sectionDescription: 'desc' }); - }); - it('should return undefined if no section or RS is found', () => { - const requiredStandards: DefectGETRequiredStandards = { - normal: [{ - sectionNumber: '01', - sectionDescription: 'desc', - requiredStandards: [{ - rsNumber: 1, - requiredStandard: 'rs', - refCalculation: '01.1', - additionalInfo: false, - inspectionTypes: [INSPECTION_TYPE.NORMAL], - }], - }], - basic: [], - euVehicleCategories: [EUVehicleCategory.M1], - }; - initialRequiredStandardsState.requiredStandards = requiredStandards; - const state: RequiredStandardState = { ...initialRequiredStandardsState, loading: false }; - const selectedState = getRequiredStandardFromTypeAndRef(INSPECTION_TYPE.NORMAL, 'data').projector(state); - expect(selectedState).toBeUndefined(); - }); - }); + describe('getRequiredStandardsState', () => { + it('should return me the required standards state', () => { + const state: RequiredStandardState = { ...initialRequiredStandardsState, loading: false }; + const selectedState = getRequiredStandardsState.projector(state); + expect(selectedState).toBeTruthy(); + }); + }); + describe('getRequiredStandardFromTypeAndRef', () => { + it('should return me the required standards state when given a inspection type and ref', () => { + const requiredStandard = { + rsNumber: 1, + requiredStandard: 'rs', + refCalculation: '01.1', + additionalInfo: false, + inspectionTypes: [INSPECTION_TYPE.NORMAL], + }; + const requiredStandards: DefectGETRequiredStandards = { + normal: [ + { + sectionNumber: '01', + sectionDescription: 'desc', + requiredStandards: [ + { + rsNumber: 1, + requiredStandard: 'rs', + refCalculation: '01.1', + additionalInfo: false, + inspectionTypes: [INSPECTION_TYPE.NORMAL], + }, + ], + }, + ], + basic: [], + euVehicleCategories: [EUVehicleCategory.M1], + }; + initialRequiredStandardsState.requiredStandards = requiredStandards; + const state: RequiredStandardState = { ...initialRequiredStandardsState, loading: false }; + const selectedState = getRequiredStandardFromTypeAndRef(INSPECTION_TYPE.NORMAL, '01.1').projector(state); + expect(selectedState).toBeTruthy(); + expect(selectedState).toStrictEqual({ ...requiredStandard, sectionNumber: '01', sectionDescription: 'desc' }); + }); + it('should return undefined if no section or RS is found', () => { + const requiredStandards: DefectGETRequiredStandards = { + normal: [ + { + sectionNumber: '01', + sectionDescription: 'desc', + requiredStandards: [ + { + rsNumber: 1, + requiredStandard: 'rs', + refCalculation: '01.1', + additionalInfo: false, + inspectionTypes: [INSPECTION_TYPE.NORMAL], + }, + ], + }, + ], + basic: [], + euVehicleCategories: [EUVehicleCategory.M1], + }; + initialRequiredStandardsState.requiredStandards = requiredStandards; + const state: RequiredStandardState = { ...initialRequiredStandardsState, loading: false }; + const selectedState = getRequiredStandardFromTypeAndRef(INSPECTION_TYPE.NORMAL, 'data').projector(state); + expect(selectedState).toBeUndefined(); + }); + }); }); diff --git a/src/app/store/required-standards/selectors/required-standards.selector.ts b/src/app/store/required-standards/selectors/required-standards.selector.ts index 66c986118d..619ea57e0c 100644 --- a/src/app/store/required-standards/selectors/required-standards.selector.ts +++ b/src/app/store/required-standards/selectors/required-standards.selector.ts @@ -2,19 +2,22 @@ import { INSPECTION_TYPE } from '@models/test-results/test-result-required-stand import { createSelector } from '@ngrx/store'; import { requiredStandardsFeatureState } from '../reducers/required-standards.reducer'; -export const getRequiredStandardsState = createSelector(requiredStandardsFeatureState, (state) => state.requiredStandards); +export const getRequiredStandardsState = createSelector( + requiredStandardsFeatureState, + (state) => state.requiredStandards +); export const getRequiredStandardFromTypeAndRef = (inspectionType: INSPECTION_TYPE, rsRefCalculation: string) => - createSelector(requiredStandardsFeatureState, (state) => { - const deRefRsCalculation = rsRefCalculation.split('.'); - const sectionNumber = deRefRsCalculation[0]; - // eslint-disable-next-line security/detect-object-injection - const section = state.requiredStandards[inspectionType] - .find((sec) => sec.sectionNumber === sectionNumber); - const requiredStandard = section?.requiredStandards.find((rs) => rs.refCalculation === rsRefCalculation); + createSelector(requiredStandardsFeatureState, (state) => { + const deRefRsCalculation = rsRefCalculation.split('.'); + const sectionNumber = deRefRsCalculation[0]; + // eslint-disable-next-line security/detect-object-injection + const section = state.requiredStandards[inspectionType].find((sec) => sec.sectionNumber === sectionNumber); + const requiredStandard = section?.requiredStandards.find((rs) => rs.refCalculation === rsRefCalculation); - if (requiredStandard && section) return { ...requiredStandard, sectionNumber, sectionDescription: section.sectionDescription }; - return undefined; - }); + if (requiredStandard && section) + return { ...requiredStandard, sectionNumber, sectionDescription: section.sectionDescription }; + return undefined; + }); export const requiredStandardsLoadingState = createSelector(requiredStandardsFeatureState, (state) => state.loading); diff --git a/src/app/store/retry-interceptor/actions/retry-interceptor.actions.ts b/src/app/store/retry-interceptor/actions/retry-interceptor.actions.ts index 60cbd8aaf9..d3bf7004e2 100644 --- a/src/app/store/retry-interceptor/actions/retry-interceptor.actions.ts +++ b/src/app/store/retry-interceptor/actions/retry-interceptor.actions.ts @@ -1,3 +1,6 @@ import { createAction, props } from '@ngrx/store'; -export const retryInterceptorFailure = createAction('[retry-interceptor] retryInterceptorFailure', props<{ error: string }>()); +export const retryInterceptorFailure = createAction( + '[retry-interceptor] retryInterceptorFailure', + props<{ error: string }>() +); diff --git a/src/app/store/retry-interceptor/retry-interceptor.module.ts b/src/app/store/retry-interceptor/retry-interceptor.module.ts index 50b5181d08..ad904696ec 100644 --- a/src/app/store/retry-interceptor/retry-interceptor.module.ts +++ b/src/app/store/retry-interceptor/retry-interceptor.module.ts @@ -2,7 +2,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; @NgModule({ - declarations: [], - imports: [CommonModule], + declarations: [], + imports: [CommonModule], }) export class RetryInterceptorStateModule {} diff --git a/src/app/store/router/router-state.module.ts b/src/app/store/router/router-state.module.ts index 93801df7bc..8c2399bf2b 100644 --- a/src/app/store/router/router-state.module.ts +++ b/src/app/store/router/router-state.module.ts @@ -1,11 +1,15 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { routerReducer, StoreRouterConnectingModule } from '@ngrx/router-store'; +import { StoreRouterConnectingModule, routerReducer } from '@ngrx/router-store'; import { StoreModule } from '@ngrx/store'; import { STORE_FEATURE_ROUTER_STORE_KEY } from './selectors/router.selectors'; @NgModule({ - declarations: [], - imports: [CommonModule, StoreModule.forFeature(STORE_FEATURE_ROUTER_STORE_KEY, routerReducer), StoreRouterConnectingModule.forRoot()], + declarations: [], + imports: [ + CommonModule, + StoreModule.forFeature(STORE_FEATURE_ROUTER_STORE_KEY, routerReducer), + StoreRouterConnectingModule.forRoot(), + ], }) export class RouterStateModule {} diff --git a/src/app/store/router/selectors/router.selectors.spec.ts b/src/app/store/router/selectors/router.selectors.spec.ts index 2f28e88505..d933820eb8 100644 --- a/src/app/store/router/selectors/router.selectors.spec.ts +++ b/src/app/store/router/selectors/router.selectors.spec.ts @@ -2,11 +2,11 @@ import { RouterReducerState, SerializedRouterStateSnapshot } from '@ngrx/router- import { selectRouteNestedParams } from './router.selectors'; describe('selectRouteNestedParams', () => { - it('should return all nested params as a flat object', () => { - const router = { - state: { root: { firstChild: { params: { foo: 'bar' }, firstChild: { params: { bar: 'baz' } } } } }, - } as unknown as RouterReducerState; - const params = selectRouteNestedParams.projector(router); - expect(params).toEqual({ foo: 'bar', bar: 'baz' }); - }); + it('should return all nested params as a flat object', () => { + const router = { + state: { root: { firstChild: { params: { foo: 'bar' }, firstChild: { params: { bar: 'baz' } } } } }, + } as unknown as RouterReducerState; + const params = selectRouteNestedParams.projector(router); + expect(params).toEqual({ foo: 'bar', bar: 'baz' }); + }); }); diff --git a/src/app/store/router/selectors/router.selectors.ts b/src/app/store/router/selectors/router.selectors.ts index ca3ab385ac..19f2f4d833 100644 --- a/src/app/store/router/selectors/router.selectors.ts +++ b/src/app/store/router/selectors/router.selectors.ts @@ -1,37 +1,38 @@ import { Params } from '@angular/router'; -import { getRouterSelectors, RouterReducerState } from '@ngrx/router-store'; +import { RouterReducerState, getRouterSelectors } from '@ngrx/router-store'; import { createFeatureSelector, createSelector } from '@ngrx/store'; export const STORE_FEATURE_ROUTER_STORE_KEY = 'router'; export const selectRouter = createFeatureSelector(STORE_FEATURE_ROUTER_STORE_KEY); export const { - selectCurrentRoute, // select the current route - selectFragment, // select the current route fragment - selectQueryParams, // select the current route query params - selectQueryParam, // factory function to select a query param - selectRouteParams, // select the current route params - selectRouteParam, // factory function to select a route param - selectRouteData, // select the current route data - selectUrl, // select the current url + selectCurrentRoute, // select the current route + selectFragment, // select the current route fragment + selectQueryParams, // select the current route query params + selectQueryParam, // factory function to select a query param + selectRouteParams, // select the current route params + selectRouteParam, // factory function to select a route param + selectRouteData, // select the current route data + selectUrl, // select the current url } = getRouterSelectors(); export const routerState = createSelector(selectRouter, (state) => state); export const currentRouteState = createSelector(selectCurrentRoute, (state) => state); -export const selectRouteDataProperty = (property: string) => createSelector(selectRouteData, (data) => data?.[`${property}`]); +export const selectRouteDataProperty = (property: string) => + createSelector(selectRouteData, (data) => data?.[`${property}`]); export const selectRouteNestedParams = createSelector(selectRouter, (router) => { - let currentRoute = router?.state?.root; - let params: Params = {}; - while (currentRoute?.firstChild) { - currentRoute = currentRoute.firstChild; - params = { - ...params, - ...currentRoute.params, - }; - } - return params; + let currentRoute = router?.state?.root; + let params: Params = {}; + while (currentRoute?.firstChild) { + currentRoute = currentRoute.firstChild; + params = { + ...params, + ...currentRoute.params, + }; + } + return params; }); export const routeEditable = createSelector(selectQueryParam('edit'), (edit) => edit === 'true'); diff --git a/src/app/store/spinner/actions/spinner.actions.spec.ts b/src/app/store/spinner/actions/spinner.actions.spec.ts index f73ff3160c..82a224a0b7 100644 --- a/src/app/store/spinner/actions/spinner.actions.spec.ts +++ b/src/app/store/spinner/actions/spinner.actions.spec.ts @@ -2,28 +2,28 @@ import { initialSpinnerState, spinnerReducer } from '../reducers/spinner.reducer import { setSpinnerState } from './spinner.actions'; describe('unknown action', () => { - it('should return the default state', () => { - const action = { - type: 'Unknown', - }; + it('should return the default state', () => { + const action = { + type: 'Unknown', + }; - const state = spinnerReducer(initialSpinnerState, action); - expect(state).toBe(initialSpinnerState); - }); + const state = spinnerReducer(initialSpinnerState, action); + expect(state).toBe(initialSpinnerState); + }); - it('should not change the state', () => { - const action = { - type: 'Unknown', - }; + it('should not change the state', () => { + const action = { + type: 'Unknown', + }; - const state = spinnerReducer({ showSpinner: true }, action); - expect(state).toEqual({ showSpinner: true }); - expect(state).not.toBe({ showSpinner: true }); - }); + const state = spinnerReducer({ showSpinner: true }, action); + expect(state).toEqual({ showSpinner: true }); + expect(state).not.toBe({ showSpinner: true }); + }); }); describe('setSpinnerState', () => { - it('should have the correct type', () => { - expect(setSpinnerState.type).toBe('[UI/spinner] set spinner state'); - }); + it('should have the correct type', () => { + expect(setSpinnerState.type).toBe('[UI/spinner] set spinner state'); + }); }); diff --git a/src/app/store/spinner/reducers/spinner.reducer.spec.ts b/src/app/store/spinner/reducers/spinner.reducer.spec.ts index e4b7b8ecaa..2108d94d80 100644 --- a/src/app/store/spinner/reducers/spinner.reducer.spec.ts +++ b/src/app/store/spinner/reducers/spinner.reducer.spec.ts @@ -2,13 +2,13 @@ import { initialSpinnerState, spinnerReducer } from '@store/spinner/reducers/spi import { setSpinnerState } from '../actions/spinner.actions'; describe('Spinner Reducer', () => { - it('should set correct state', () => { - expect(setSpinnerState.type).toBe('[UI/spinner] set spinner state'); - const state = { ...initialSpinnerState }; - expect(state.showSpinner).toBeFalsy(); - const showingState = spinnerReducer(state, setSpinnerState({ showSpinner: true })); - expect(showingState.showSpinner).toBeTruthy(); - const notShowingState = spinnerReducer(state, setSpinnerState({ showSpinner: false })); - expect(notShowingState.showSpinner).toBeFalsy(); - }); + it('should set correct state', () => { + expect(setSpinnerState.type).toBe('[UI/spinner] set spinner state'); + const state = { ...initialSpinnerState }; + expect(state.showSpinner).toBeFalsy(); + const showingState = spinnerReducer(state, setSpinnerState({ showSpinner: true })); + expect(showingState.showSpinner).toBeTruthy(); + const notShowingState = spinnerReducer(state, setSpinnerState({ showSpinner: false })); + expect(notShowingState.showSpinner).toBeFalsy(); + }); }); diff --git a/src/app/store/spinner/reducers/spinner.reducer.ts b/src/app/store/spinner/reducers/spinner.reducer.ts index cb2ae9f57b..fecb967bd5 100644 --- a/src/app/store/spinner/reducers/spinner.reducer.ts +++ b/src/app/store/spinner/reducers/spinner.reducer.ts @@ -4,14 +4,14 @@ import { setSpinnerState } from '../actions/spinner.actions'; export const STORE_FEATURE_SPINNER_KEY = 'Spinner'; export interface SpinnerState { - showSpinner: boolean; + showSpinner: boolean; } export const initialSpinnerState: SpinnerState = { - showSpinner: false, + showSpinner: false, }; export const spinnerReducer = createReducer( - initialSpinnerState, - on(setSpinnerState, (state, { showSpinner }) => ({ ...state, showSpinner })), + initialSpinnerState, + on(setSpinnerState, (state, { showSpinner }) => ({ ...state, showSpinner })) ); diff --git a/src/app/store/spinner/selectors/spinner.selectors.spec.ts b/src/app/store/spinner/selectors/spinner.selectors.spec.ts index 08bb9f445a..501e06bf32 100644 --- a/src/app/store/spinner/selectors/spinner.selectors.spec.ts +++ b/src/app/store/spinner/selectors/spinner.selectors.spec.ts @@ -2,11 +2,11 @@ import { SpinnerState, initialSpinnerState } from '@store/spinner/reducers/spinn import { getSpinner } from '@store/spinner/selectors/spinner.selectors'; describe('Spinner Selectors', () => { - describe('getSpinner', () => { - it('should return the spinner', () => { - const state: SpinnerState = { ...initialSpinnerState, showSpinner: true }; - const selectedState = getSpinner.projector(state); - expect(selectedState).toEqual(state.showSpinner); - }); - }); + describe('getSpinner', () => { + it('should return the spinner', () => { + const state: SpinnerState = { ...initialSpinnerState, showSpinner: true }; + const selectedState = getSpinner.projector(state); + expect(selectedState).toEqual(state.showSpinner); + }); + }); }); diff --git a/src/app/store/spinner/selectors/spinner.selectors.ts b/src/app/store/spinner/selectors/spinner.selectors.ts index 99b9d40043..97fa3c8503 100644 --- a/src/app/store/spinner/selectors/spinner.selectors.ts +++ b/src/app/store/spinner/selectors/spinner.selectors.ts @@ -1,8 +1,8 @@ import { createFeatureSelector, createSelector } from '@ngrx/store'; -import { SpinnerState, STORE_FEATURE_SPINNER_KEY } from '../reducers/spinner.reducer'; +import { STORE_FEATURE_SPINNER_KEY, SpinnerState } from '../reducers/spinner.reducer'; export const getSpinnerState = createFeatureSelector(STORE_FEATURE_SPINNER_KEY); export const getSpinner = createSelector(getSpinnerState, (state) => { - return state.showSpinner; + return state.showSpinner; }); diff --git a/src/app/store/spinner/spinner-state.module.ts b/src/app/store/spinner/spinner-state.module.ts index ce07911533..91bf97abdc 100644 --- a/src/app/store/spinner/spinner-state.module.ts +++ b/src/app/store/spinner/spinner-state.module.ts @@ -1,10 +1,10 @@ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; import { StoreModule } from '@ngrx/store'; -import { spinnerReducer, STORE_FEATURE_SPINNER_KEY } from '@store/spinner/reducers/spinner.reducer'; +import { STORE_FEATURE_SPINNER_KEY, spinnerReducer } from '@store/spinner/reducers/spinner.reducer'; @NgModule({ - declarations: [], - imports: [CommonModule, StoreModule.forFeature(STORE_FEATURE_SPINNER_KEY, spinnerReducer)], + declarations: [], + imports: [CommonModule, StoreModule.forFeature(STORE_FEATURE_SPINNER_KEY, spinnerReducer)], }) export class SpinnerStateModule {} diff --git a/src/app/store/tech-record-search/actions/tech-record-search.actions.ts b/src/app/store/tech-record-search/actions/tech-record-search.actions.ts index 161fc808c0..eddddad410 100644 --- a/src/app/store/tech-record-search/actions/tech-record-search.actions.ts +++ b/src/app/store/tech-record-search/actions/tech-record-search.actions.ts @@ -1,13 +1,16 @@ import { GlobalError } from '@core/components/global-error/global-error.interface'; import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; -import { createAction, props } from '@ngrx/store'; import { SEARCH_TYPES } from '@models/search-types-enum'; +import { createAction, props } from '@ngrx/store'; export const fetchSearchResult = createAction(getTitle(), props<{ searchBy?: SEARCH_TYPES; term: string }>()); -export const fetchSearchResultSuccess = createAction(getTitle('Success'), props<{ payload: TechRecordSearchSchema[] }>()); +export const fetchSearchResultSuccess = createAction( + getTitle('Success'), + props<{ payload: TechRecordSearchSchema[] }>() +); export const fetchSearchResultFailed = createAction(getTitle('Failed'), props()); function getTitle(suffix = ''): string { - suffix = suffix ? ` ${suffix}` : suffix; - return `[API/tech-records search] Search Results ${suffix}`; + suffix = suffix ? ` ${suffix}` : suffix; + return `[API/tech-records search] Search Results ${suffix}`; } diff --git a/src/app/store/tech-record-search/effects/tech-record-search.effect.spec.ts b/src/app/store/tech-record-search/effects/tech-record-search.effect.spec.ts index 8c767af569..c1f5eea4c7 100644 --- a/src/app/store/tech-record-search/effects/tech-record-search.effect.spec.ts +++ b/src/app/store/tech-record-search/effects/tech-record-search.effect.spec.ts @@ -9,76 +9,83 @@ import { TechnicalRecordHttpService } from '@services/technical-record-http/tech import { initialAppState } from '@store/index'; import { Observable } from 'rxjs'; import { TestScheduler } from 'rxjs/testing'; -import { fetchSearchResult, fetchSearchResultFailed, fetchSearchResultSuccess } from '../actions/tech-record-search.actions'; +import { + fetchSearchResult, + fetchSearchResultFailed, + fetchSearchResultSuccess, +} from '../actions/tech-record-search.actions'; import { TechSearchResultsEffects } from './tech-record-search.effect'; describe('DefectsEffects', () => { - let effects: TechSearchResultsEffects; - let actions$ = new Observable(); - let testScheduler: TestScheduler; - let service: TechnicalRecordHttpService; + let effects: TechSearchResultsEffects; + let actions$ = new Observable(); + let testScheduler: TestScheduler; + let service: TechnicalRecordHttpService; - const expectedResult = { systemNumber: '1' } as TechRecordSearchSchema; - const testCases = [ - { - id: expectedResult.systemNumber, - payload: [expectedResult], - }, - ]; + const expectedResult = { systemNumber: '1' } as TechRecordSearchSchema; + const testCases = [ + { + id: expectedResult.systemNumber, + payload: [expectedResult], + }, + ]; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - TechSearchResultsEffects, - provideMockActions(() => actions$), - TechnicalRecordHttpService, - provideMockStore({ - initialState: initialAppState, - }), - ], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + TechSearchResultsEffects, + provideMockActions(() => actions$), + TechnicalRecordHttpService, + provideMockStore({ + initialState: initialAppState, + }), + ], + }); - effects = TestBed.inject(TechSearchResultsEffects); - service = TestBed.inject(TechnicalRecordHttpService); - }); + effects = TestBed.inject(TechSearchResultsEffects); + service = TestBed.inject(TechnicalRecordHttpService); + }); - beforeEach(() => { - testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - }); + beforeEach(() => { + testScheduler = new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); + }); + }); - describe('fetchSearchResults$', () => { - it.each(testCases)('should return fetchSearchResultsSuccess action on successfull API call', (value) => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const { payload } = value; + describe('fetchSearchResults$', () => { + it.each(testCases)('should return fetchSearchResultsSuccess action on successfull API call', (value) => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const { payload } = value; - // mock action to trigger effect - actions$ = hot('-a--', { a: fetchSearchResult }); + // mock action to trigger effect + actions$ = hot('-a--', { a: fetchSearchResult }); - // mock service call - jest.spyOn(service, 'search$').mockReturnValue(cold('--a|', { a: payload })); + // mock service call + jest.spyOn(service, 'search$').mockReturnValue(cold('--a|', { a: payload })); - // expect effect to return success action - expectObservable(effects.fetchSearchResults$).toBe('---b', { - b: fetchSearchResultSuccess({ payload }), - }); - }); - }); + // expect effect to return success action + expectObservable(effects.fetchSearchResults$).toBe('---b', { + b: fetchSearchResultSuccess({ payload }), + }); + }); + }); - it.each(testCases)('should return fetchSearchResults action on API error', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - actions$ = hot('-a--', { a: fetchSearchResult({ searchBy: SEARCH_TYPES.VIN, term: 'foo' }) }); + it.each(testCases)('should return fetchSearchResults action on API error', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + actions$ = hot('-a--', { a: fetchSearchResult({ searchBy: SEARCH_TYPES.VIN, term: 'foo' }) }); - const expectedError = new Error('Oopsi'); + const expectedError = new Error('Oopsi'); - jest.spyOn(service, 'search$').mockReturnValue(cold('--#|', {}, expectedError)); + jest.spyOn(service, 'search$').mockReturnValue(cold('--#|', {}, expectedError)); - expectObservable(effects.fetchSearchResults$).toBe('---b', { - b: fetchSearchResultFailed({ error: 'There was a problem getting the Tech Record by vin', anchorLink: 'search-term' }), - }); - }); - }); - }); + expectObservable(effects.fetchSearchResults$).toBe('---b', { + b: fetchSearchResultFailed({ + error: 'There was a problem getting the Tech Record by vin', + anchorLink: 'search-term', + }), + }); + }); + }); + }); }); diff --git a/src/app/store/tech-record-search/effects/tech-record-search.effect.ts b/src/app/store/tech-record-search/effects/tech-record-search.effect.ts index 8c3b75aac3..fa4e716447 100644 --- a/src/app/store/tech-record-search/effects/tech-record-search.effect.ts +++ b/src/app/store/tech-record-search/effects/tech-record-search.effect.ts @@ -1,41 +1,55 @@ import { Injectable } from '@angular/core'; +import { SEARCH_TYPES } from '@models/search-types-enum'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { TechnicalRecordHttpService } from '@services/technical-record-http/technical-record-http.service'; -import { SEARCH_TYPES } from '@models/search-types-enum'; +import { catchError, map, of, switchMap } from 'rxjs'; import { - catchError, map, of, switchMap, -} from 'rxjs'; -import { fetchSearchResult, fetchSearchResultFailed, fetchSearchResultSuccess } from '../actions/tech-record-search.actions'; + fetchSearchResult, + fetchSearchResultFailed, + fetchSearchResultSuccess, +} from '../actions/tech-record-search.actions'; @Injectable() export class TechSearchResultsEffects { - fetchSearchResults$ = createEffect(() => - this.actions$.pipe( - ofType(fetchSearchResult), - switchMap(({ searchBy, term }) => - this.techRecordHttpService.search$(searchBy ?? SEARCH_TYPES.ALL, term).pipe( - map((results) => fetchSearchResultSuccess({ payload: results })), - catchError((e) => - of(fetchSearchResultFailed({ error: this.getTechRecordErrorMessage(e, 'getTechnicalRecords', searchBy), anchorLink: 'search-term' }))), - )), - )); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - getTechRecordErrorMessage(error: any, type: string, search?: string): string { - if (typeof error !== 'object') { - return error; - } if (error.status === 404) { - return this.apiErrors[`${type}_404`]; - } - const messageFromSearchType = search === SEARCH_TYPES.ALL ? 'the current search criteria' : search; - return `${this.apiErrors[`${type}_400`]} ${messageFromSearchType ?? JSON.stringify(error.error)}`; + fetchSearchResults$ = createEffect(() => + this.actions$.pipe( + ofType(fetchSearchResult), + switchMap(({ searchBy, term }) => + this.techRecordHttpService.search$(searchBy ?? SEARCH_TYPES.ALL, term).pipe( + map((results) => fetchSearchResultSuccess({ payload: results })), + catchError((e) => + of( + fetchSearchResultFailed({ + error: this.getTechRecordErrorMessage(e, 'getTechnicalRecords', searchBy), + anchorLink: 'search-term', + }) + ) + ) + ) + ) + ) + ); - } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getTechRecordErrorMessage(error: any, type: string, search?: string): string { + if (typeof error !== 'object') { + return error; + } + if (error.status === 404) { + return this.apiErrors[`${type}_404`]; + } + const messageFromSearchType = search === SEARCH_TYPES.ALL ? 'the current search criteria' : search; + return `${this.apiErrors[`${type}_400`]} ${messageFromSearchType ?? JSON.stringify(error.error)}`; + } - private apiErrors: Record = { - getTechnicalRecords_400: 'There was a problem getting the Tech Record by', - getTechnicalRecords_404: 'Vehicle not found, check the vehicle registration mark, trailer ID or vehicle identification number', - }; + private apiErrors: Record = { + getTechnicalRecords_400: 'There was a problem getting the Tech Record by', + getTechnicalRecords_404: + 'Vehicle not found, check the vehicle registration mark, trailer ID or vehicle identification number', + }; - constructor(private actions$: Actions, private techRecordHttpService: TechnicalRecordHttpService) {} + constructor( + private actions$: Actions, + private techRecordHttpService: TechnicalRecordHttpService + ) {} } diff --git a/src/app/store/tech-record-search/reducer/tech-record-search.reducer.spec.ts b/src/app/store/tech-record-search/reducer/tech-record-search.reducer.spec.ts index d98557a741..370a99de8b 100644 --- a/src/app/store/tech-record-search/reducer/tech-record-search.reducer.spec.ts +++ b/src/app/store/tech-record-search/reducer/tech-record-search.reducer.spec.ts @@ -1,46 +1,50 @@ import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; -import { fetchSearchResult, fetchSearchResultFailed, fetchSearchResultSuccess } from '../actions/tech-record-search.actions'; +import { + fetchSearchResult, + fetchSearchResultFailed, + fetchSearchResultSuccess, +} from '../actions/tech-record-search.actions'; import { SearchResultState, initialTechSearchResultState, techSearchResultReducer } from './tech-record-search.reducer'; describe('fetchSearchResults actions', () => { - it('should set loading to true', () => { - const newState: SearchResultState = { ...initialTechSearchResultState, loading: true }; - const action = fetchSearchResult({ term: 'foo' }); - const state = techSearchResultReducer(initialTechSearchResultState, action); + it('should set loading to true', () => { + const newState: SearchResultState = { ...initialTechSearchResultState, loading: true }; + const action = fetchSearchResult({ term: 'foo' }); + const state = techSearchResultReducer(initialTechSearchResultState, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); - describe('fetchSearchResultsSuccess', () => { - it('should set all test result records', () => { - const mockSearchResult = [ - { - systemNumber: '123456', - createdTimestamp: '10-22-10', - }, - ] as TechRecordSearchSchema[]; - const newState: SearchResultState = { - ...initialTechSearchResultState, - ids: ['123456#10-22-10'], - entities: { '123456#10-22-10': mockSearchResult[0] }, - }; - const action = fetchSearchResultSuccess({ payload: mockSearchResult }); - const state = techSearchResultReducer(initialTechSearchResultState, action); + describe('fetchSearchResultsSuccess', () => { + it('should set all test result records', () => { + const mockSearchResult = [ + { + systemNumber: '123456', + createdTimestamp: '10-22-10', + }, + ] as TechRecordSearchSchema[]; + const newState: SearchResultState = { + ...initialTechSearchResultState, + ids: ['123456#10-22-10'], + entities: { '123456#10-22-10': mockSearchResult[0] }, + }; + const action = fetchSearchResultSuccess({ payload: mockSearchResult }); + const state = techSearchResultReducer(initialTechSearchResultState, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); - describe('fetchSearchResultsFailed', () => { - it('should set error state', () => { - const newState = { ...initialTechSearchResultState, loading: false, error: ':cry:' }; - const action = fetchSearchResultFailed({ error: ':cry:' }); - const state = techSearchResultReducer({ ...initialTechSearchResultState, loading: true }, action); + describe('fetchSearchResultsFailed', () => { + it('should set error state', () => { + const newState = { ...initialTechSearchResultState, loading: false, error: ':cry:' }; + const action = fetchSearchResultFailed({ error: ':cry:' }); + const state = techSearchResultReducer({ ...initialTechSearchResultState, loading: true }, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + }); }); diff --git a/src/app/store/tech-record-search/reducer/tech-record-search.reducer.ts b/src/app/store/tech-record-search/reducer/tech-record-search.reducer.ts index dd128b0826..311554e567 100644 --- a/src/app/store/tech-record-search/reducer/tech-record-search.reducer.ts +++ b/src/app/store/tech-record-search/reducer/tech-record-search.reducer.ts @@ -1,30 +1,40 @@ import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; import { EntityAdapter, EntityState, createEntityAdapter } from '@ngrx/entity'; import { createFeatureSelector, createReducer, on } from '@ngrx/store'; -import { fetchSearchResult, fetchSearchResultFailed, fetchSearchResultSuccess } from '../actions/tech-record-search.actions'; +import { + fetchSearchResult, + fetchSearchResultFailed, + fetchSearchResultSuccess, +} from '../actions/tech-record-search.actions'; export interface SearchResultState extends EntityState { - loading: boolean; - error: string; + loading: boolean; + error: string; } export const STORE_FEATURE_SEARCH_TECH_RESULTS_KEY = 'techSearchResults'; -export const techSearchResultFeatureState = createFeatureSelector(STORE_FEATURE_SEARCH_TECH_RESULTS_KEY); +export const techSearchResultFeatureState = createFeatureSelector( + STORE_FEATURE_SEARCH_TECH_RESULTS_KEY +); -export const techSearchResultAdapter: EntityAdapter = createEntityAdapter({ - selectId: (result) => `${result.systemNumber}#${result.createdTimestamp}`, -}); +export const techSearchResultAdapter: EntityAdapter = + createEntityAdapter({ + selectId: (result) => `${result.systemNumber}#${result.createdTimestamp}`, + }); export const initialTechSearchResultState = techSearchResultAdapter.getInitialState({ loading: false, error: '' }); export const techSearchResultReducer = createReducer( - initialTechSearchResultState, - on(fetchSearchResult, (state) => ({ ...state, loading: true })), - on(fetchSearchResultSuccess, (state, action) => ({ ...techSearchResultAdapter.setAll(action.payload, state), loading: false })), - on(fetchSearchResultFailed, (state, action) => ({ - ...techSearchResultAdapter.setAll([], state), - loading: false, - error: action.error, - })), + initialTechSearchResultState, + on(fetchSearchResult, (state) => ({ ...state, loading: true })), + on(fetchSearchResultSuccess, (state, action) => ({ + ...techSearchResultAdapter.setAll(action.payload, state), + loading: false, + })), + on(fetchSearchResultFailed, (state, action) => ({ + ...techSearchResultAdapter.setAll([], state), + loading: false, + error: action.error, + })) ); diff --git a/src/app/store/tech-record-search/selector/tech-record-search.selector.spec.ts b/src/app/store/tech-record-search/selector/tech-record-search.selector.spec.ts index 84621dea90..6d67775b3a 100644 --- a/src/app/store/tech-record-search/selector/tech-record-search.selector.spec.ts +++ b/src/app/store/tech-record-search/selector/tech-record-search.selector.spec.ts @@ -1,156 +1,163 @@ import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; import { initialTechSearchResultState } from '../reducer/tech-record-search.reducer'; -import { selectTechRecordSearchResults, selectTechRecordSearchResultsBySystemNumber } from './tech-record-search.selector'; +import { + selectTechRecordSearchResults, + selectTechRecordSearchResultsBySystemNumber, +} from './tech-record-search.selector'; describe('Tech Record Search Selectors', () => { - describe('selectTechRecordsSearchResults', () => { - it('should return the records in state', () => { - const state = { ...initialTechSearchResultState, ids: [1], entities: { 1: { systemNumber: '123' } as TechRecordSearchSchema } }; - const selectedState = selectTechRecordSearchResults.projector(state); - expect(selectedState).toEqual([{ systemNumber: '123' }]); - }); - }); - describe('selectTechRecordsSearchResultsBySystemNumber', () => { - const testCases = [ - { - results: [ - { - systemNumber: '123456', - }, - { - systemNumber: '123456', - }, - { - systemNumber: '123456', - }, - { - systemNumber: '123456', - }, - ], - }, - { - results: [ - { - systemNumber: '123456', - }, - { - systemNumber: '7545677', - }, - { - systemNumber: '123456', - }, - { - systemNumber: '12', - }, - ], - }, - { - results: [ - { - systemNumber: '4444', - }, - { - systemNumber: '4444', - }, - { - systemNumber: '123456', - }, - { - systemNumber: '12', - }, - ], - }, - ] as { results: TechRecordSearchSchema[] }[]; + describe('selectTechRecordsSearchResults', () => { + it('should return the records in state', () => { + const state = { + ...initialTechSearchResultState, + ids: [1], + entities: { 1: { systemNumber: '123' } as TechRecordSearchSchema }, + }; + const selectedState = selectTechRecordSearchResults.projector(state); + expect(selectedState).toEqual([{ systemNumber: '123' }]); + }); + }); + describe('selectTechRecordsSearchResultsBySystemNumber', () => { + const testCases = [ + { + results: [ + { + systemNumber: '123456', + }, + { + systemNumber: '123456', + }, + { + systemNumber: '123456', + }, + { + systemNumber: '123456', + }, + ], + }, + { + results: [ + { + systemNumber: '123456', + }, + { + systemNumber: '7545677', + }, + { + systemNumber: '123456', + }, + { + systemNumber: '12', + }, + ], + }, + { + results: [ + { + systemNumber: '4444', + }, + { + systemNumber: '4444', + }, + { + systemNumber: '123456', + }, + { + systemNumber: '12', + }, + ], + }, + ] as { results: TechRecordSearchSchema[] }[]; - it.each(testCases)('should group the search results by systemNumber', ({ results }) => { - const selectedState = selectTechRecordSearchResultsBySystemNumber.projector(results); - const expectedLength = new Set(results.map((r) => r.systemNumber)).size; - expect(selectedState).toHaveLength(expectedLength); - }); - const now = new Date(); - const oneDayAgo = new Date(); - oneDayAgo.setDate(new Date().getDate() - 1); - const twoDaysAgo = new Date(); - twoDaysAgo.setDate(new Date().getDate() - 2); - const statusCases = [ - { - results: [ - { - systemNumber: '123456', - techRecord_statusCode: 'current', - }, - { - systemNumber: '123456', - }, - { - systemNumber: '123456', - }, - { - systemNumber: '123456', - }, - ], - status: 'current', - }, - { - results: [ - { - systemNumber: '123456', - }, - { - systemNumber: '123456', - }, - { - systemNumber: '123456', - techRecord_statusCode: 'provisional', - }, - { - systemNumber: '123456', - }, - ], + it.each(testCases)('should group the search results by systemNumber', ({ results }) => { + const selectedState = selectTechRecordSearchResultsBySystemNumber.projector(results); + const expectedLength = new Set(results.map((r) => r.systemNumber)).size; + expect(selectedState).toHaveLength(expectedLength); + }); + const now = new Date(); + const oneDayAgo = new Date(); + oneDayAgo.setDate(new Date().getDate() - 1); + const twoDaysAgo = new Date(); + twoDaysAgo.setDate(new Date().getDate() - 2); + const statusCases = [ + { + results: [ + { + systemNumber: '123456', + techRecord_statusCode: 'current', + }, + { + systemNumber: '123456', + }, + { + systemNumber: '123456', + }, + { + systemNumber: '123456', + }, + ], + status: 'current', + }, + { + results: [ + { + systemNumber: '123456', + }, + { + systemNumber: '123456', + }, + { + systemNumber: '123456', + techRecord_statusCode: 'provisional', + }, + { + systemNumber: '123456', + }, + ], - status: 'provisional', - }, - { - results: [ - { - systemNumber: '123456', - }, - { - systemNumber: '123456', - techRecord_statusCode: 'current', - }, - { - systemNumber: '123456', - techRecord_statusCode: 'provisional', - }, - { - systemNumber: '123456', - }, - ], - status: 'current', - }, - { - results: [ - { - systemNumber: '123456', - createdTimestamp: twoDaysAgo.toISOString(), - }, - { - systemNumber: '123456', - createdTimestamp: oneDayAgo.toISOString(), - }, - { - systemNumber: '123456', - createdTimestamp: now.toISOString(), - techRecord_statusCode: 'this is the right record', - }, - ], - status: 'this is the right record', - }, - ] as { results: TechRecordSearchSchema[]; status: string }[]; - it.each(statusCases)('should group the search results by systemNumber', ({ results, status }) => { - const selectedState = selectTechRecordSearchResultsBySystemNumber.projector(results); - expect(selectedState[0].techRecord_statusCode).toBe(status); - }); - }); + status: 'provisional', + }, + { + results: [ + { + systemNumber: '123456', + }, + { + systemNumber: '123456', + techRecord_statusCode: 'current', + }, + { + systemNumber: '123456', + techRecord_statusCode: 'provisional', + }, + { + systemNumber: '123456', + }, + ], + status: 'current', + }, + { + results: [ + { + systemNumber: '123456', + createdTimestamp: twoDaysAgo.toISOString(), + }, + { + systemNumber: '123456', + createdTimestamp: oneDayAgo.toISOString(), + }, + { + systemNumber: '123456', + createdTimestamp: now.toISOString(), + techRecord_statusCode: 'this is the right record', + }, + ], + status: 'this is the right record', + }, + ] as { results: TechRecordSearchSchema[]; status: string }[]; + it.each(statusCases)('should group the search results by systemNumber', ({ results, status }) => { + const selectedState = selectTechRecordSearchResultsBySystemNumber.projector(results); + expect(selectedState[0].techRecord_statusCode).toBe(status); + }); + }); }); diff --git a/src/app/store/tech-record-search/selector/tech-record-search.selector.ts b/src/app/store/tech-record-search/selector/tech-record-search.selector.ts index 6aa59b2f82..81e75ac834 100644 --- a/src/app/store/tech-record-search/selector/tech-record-search.selector.ts +++ b/src/app/store/tech-record-search/selector/tech-record-search.selector.ts @@ -4,26 +4,35 @@ import { techSearchResultAdapter, techSearchResultFeatureState } from '../reduce const { selectAll } = techSearchResultAdapter.getSelectors(); -export const selectTechRecordSearchLoadingState = createSelector(techSearchResultFeatureState, (state) => state.loading); +export const selectTechRecordSearchLoadingState = createSelector( + techSearchResultFeatureState, + (state) => state.loading +); export const selectTechRecordSearchResults = createSelector(techSearchResultFeatureState, (state) => selectAll(state)); -export const selectTechRecordSearchResultsBySystemNumber = createSelector(selectTechRecordSearchResults, (searchResults) => { - const records: TechRecordSearchSchema[] = []; - const visitedSystemNumbers = new Set(); - searchResults.forEach((result) => { - if (!visitedSystemNumbers.has(result.systemNumber)) { - visitedSystemNumbers.add(result.systemNumber); - const recordsWithSameSystemNumber = searchResults.filter((record) => record.systemNumber === result.systemNumber); - const mostCurrentRecord = recordsWithSameSystemNumber.find((r) => r.techRecord_statusCode === 'current') - ?? recordsWithSameSystemNumber.find((r) => r.techRecord_statusCode === 'provisional') - ?? recordsWithSameSystemNumber.find( - (r) => - new Date(r.createdTimestamp).getTime() - === Math.max(...recordsWithSameSystemNumber.map((rec) => new Date(rec.createdTimestamp).getTime())), - ) - ?? records[0]; - records.push(mostCurrentRecord); - } - }); - return records; -}); +export const selectTechRecordSearchResultsBySystemNumber = createSelector( + selectTechRecordSearchResults, + (searchResults) => { + const records: TechRecordSearchSchema[] = []; + const visitedSystemNumbers = new Set(); + searchResults.forEach((result) => { + if (!visitedSystemNumbers.has(result.systemNumber)) { + visitedSystemNumbers.add(result.systemNumber); + const recordsWithSameSystemNumber = searchResults.filter( + (record) => record.systemNumber === result.systemNumber + ); + const mostCurrentRecord = + recordsWithSameSystemNumber.find((r) => r.techRecord_statusCode === 'current') ?? + recordsWithSameSystemNumber.find((r) => r.techRecord_statusCode === 'provisional') ?? + recordsWithSameSystemNumber.find( + (r) => + new Date(r.createdTimestamp).getTime() === + Math.max(...recordsWithSameSystemNumber.map((rec) => new Date(rec.createdTimestamp).getTime())) + ) ?? + records[0]; + records.push(mostCurrentRecord); + } + }); + return records; + } +); diff --git a/src/app/store/tech-record-search/tech-record-search-state.module.ts b/src/app/store/tech-record-search/tech-record-search-state.module.ts index 7a0fbc05da..82f8711cdb 100644 --- a/src/app/store/tech-record-search/tech-record-search-state.module.ts +++ b/src/app/store/tech-record-search/tech-record-search-state.module.ts @@ -2,15 +2,15 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { EffectsModule } from '@ngrx/effects'; import { StoreModule } from '@ngrx/store'; -import { STORE_FEATURE_SEARCH_TECH_RESULTS_KEY, techSearchResultReducer } from './reducer/tech-record-search.reducer'; import { TechSearchResultsEffects } from './effects/tech-record-search.effect'; +import { STORE_FEATURE_SEARCH_TECH_RESULTS_KEY, techSearchResultReducer } from './reducer/tech-record-search.reducer'; @NgModule({ - declarations: [], - imports: [ - CommonModule, - StoreModule.forFeature(STORE_FEATURE_SEARCH_TECH_RESULTS_KEY, techSearchResultReducer), - EffectsModule.forFeature([TechSearchResultsEffects]), - ], + declarations: [], + imports: [ + CommonModule, + StoreModule.forFeature(STORE_FEATURE_SEARCH_TECH_RESULTS_KEY, techSearchResultReducer), + EffectsModule.forFeature([TechSearchResultsEffects]), + ], }) export class TechRecordSearchStateModule {} diff --git a/src/app/store/technical-records/actions/batch-create.actions.ts b/src/app/store/technical-records/actions/batch-create.actions.ts index 0f1aa96b67..ae41cd0a99 100644 --- a/src/app/store/technical-records/actions/batch-create.actions.ts +++ b/src/app/store/technical-records/actions/batch-create.actions.ts @@ -2,12 +2,24 @@ import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { createAction, props } from '@ngrx/store'; export const upsertVehicleBatch = createAction( - '[Technical Record Batch Create] upsert many', - props<{ vehicles: Array<{ vin: string; trailerId?: string; primaryVrm?: string }> }>(), + '[Technical Record Batch Create] upsert many', + props<{ vehicles: Array<{ vin: string; trailerId?: string; primaryVrm?: string }> }>() ); -export const setGenerateNumberFlag = createAction('[Technical Record Batch Create] set generate number', props<{ generateNumber: boolean }>()); -export const setApplicationId = createAction('[Technical Record Batch Create] set batch ID', props<{ applicationId: string }>()); -export const setVehicleStatus = createAction('[Technical Record Batch Create] set record status', props<{ vehicleStatus: string }>()); -export const setVehicleType = createAction('[Technical Record Batch Create] set batch vehicle type', props<{ vehicleType: VehicleTypes }>()); +export const setGenerateNumberFlag = createAction( + '[Technical Record Batch Create] set generate number', + props<{ generateNumber: boolean }>() +); +export const setApplicationId = createAction( + '[Technical Record Batch Create] set batch ID', + props<{ applicationId: string }>() +); +export const setVehicleStatus = createAction( + '[Technical Record Batch Create] set record status', + props<{ vehicleStatus: string }>() +); +export const setVehicleType = createAction( + '[Technical Record Batch Create] set batch vehicle type', + props<{ vehicleType: VehicleTypes }>() +); export const clearBatch = createAction('[Technical Record Batch Create] clear all'); diff --git a/src/app/store/technical-records/actions/technical-record-service.actions.spec.ts b/src/app/store/technical-records/actions/technical-record-service.actions.spec.ts index efeebae44b..e3bb907ffc 100644 --- a/src/app/store/technical-records/actions/technical-record-service.actions.spec.ts +++ b/src/app/store/technical-records/actions/technical-record-service.actions.spec.ts @@ -1,63 +1,63 @@ import { - archiveTechRecord, - archiveTechRecordFailure, - archiveTechRecordSuccess, - changeVehicleType, - clearADRDetailsBeforeUpdate, - createVehicle, - createVehicleRecord, - createVehicleRecordFailure, - createVehicleRecordSuccess, - getBySystemNumber, - getBySystemNumberFailure, - getBySystemNumberSuccess, - unarchiveTechRecord, - unarchiveTechRecordFailure, - unarchiveTechRecordSuccess, - updateEditingTechRecord, - updateEditingTechRecordCancel, - updateTechRecord, - updateTechRecordFailure, - updateTechRecordSuccess, + archiveTechRecord, + archiveTechRecordFailure, + archiveTechRecordSuccess, + changeVehicleType, + clearADRDetailsBeforeUpdate, + createVehicle, + createVehicleRecord, + createVehicleRecordFailure, + createVehicleRecordSuccess, + getBySystemNumber, + getBySystemNumberFailure, + getBySystemNumberSuccess, + unarchiveTechRecord, + unarchiveTechRecordFailure, + unarchiveTechRecordSuccess, + updateEditingTechRecord, + updateEditingTechRecordCancel, + updateTechRecord, + updateTechRecordFailure, + updateTechRecordSuccess, } from './technical-record-service.actions'; const SUCCESS = ' Success'; const FAILURE = ' Failure'; describe('Technical record actions', () => { - it('should have correct types', () => { - expect(getBySystemNumber.type).toBe(getMessage('getBySystemNumber')); - expect(getBySystemNumberSuccess.type).toBe(getMessage('getBySystemNumber', SUCCESS)); - expect(getBySystemNumberFailure.type).toBe(getMessage('getBySystemNumber', FAILURE)); + it('should have correct types', () => { + expect(getBySystemNumber.type).toBe(getMessage('getBySystemNumber')); + expect(getBySystemNumberSuccess.type).toBe(getMessage('getBySystemNumber', SUCCESS)); + expect(getBySystemNumberFailure.type).toBe(getMessage('getBySystemNumber', FAILURE)); - expect(createVehicleRecord.type).toBe(getMessage('createVehicleRecord')); - expect(createVehicleRecordSuccess.type).toBe(getMessage('createVehicleRecord', SUCCESS)); - expect(createVehicleRecordFailure.type).toBe(getMessage('createVehicleRecord', FAILURE)); + expect(createVehicleRecord.type).toBe(getMessage('createVehicleRecord')); + expect(createVehicleRecordSuccess.type).toBe(getMessage('createVehicleRecord', SUCCESS)); + expect(createVehicleRecordFailure.type).toBe(getMessage('createVehicleRecord', FAILURE)); - expect(updateTechRecord.type).toBe(getMessage('updateTechRecords')); - expect(updateTechRecordSuccess.type).toBe(getMessage('updateTechRecords', SUCCESS)); - expect(updateTechRecordFailure.type).toBe(getMessage('updateTechRecords', FAILURE)); + expect(updateTechRecord.type).toBe(getMessage('updateTechRecords')); + expect(updateTechRecordSuccess.type).toBe(getMessage('updateTechRecords', SUCCESS)); + expect(updateTechRecordFailure.type).toBe(getMessage('updateTechRecords', FAILURE)); - expect(archiveTechRecord.type).toBe(getMessage('archiveTechRecord')); - expect(archiveTechRecordSuccess.type).toBe(getMessage('archiveTechRecord', SUCCESS)); - expect(archiveTechRecordFailure.type).toBe(getMessage('archiveTechRecord', FAILURE)); + expect(archiveTechRecord.type).toBe(getMessage('archiveTechRecord')); + expect(archiveTechRecordSuccess.type).toBe(getMessage('archiveTechRecord', SUCCESS)); + expect(archiveTechRecordFailure.type).toBe(getMessage('archiveTechRecord', FAILURE)); - expect(updateEditingTechRecord.type).toBe(getMessage('updateEditingTechRecord')); + expect(updateEditingTechRecord.type).toBe(getMessage('updateEditingTechRecord')); - expect(updateEditingTechRecordCancel.type).toBe(getMessage('updateEditingTechRecordCancel')); + expect(updateEditingTechRecordCancel.type).toBe(getMessage('updateEditingTechRecordCancel')); - expect(changeVehicleType.type).toBe(getMessage('changeVehicleType')); + expect(changeVehicleType.type).toBe(getMessage('changeVehicleType')); - expect(createVehicle.type).toBe(getMessage('createVehicle')); + expect(createVehicle.type).toBe(getMessage('createVehicle')); - expect(unarchiveTechRecord.type).toBe(getMessage('unarchiveTechRecord')); - expect(unarchiveTechRecordFailure.type).toBe(getMessage('unarchiveTechRecord', FAILURE)); - expect(unarchiveTechRecordSuccess.type).toBe(getMessage('unarchiveTechRecord', SUCCESS)); + expect(unarchiveTechRecord.type).toBe(getMessage('unarchiveTechRecord')); + expect(unarchiveTechRecordFailure.type).toBe(getMessage('unarchiveTechRecord', FAILURE)); + expect(unarchiveTechRecordSuccess.type).toBe(getMessage('unarchiveTechRecord', SUCCESS)); - expect(clearADRDetailsBeforeUpdate.type).toBe(getMessage('clearADRDetailsBeforeUpdate')); - }); + expect(clearADRDetailsBeforeUpdate.type).toBe(getMessage('clearADRDetailsBeforeUpdate')); + }); }); function getMessage(title: string, suffix = '') { - return `[Technical Record Service] ${title}${suffix}`; + return `[Technical Record Service] ${title}${suffix}`; } diff --git a/src/app/store/technical-records/actions/technical-record-service.actions.ts b/src/app/store/technical-records/actions/technical-record-service.actions.ts index 3e70e03b7b..12a8a16728 100644 --- a/src/app/store/technical-records/actions/technical-record-service.actions.ts +++ b/src/app/store/technical-records/actions/technical-record-service.actions.ts @@ -3,65 +3,84 @@ import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; import { PsvMake } from '@models/reference-data.model'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; -import { - ActionCreator, ActionCreatorProps, createAction, props, -} from '@ngrx/store'; +import { ActionCreator, ActionCreatorProps, createAction, props } from '@ngrx/store'; // eslint-disable-next-line import/no-unresolved import { TypedAction } from '@ngrx/store/src/models'; const prefix = '[Technical Record Service]'; export const getBySystemNumber = createAction(`${prefix} getBySystemNumber`, props<{ systemNumber: string }>()); -export const getBySystemNumberSuccess = createAction(`${prefix} getBySystemNumber Success`, props<{ techRecordHistory: TechRecordSearchSchema[] }>()); +export const getBySystemNumberSuccess = createAction( + `${prefix} getBySystemNumber Success`, + props<{ techRecordHistory: TechRecordSearchSchema[] }>() +); export const getBySystemNumberFailure = createAction(`${prefix} getBySystemNumber Failure`, props()); -export const getTechRecordV3 = createAction(`${prefix} getTechRecordV3`, props<{ systemNumber: string; createdTimestamp: string }>()); +export const getTechRecordV3 = createAction( + `${prefix} getTechRecordV3`, + props<{ systemNumber: string; createdTimestamp: string }>() +); export const getTechRecordV3Success = createOutcomeAction('getTechRecordV3', true); export const getTechRecordV3Failure = createOutcomeAction('getTechRecordV3', false); -export const createVehicleRecord = createAction(`${prefix} createVehicleRecord`, props<{ vehicle: TechRecordType<'put'> }>()); +export const createVehicleRecord = createAction( + `${prefix} createVehicleRecord`, + props<{ vehicle: TechRecordType<'put'> }>() +); export const createVehicleRecordSuccess = createOutcomeAction('createVehicleRecord', true); export const createVehicleRecordFailure = createOutcomeAction('createVehicleRecord', false); export const updateTechRecord = createAction( - `${prefix} updateTechRecords`, - props<{ systemNumber: string; createdTimestamp: string }>(), + `${prefix} updateTechRecords`, + props<{ systemNumber: string; createdTimestamp: string }>() ); export const updateTechRecordSuccess = createOutcomeAction('updateTechRecords', true); export const updateTechRecordFailure = createOutcomeAction('updateTechRecords', false); export const amendVin = createAction( - `${prefix} amendVin`, - props<{ newVin: string; systemNumber: string; createdTimestamp: string }>(), + `${prefix} amendVin`, + props<{ newVin: string; systemNumber: string; createdTimestamp: string }>() ); export const amendVinSuccess = createOutcomeAction('amendVin', true); export const amendVinFailure = createOutcomeAction('amendVin', false); export const amendVrm = createAction( - `${prefix} amendVrm`, - props<{ newVrm: string; cherishedTransfer: boolean; systemNumber: string; createdTimestamp: string; thirdMark?: string }>(), + `${prefix} amendVrm`, + props<{ + newVrm: string; + cherishedTransfer: boolean; + systemNumber: string; + createdTimestamp: string; + thirdMark?: string; + }>() ); export const amendVrmSuccess = createOutcomeAction('amendVrm', true); export const amendVrmFailure = createOutcomeAction('amendVrm', false); export const archiveTechRecord = createAction( - `${prefix} archiveTechRecord`, - props<{ systemNumber: string; createdTimestamp: string; reasonForArchiving: string }>(), + `${prefix} archiveTechRecord`, + props<{ systemNumber: string; createdTimestamp: string; reasonForArchiving: string }>() ); export const archiveTechRecordSuccess = createOutcomeAction('archiveTechRecord', true); export const archiveTechRecordFailure = createOutcomeAction('archiveTechRecord', false); export const promoteTechRecord = createAction( - `${prefix} promoteTechRecord`, - props<{ systemNumber: string; createdTimestamp: string; reasonForPromoting: string }>(), + `${prefix} promoteTechRecord`, + props<{ systemNumber: string; createdTimestamp: string; reasonForPromoting: string }>() ); export const promoteTechRecordSuccess = createOutcomeAction('promoteTechRecord', true); export const promoteTechRecordFailure = createOutcomeAction('promoteTechRecord', false); -export const updateEditingTechRecord = createAction(`${prefix} updateEditingTechRecord`, props<{ vehicleTechRecord: TechRecordType<'put'> }>()); +export const updateEditingTechRecord = createAction( + `${prefix} updateEditingTechRecord`, + props<{ vehicleTechRecord: TechRecordType<'put'> }>() +); export const updateEditingTechRecordCancel = createAction(`${prefix} updateEditingTechRecordCancel`); -export const changeVehicleType = createAction(`${prefix} changeVehicleType`, props<{ techRecord_vehicleType: VehicleTypes }>()); +export const changeVehicleType = createAction( + `${prefix} changeVehicleType`, + props<{ techRecord_vehicleType: VehicleTypes }>() +); export const createVehicle = createAction(`${prefix} createVehicle`, props<{ techRecord_vehicleType: VehicleTypes }>()); @@ -71,17 +90,23 @@ export const generatePlateFailure = createOutcomeAction('generatePlate', false); export const canGeneratePlate = createAction(`${prefix} canGeneratePlate`); export const cannotGeneratePlate = createAction(`${prefix} cannotGeneratePlate`); -export const generateLetter = createAction(`${prefix} generateLetter`, props<{ letterType: string; paragraphId: number }>()); +export const generateLetter = createAction( + `${prefix} generateLetter`, + props<{ letterType: string; paragraphId: number }>() +); export const generateLetterSuccess = createAction(`${prefix} generateLetter Success`); export const generateLetterFailure = createOutcomeAction('generateLetter', false); -export const updateBrakeForces = createAction(`${prefix} updateBrakesForces`, props<{ grossLadenWeight?: number; grossKerbWeight?: number }>()); +export const updateBrakeForces = createAction( + `${prefix} updateBrakesForces`, + props<{ grossLadenWeight?: number; grossKerbWeight?: number }>() +); export const updateBody = createAction(`${prefix} updatebody`, props<{ psvMake: PsvMake }>()); export const unarchiveTechRecord = createAction( - `${prefix} unarchiveTechRecord`, - props<{ systemNumber: string; createdTimestamp: string; reasonForUnarchiving: string; status: string }>(), + `${prefix} unarchiveTechRecord`, + props<{ systemNumber: string; createdTimestamp: string; reasonForUnarchiving: string; status: string }>() ); export const unarchiveTechRecordSuccess = createOutcomeAction('unarchiveTechRecord', true); export const unarchiveTechRecordFailure = createOutcomeAction('unarchiveTechRecord', false); @@ -93,42 +118,65 @@ export const addSectionState = createAction(`${prefix} addSectionState`, props<{ export const removeSectionState = createAction(`${prefix} removeSectionState`, props<{ section: string | number }>()); export const clearAllSectionStates = createAction(`${prefix} clearAllSectionState`); -export const updateScrollPosition = createAction(`${prefix} updateScrollPosition`, props<{ position: [number, number] }>()); +export const updateScrollPosition = createAction( + `${prefix} updateScrollPosition`, + props<{ position: [number, number] }>() +); export const clearScrollPosition = createAction(`${prefix} clearScrollPosition`); export const clearADRDetailsBeforeUpdate = createAction(`${prefix} clearADRDetailsBeforeUpdate`); -export const updateADRAdditionalExaminerNotes = createAction(`${prefix} updateADRAdditionalExaminerNotes`, props<{ username: string }>()); +export const updateADRAdditionalExaminerNotes = createAction( + `${prefix} updateADRAdditionalExaminerNotes`, + props<{ username: string }>() +); export const updateExistingADRAdditionalExaminerNote = createAction( - `${prefix} updateExistingADRAdditionalExaminerNote`, - props<{ additionalExaminerNote: string, examinerNoteIndex: number }>(), + `${prefix} updateExistingADRAdditionalExaminerNote`, + props<{ additionalExaminerNote: string; examinerNoteIndex: number }>() ); -export const generateADRCertificate = createAction(`${prefix} generateADRCertificate`, props<{ - systemNumber: string, createdTimestamp: string, certificateType: string -}>()); -export const generateADRCertificateSuccess = createAction(`${prefix} generateADRCertificate Success`, props<{ id: string }>()); +export const generateADRCertificate = createAction( + `${prefix} generateADRCertificate`, + props<{ + systemNumber: string; + createdTimestamp: string; + certificateType: string; + }>() +); +export const generateADRCertificateSuccess = createAction( + `${prefix} generateADRCertificate Success`, + props<{ id: string }>() +); export const generateADRCertificateFailure = createOutcomeAction('generateADRCertificate', false); -export const generateContingencyADRCertificate = createAction(`${prefix} generateContingencyADRCertificate`, props<{ - systemNumber: string, createdTimestamp: string, certificateType: string -}>()); +export const generateContingencyADRCertificate = createAction( + `${prefix} generateContingencyADRCertificate`, + props<{ + systemNumber: string; + createdTimestamp: string; + certificateType: string; + }>() +); function createOutcomeAction( - title: string, - isSuccess: T, + title: string, + isSuccess: T ): ActionCreator< - string, - T extends false - ? (props: GlobalError) => GlobalError & TypedAction - : (props: { vehicleTechRecord: TechRecordType<'get'> }) => { vehicleTechRecord: TechRecordType<'get'> } & TypedAction - > { - const suffix = isSuccess ? 'Success' : 'Failure'; - const type = `${prefix} ${title} ${suffix}`; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const actionCreator: ActionCreatorProps = isSuccess ? props<{ vehicleTechRecord: TechRecordType<'get'>[] }>() : props(); - - return createAction(type, actionCreator); + string, + T extends false + ? (props: GlobalError) => GlobalError & TypedAction + : (props: { vehicleTechRecord: TechRecordType<'get'> }) => { + vehicleTechRecord: TechRecordType<'get'>; + } & TypedAction +> { + const suffix = isSuccess ? 'Success' : 'Failure'; + const type = `${prefix} ${title} ${suffix}`; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const actionCreator: ActionCreatorProps = isSuccess + ? props<{ vehicleTechRecord: TechRecordType<'get'>[] }>() + : props(); + + return createAction(type, actionCreator); } diff --git a/src/app/store/technical-records/effects/technical-record-service.effects.spec.ts b/src/app/store/technical-records/effects/technical-record-service.effects.spec.ts index 5dfc9f7ced..5a320064f9 100644 --- a/src/app/store/technical-records/effects/technical-record-service.effects.spec.ts +++ b/src/app/store/technical-records/effects/technical-record-service.effects.spec.ts @@ -1,6 +1,6 @@ import { HttpErrorResponse } from '@angular/common/http'; import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { fakeAsync, flush, TestBed } from '@angular/core/testing'; +import { TestBed, fakeAsync, flush } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; import { V3TechRecordModel, VehicleTypes } from '@models/vehicle-tech-record.model'; @@ -10,389 +10,419 @@ import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { TechnicalRecordHttpService } from '@services/technical-record-http/technical-record-http.service'; import { TechnicalRecordService } from '@services/technical-record/technical-record.service'; import { UserService } from '@services/user-service/user-service'; -import { initialAppState, State } from '@store/index'; +import { State, initialAppState } from '@store/index'; import { Observable, of } from 'rxjs'; import { TestScheduler } from 'rxjs/testing'; import { - archiveTechRecord, - archiveTechRecordFailure, - archiveTechRecordSuccess, - changeVehicleType, - createVehicleRecord, - createVehicleRecordFailure, - createVehicleRecordSuccess, - unarchiveTechRecord, - unarchiveTechRecordFailure, - unarchiveTechRecordSuccess, - updateTechRecord, - updateTechRecordFailure, - updateTechRecordSuccess, + archiveTechRecord, + archiveTechRecordFailure, + archiveTechRecordSuccess, + changeVehicleType, + createVehicleRecord, + createVehicleRecordFailure, + createVehicleRecordSuccess, + unarchiveTechRecord, + unarchiveTechRecordFailure, + unarchiveTechRecordSuccess, + updateTechRecord, + updateTechRecordFailure, + updateTechRecordSuccess, } from '../actions/technical-record-service.actions'; import { editingTechRecord } from '../selectors/technical-record-service.selectors'; import { TechnicalRecordServiceEffects } from './technical-record-service.effects'; describe('TechnicalRecordServiceEffects', () => { - let actions$ = new Observable(); - let effects: TechnicalRecordServiceEffects; - let store: MockStore; - let techRecordHttpService: TechnicalRecordHttpService; - let testScheduler: TestScheduler; - let technicalRecordService: TechnicalRecordService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, RouterTestingModule], - providers: [ - TechnicalRecordServiceEffects, - provideMockActions(() => actions$), - provideMockStore({ initialState: initialAppState }), - { provide: UserService, useValue: { name$: of('name'), id$: of('iod') } }, - { provide: TechnicalRecordService, useValue: { updateEditingTechRecord: jest.fn() } }, - ], - }); - effects = TestBed.inject(TechnicalRecordServiceEffects); - techRecordHttpService = TestBed.inject(TechnicalRecordHttpService); - technicalRecordService = TestBed.inject(TechnicalRecordService); - - }); - - beforeEach(() => { - testScheduler = new TestScheduler((actual, expected) => expect(actual).toEqual(expected)); - }); - - describe('createVehicleRecord', () => { - it('should return a vehicle on successful API call', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const mockVehicle = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' }; - const expectedVehicle = { - ...mockVehicle, - } as TechRecordType<'get'>; - - // mock action to trigger effect - actions$ = hot('-a--', { - a: createVehicleRecord({ vehicle: { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as unknown as TechRecordType<'put'> }), - }); - - // mock service call - jest.spyOn(techRecordHttpService, 'createVehicleRecord$').mockReturnValue(cold('--a|', { a: expectedVehicle })); - - // expect effect to return success action - expectObservable(effects.createVehicleRecord$).toBe('---b', { - b: createVehicleRecordSuccess({ vehicleTechRecord: expectedVehicle }), - }); - }); - }); - - it('should return an error message if not created', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - // mock action to trigger effect - actions$ = hot('-a--', { - a: createVehicleRecord({ vehicle: { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as unknown as TechRecordType<'put'> }), - }); - - // mock service call - const expectedError = new HttpErrorResponse({ status: 500, statusText: 'Internal server error' }); - - jest.spyOn(techRecordHttpService, 'createVehicleRecord$').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.createVehicleRecord$).toBe('---b', { - b: createVehicleRecordFailure({ error: 'Unable to create vehicle with VIN testVin' }), - }); - }); - }); - }); - - describe('updateTechRecords$', () => { - beforeEach(() => { - store = TestBed.inject(MockStore); - store.overrideSelector(editingTechRecord, {} as unknown as TechRecordType<'put'>); - }); - it('should return a technical record on successful API call', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const technicalRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>; - - // mock action to trigger effect - actions$ = hot('-a--', { a: updateTechRecord }); - - // mock service call - jest.spyOn(techRecordHttpService, 'updateTechRecords$').mockReturnValue(cold('--a|', { a: technicalRecord })); - - // expect effect to return success action - expectObservable(effects.updateTechRecord$).toBe('---b', { - b: updateTechRecordSuccess({ vehicleTechRecord: technicalRecord }), - }); - }); - }); - - it('should return an error message if not updated', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - // mock action to trigger effect - actions$ = hot('-a--', { a: updateTechRecord }); - - // mock service call - const expectedError = new HttpErrorResponse({ status: 500, statusText: 'Internal server error' }); - jest.spyOn(techRecordHttpService, 'updateTechRecords$').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.updateTechRecord$).toBe('---b', { - b: updateTechRecordFailure({ - error: 'Unable to update technical record null', - }), - }); - }); - }); - }); - - describe('archiveTechRecord', () => { - it('should return an archived technical record on successful API call', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const technicalRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>; - - // mock action to trigger effect - actions$ = hot('-a--', { a: archiveTechRecord }); - - // mock service call - jest.spyOn(techRecordHttpService, 'archiveTechnicalRecord$').mockReturnValue(cold('--a|', { a: technicalRecord })); - - // expect effect to return success action - expectObservable(effects.archiveTechRecord$).toBe('---b', { - b: archiveTechRecordSuccess({ vehicleTechRecord: technicalRecord }), - }); - }); - }); - - it.each([ - [500, 'Internal server error'], - [400, 'You are not allowed to update an archived tech-record'], - ])('should return an error message if not found', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - // mock action to trigger effect - actions$ = hot('-a--', { a: archiveTechRecord }); - - // mock service call - const expectedError = new HttpErrorResponse({ status: 500, statusText: 'Internal server error' }); - jest.spyOn(techRecordHttpService, 'archiveTechnicalRecord$').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.archiveTechRecord$).toBe('---b', { - b: archiveTechRecordFailure({ - error: 'Unable to archive technical record null', - }), - }); - }); - }); - }); - - describe('unarchiveTechRecord', () => { - it('should return an unarchived technical record on successful API call', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const technicalRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>; - - // mock action to trigger effect - actions$ = hot('-a--', { a: unarchiveTechRecord }); - - // mock service call - jest.spyOn(techRecordHttpService, 'unarchiveTechnicalRecord$').mockReturnValue(cold('--a|', { a: technicalRecord })); - - // expect effect to return success action - expectObservable(effects.unarchiveTechRecord$).toBe('---b', { - b: unarchiveTechRecordSuccess({ vehicleTechRecord: technicalRecord }), - }); - }); - }); - - it('should return an error message if not there is a non-archived record with the same VRM', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - // mock action to trigger effect - actions$ = hot('-a--', { a: unarchiveTechRecord }); - - // mock service call - const expectedError = new HttpErrorResponse({ status: 400, statusText: 'Cannot archive a record with unarchived records' }); - jest.spyOn(techRecordHttpService, 'unarchiveTechnicalRecord$').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.unarchiveTechRecord$).toBe('---b', { - b: unarchiveTechRecordFailure({ - error: 'Unable to unarchive technical record null', - }), - }); - }); - }); - - it('should return an error message if there was an internal server error', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - // mock action to trigger effect - actions$ = hot('-a--', { a: unarchiveTechRecord }); - - // mock service call - const expectedError = new HttpErrorResponse({ status: 500, statusText: 'Failed to unarchive record' }); - jest.spyOn(techRecordHttpService, 'unarchiveTechnicalRecord$').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.unarchiveTechRecord$).toBe('---b', { - b: unarchiveTechRecordFailure({ - error: 'Unable to unarchive technical record null', - }), - }); - }); - }); - }); - - describe('generateTechRecordBasedOnSectionTemplates', () => { - beforeEach(() => { - store = TestBed.inject(MockStore); - store.resetSelectors(); - jest.resetModules(); - }); - - it('should generate new techRecord based on vehicle type', fakeAsync(() => { - const techRecordServiceSpy = jest.spyOn(technicalRecordService, 'updateEditingTechRecord'); - const expectedTechRecord = getEmptyTechRecord(); - - testScheduler.run(({ hot, expectObservable }) => { - store.overrideSelector(editingTechRecord, { - vin: 'foo', - primaryVrm: 'bar', - systemNumber: 'foobar', - createdTimestamp: 'barfoo', - techRecord_vehicleType: 'lgv', - } as unknown as TechRecordType<'put'>); - // mock action to trigger effect - actions$ = hot('-a--', { - a: changeVehicleType({ - techRecord_vehicleType: VehicleTypes.CAR, - }), - }); - - expectObservable(effects.generateTechRecordBasedOnSectionTemplatesAfterVehicleTypeChange$).toBe('-b', { - b: expectedTechRecord, - }); - }); - - flush(); - expect(techRecordServiceSpy).toHaveBeenCalledTimes(1); - expect(techRecordServiceSpy).toHaveBeenCalledWith(expectedTechRecord); - })); - it('should default to heavy goods vehicle class when vehicle type is changed to hgv', fakeAsync(() => { - const techRecordServiceSpy = jest.spyOn(technicalRecordService, 'updateEditingTechRecord'); - const expectedTechRecord = getEmptyHGVRecord(); - testScheduler.run(({ hot, expectObservable }) => { - store.overrideSelector(editingTechRecord, { - vin: 'foo', - primaryVrm: 'bar', - systemNumber: 'foobar', - createdTimestamp: 'barfoo', - techRecord_vehicleType: 'lgv', - } as unknown as TechRecordType<'put'>); - // mock action to trigger effect - actions$ = hot('-a--', { - a: changeVehicleType({ - techRecord_vehicleType: VehicleTypes.HGV, - }), - }); - - expectObservable(effects.generateTechRecordBasedOnSectionTemplatesAfterVehicleTypeChange$).toBe('-b', { - b: expectedTechRecord, - }); - }); - - flush(); - expect(techRecordServiceSpy).toHaveBeenCalledTimes(1); - expect(techRecordServiceSpy).toHaveBeenCalledWith(expectedTechRecord); - })); - }); + let actions$ = new Observable(); + let effects: TechnicalRecordServiceEffects; + let store: MockStore; + let techRecordHttpService: TechnicalRecordHttpService; + let testScheduler: TestScheduler; + let technicalRecordService: TechnicalRecordService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule, RouterTestingModule], + providers: [ + TechnicalRecordServiceEffects, + provideMockActions(() => actions$), + provideMockStore({ initialState: initialAppState }), + { provide: UserService, useValue: { name$: of('name'), id$: of('iod') } }, + { provide: TechnicalRecordService, useValue: { updateEditingTechRecord: jest.fn() } }, + ], + }); + effects = TestBed.inject(TechnicalRecordServiceEffects); + techRecordHttpService = TestBed.inject(TechnicalRecordHttpService); + technicalRecordService = TestBed.inject(TechnicalRecordService); + }); + + beforeEach(() => { + testScheduler = new TestScheduler((actual, expected) => expect(actual).toEqual(expected)); + }); + + describe('createVehicleRecord', () => { + it('should return a vehicle on successful API call', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const mockVehicle = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' }; + const expectedVehicle = { + ...mockVehicle, + } as TechRecordType<'get'>; + + // mock action to trigger effect + actions$ = hot('-a--', { + a: createVehicleRecord({ + vehicle: { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + } as unknown as TechRecordType<'put'>, + }), + }); + + // mock service call + jest.spyOn(techRecordHttpService, 'createVehicleRecord$').mockReturnValue(cold('--a|', { a: expectedVehicle })); + + // expect effect to return success action + expectObservable(effects.createVehicleRecord$).toBe('---b', { + b: createVehicleRecordSuccess({ vehicleTechRecord: expectedVehicle }), + }); + }); + }); + + it('should return an error message if not created', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + // mock action to trigger effect + actions$ = hot('-a--', { + a: createVehicleRecord({ + vehicle: { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + } as unknown as TechRecordType<'put'>, + }), + }); + + // mock service call + const expectedError = new HttpErrorResponse({ status: 500, statusText: 'Internal server error' }); + + jest.spyOn(techRecordHttpService, 'createVehicleRecord$').mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.createVehicleRecord$).toBe('---b', { + b: createVehicleRecordFailure({ error: 'Unable to create vehicle with VIN testVin' }), + }); + }); + }); + }); + + describe('updateTechRecords$', () => { + beforeEach(() => { + store = TestBed.inject(MockStore); + store.overrideSelector(editingTechRecord, {} as unknown as TechRecordType<'put'>); + }); + it('should return a technical record on successful API call', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const technicalRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + } as TechRecordType<'get'>; + + // mock action to trigger effect + actions$ = hot('-a--', { a: updateTechRecord }); + + // mock service call + jest.spyOn(techRecordHttpService, 'updateTechRecords$').mockReturnValue(cold('--a|', { a: technicalRecord })); + + // expect effect to return success action + expectObservable(effects.updateTechRecord$).toBe('---b', { + b: updateTechRecordSuccess({ vehicleTechRecord: technicalRecord }), + }); + }); + }); + + it('should return an error message if not updated', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + // mock action to trigger effect + actions$ = hot('-a--', { a: updateTechRecord }); + + // mock service call + const expectedError = new HttpErrorResponse({ status: 500, statusText: 'Internal server error' }); + jest.spyOn(techRecordHttpService, 'updateTechRecords$').mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.updateTechRecord$).toBe('---b', { + b: updateTechRecordFailure({ + error: 'Unable to update technical record null', + }), + }); + }); + }); + }); + + describe('archiveTechRecord', () => { + it('should return an archived technical record on successful API call', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const technicalRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + } as TechRecordType<'get'>; + + // mock action to trigger effect + actions$ = hot('-a--', { a: archiveTechRecord }); + + // mock service call + jest + .spyOn(techRecordHttpService, 'archiveTechnicalRecord$') + .mockReturnValue(cold('--a|', { a: technicalRecord })); + + // expect effect to return success action + expectObservable(effects.archiveTechRecord$).toBe('---b', { + b: archiveTechRecordSuccess({ vehicleTechRecord: technicalRecord }), + }); + }); + }); + + it.each([ + [500, 'Internal server error'], + [400, 'You are not allowed to update an archived tech-record'], + ])('should return an error message if not found', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + // mock action to trigger effect + actions$ = hot('-a--', { a: archiveTechRecord }); + + // mock service call + const expectedError = new HttpErrorResponse({ status: 500, statusText: 'Internal server error' }); + jest.spyOn(techRecordHttpService, 'archiveTechnicalRecord$').mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.archiveTechRecord$).toBe('---b', { + b: archiveTechRecordFailure({ + error: 'Unable to archive technical record null', + }), + }); + }); + }); + }); + + describe('unarchiveTechRecord', () => { + it('should return an unarchived technical record on successful API call', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const technicalRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + } as TechRecordType<'get'>; + + // mock action to trigger effect + actions$ = hot('-a--', { a: unarchiveTechRecord }); + + // mock service call + jest + .spyOn(techRecordHttpService, 'unarchiveTechnicalRecord$') + .mockReturnValue(cold('--a|', { a: technicalRecord })); + + // expect effect to return success action + expectObservable(effects.unarchiveTechRecord$).toBe('---b', { + b: unarchiveTechRecordSuccess({ vehicleTechRecord: technicalRecord }), + }); + }); + }); + + it('should return an error message if not there is a non-archived record with the same VRM', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + // mock action to trigger effect + actions$ = hot('-a--', { a: unarchiveTechRecord }); + + // mock service call + const expectedError = new HttpErrorResponse({ + status: 400, + statusText: 'Cannot archive a record with unarchived records', + }); + jest.spyOn(techRecordHttpService, 'unarchiveTechnicalRecord$').mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.unarchiveTechRecord$).toBe('---b', { + b: unarchiveTechRecordFailure({ + error: 'Unable to unarchive technical record null', + }), + }); + }); + }); + + it('should return an error message if there was an internal server error', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + // mock action to trigger effect + actions$ = hot('-a--', { a: unarchiveTechRecord }); + + // mock service call + const expectedError = new HttpErrorResponse({ status: 500, statusText: 'Failed to unarchive record' }); + jest.spyOn(techRecordHttpService, 'unarchiveTechnicalRecord$').mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.unarchiveTechRecord$).toBe('---b', { + b: unarchiveTechRecordFailure({ + error: 'Unable to unarchive technical record null', + }), + }); + }); + }); + }); + + describe('generateTechRecordBasedOnSectionTemplates', () => { + beforeEach(() => { + store = TestBed.inject(MockStore); + store.resetSelectors(); + jest.resetModules(); + }); + + it('should generate new techRecord based on vehicle type', fakeAsync(() => { + const techRecordServiceSpy = jest.spyOn(technicalRecordService, 'updateEditingTechRecord'); + const expectedTechRecord = getEmptyTechRecord(); + + testScheduler.run(({ hot, expectObservable }) => { + store.overrideSelector(editingTechRecord, { + vin: 'foo', + primaryVrm: 'bar', + systemNumber: 'foobar', + createdTimestamp: 'barfoo', + techRecord_vehicleType: 'lgv', + } as unknown as TechRecordType<'put'>); + // mock action to trigger effect + actions$ = hot('-a--', { + a: changeVehicleType({ + techRecord_vehicleType: VehicleTypes.CAR, + }), + }); + + expectObservable(effects.generateTechRecordBasedOnSectionTemplatesAfterVehicleTypeChange$).toBe('-b', { + b: expectedTechRecord, + }); + }); + + flush(); + expect(techRecordServiceSpy).toHaveBeenCalledTimes(1); + expect(techRecordServiceSpy).toHaveBeenCalledWith(expectedTechRecord); + })); + it('should default to heavy goods vehicle class when vehicle type is changed to hgv', fakeAsync(() => { + const techRecordServiceSpy = jest.spyOn(technicalRecordService, 'updateEditingTechRecord'); + const expectedTechRecord = getEmptyHGVRecord(); + testScheduler.run(({ hot, expectObservable }) => { + store.overrideSelector(editingTechRecord, { + vin: 'foo', + primaryVrm: 'bar', + systemNumber: 'foobar', + createdTimestamp: 'barfoo', + techRecord_vehicleType: 'lgv', + } as unknown as TechRecordType<'put'>); + // mock action to trigger effect + actions$ = hot('-a--', { + a: changeVehicleType({ + techRecord_vehicleType: VehicleTypes.HGV, + }), + }); + + expectObservable(effects.generateTechRecordBasedOnSectionTemplatesAfterVehicleTypeChange$).toBe('-b', { + b: expectedTechRecord, + }); + }); + + flush(); + expect(techRecordServiceSpy).toHaveBeenCalledTimes(1); + expect(techRecordServiceSpy).toHaveBeenCalledWith(expectedTechRecord); + })); + }); }); function getEmptyTechRecord(): V3TechRecordModel { - return { - techRecord_createdAt: '', - techRecord_createdById: null, - techRecord_createdByName: null, - techRecord_euVehicleCategory: null, - techRecord_lastUpdatedAt: null, - techRecord_lastUpdatedById: null, - techRecord_lastUpdatedByName: null, - techRecord_manufactureYear: null, - techRecord_noOfAxles: 2, - techRecord_notes: undefined, - techRecord_applicantDetails_address1: null, - techRecord_applicantDetails_address2: null, - techRecord_applicantDetails_address3: null, - techRecord_applicantDetails_emailAddress: null, - techRecord_applicantDetails_name: null, - techRecord_applicantDetails_postCode: null, - techRecord_applicantDetails_postTown: null, - techRecord_applicantDetails_telephoneNumber: null, - techRecord_reasonForCreation: '', - techRecord_regnDate: null, - techRecord_statusCode: '', - techRecord_vehicleConfiguration: 'other', - techRecord_vehicleSubclass: undefined, - techRecord_vehicleType: 'car', - } as unknown as V3TechRecordModel; + return { + techRecord_createdAt: '', + techRecord_createdById: null, + techRecord_createdByName: null, + techRecord_euVehicleCategory: null, + techRecord_lastUpdatedAt: null, + techRecord_lastUpdatedById: null, + techRecord_lastUpdatedByName: null, + techRecord_manufactureYear: null, + techRecord_noOfAxles: 2, + techRecord_notes: undefined, + techRecord_applicantDetails_address1: null, + techRecord_applicantDetails_address2: null, + techRecord_applicantDetails_address3: null, + techRecord_applicantDetails_emailAddress: null, + techRecord_applicantDetails_name: null, + techRecord_applicantDetails_postCode: null, + techRecord_applicantDetails_postTown: null, + techRecord_applicantDetails_telephoneNumber: null, + techRecord_reasonForCreation: '', + techRecord_regnDate: null, + techRecord_statusCode: '', + techRecord_vehicleConfiguration: 'other', + techRecord_vehicleSubclass: undefined, + techRecord_vehicleType: 'car', + } as unknown as V3TechRecordModel; } function getEmptyHGVRecord(): V3TechRecordModel { - return { - techRecord_adrDetails_dangerousGoods: false, - techRecord_alterationMarker: null, - techRecord_applicantDetails_address1: null, - techRecord_applicantDetails_address2: null, - techRecord_applicantDetails_address3: null, - techRecord_applicantDetails_emailAddress: null, - techRecord_applicantDetails_name: null, - techRecord_applicantDetails_postCode: null, - techRecord_applicantDetails_postTown: null, - techRecord_applicantDetails_telephoneNumber: null, - techRecord_approvalType: null, - techRecord_axles: [], - techRecord_approvalTypeNumber: undefined, - techRecord_bodyType_code: null, - techRecord_bodyType_description: null, - techRecord_brakes_dtpNumber: null, - techRecord_conversionRefNo: null, - techRecord_departmentalVehicleMarker: null, - techRecord_dimensions_axleSpacing: [], - techRecord_dimensions_length: null, - techRecord_dimensions_width: null, - techRecord_drawbarCouplingFitted: null, - techRecord_emissionsLimit: null, - techRecord_euVehicleCategory: null, - techRecord_euroStandard: undefined, - techRecord_frontAxleTo5thWheelMax: null, - techRecord_frontAxleTo5thWheelMin: null, - techRecord_frontAxleToRearAxle: null, - techRecord_frontVehicleTo5thWheelCouplingMax: null, - techRecord_frontVehicleTo5thWheelCouplingMin: null, - techRecord_fuelPropulsionSystem: null, - techRecord_functionCode: null, - techRecord_grossDesignWeight: null, - techRecord_grossEecWeight: null, - techRecord_grossGbWeight: null, - techRecord_make: null, - techRecord_manufactureYear: null, - techRecord_maxTrainDesignWeight: null, - techRecord_maxTrainEecWeight: null, - techRecord_maxTrainGbWeight: null, - techRecord_microfilm_microfilmDocumentType: undefined, - techRecord_microfilm_microfilmRollNumber: undefined, - techRecord_microfilm_microfilmSerialNumber: undefined, - techRecord_model: null, - techRecord_noOfAxles: null, - techRecord_notes: undefined, - techRecord_ntaNumber: undefined, - techRecord_numberOfWheelsDriven: null, - techRecord_offRoad: null, - techRecord_plates: [], - techRecord_reasonForCreation: undefined, - techRecord_regnDate: null, - techRecord_roadFriendly: null, - techRecord_speedLimiterMrk: null, - techRecord_statusCode: '', - techRecord_tachoExemptMrk: null, - techRecord_trainDesignWeight: null, - techRecord_trainEecWeight: null, - techRecord_trainGbWeight: null, - techRecord_tyreUseCode: null, - techRecord_variantNumber: undefined, - techRecord_variantVersionNumber: undefined, - techRecord_vehicleClass_description: 'heavy goods vehicle', - techRecord_vehicleConfiguration: null, - techRecord_vehicleType: 'hgv', - } as unknown as V3TechRecordModel; + return { + techRecord_adrDetails_dangerousGoods: false, + techRecord_alterationMarker: null, + techRecord_applicantDetails_address1: null, + techRecord_applicantDetails_address2: null, + techRecord_applicantDetails_address3: null, + techRecord_applicantDetails_emailAddress: null, + techRecord_applicantDetails_name: null, + techRecord_applicantDetails_postCode: null, + techRecord_applicantDetails_postTown: null, + techRecord_applicantDetails_telephoneNumber: null, + techRecord_approvalType: null, + techRecord_axles: [], + techRecord_approvalTypeNumber: undefined, + techRecord_bodyType_code: null, + techRecord_bodyType_description: null, + techRecord_brakes_dtpNumber: null, + techRecord_conversionRefNo: null, + techRecord_departmentalVehicleMarker: null, + techRecord_dimensions_axleSpacing: [], + techRecord_dimensions_length: null, + techRecord_dimensions_width: null, + techRecord_drawbarCouplingFitted: null, + techRecord_emissionsLimit: null, + techRecord_euVehicleCategory: null, + techRecord_euroStandard: undefined, + techRecord_frontAxleTo5thWheelMax: null, + techRecord_frontAxleTo5thWheelMin: null, + techRecord_frontAxleToRearAxle: null, + techRecord_frontVehicleTo5thWheelCouplingMax: null, + techRecord_frontVehicleTo5thWheelCouplingMin: null, + techRecord_fuelPropulsionSystem: null, + techRecord_functionCode: null, + techRecord_grossDesignWeight: null, + techRecord_grossEecWeight: null, + techRecord_grossGbWeight: null, + techRecord_make: null, + techRecord_manufactureYear: null, + techRecord_maxTrainDesignWeight: null, + techRecord_maxTrainEecWeight: null, + techRecord_maxTrainGbWeight: null, + techRecord_microfilm_microfilmDocumentType: undefined, + techRecord_microfilm_microfilmRollNumber: undefined, + techRecord_microfilm_microfilmSerialNumber: undefined, + techRecord_model: null, + techRecord_noOfAxles: null, + techRecord_notes: undefined, + techRecord_ntaNumber: undefined, + techRecord_numberOfWheelsDriven: null, + techRecord_offRoad: null, + techRecord_plates: [], + techRecord_reasonForCreation: undefined, + techRecord_regnDate: null, + techRecord_roadFriendly: null, + techRecord_speedLimiterMrk: null, + techRecord_statusCode: '', + techRecord_tachoExemptMrk: null, + techRecord_trainDesignWeight: null, + techRecord_trainEecWeight: null, + techRecord_trainGbWeight: null, + techRecord_tyreUseCode: null, + techRecord_variantNumber: undefined, + techRecord_variantVersionNumber: undefined, + techRecord_vehicleClass_description: 'heavy goods vehicle', + techRecord_vehicleConfiguration: null, + techRecord_vehicleType: 'hgv', + } as unknown as V3TechRecordModel; } diff --git a/src/app/store/technical-records/effects/technical-record-service.effects.ts b/src/app/store/technical-records/effects/technical-record-service.effects.ts index eb6bea5f9e..f523055916 100644 --- a/src/app/store/technical-records/effects/technical-record-service.effects.ts +++ b/src/app/store/technical-records/effects/technical-record-service.effects.ts @@ -2,7 +2,11 @@ import { Injectable } from '@angular/core'; import { EUVehicleCategory } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/euVehicleCategory.enum.js'; import { VehicleClassDescription } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleClassDescription.enum.js'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; -import { TechRecordGETHGV, TechRecordGETPSV, TechRecordGETTRL } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb-vehicle-type'; +import { + TechRecordGETHGV, + TechRecordGETPSV, + TechRecordGETTRL, +} from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb-vehicle-type'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; import { vehicleTemplateMap } from '@forms/utils/tech-record-constants'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; @@ -14,316 +18,366 @@ import { TechnicalRecordService } from '@services/technical-record/technical-rec import { UserService } from '@services/user-service/user-service'; import { State } from '@store/index'; import { cloneDeep, merge } from 'lodash'; +import { catchError, concatMap, map, mergeMap, of, switchMap, tap, withLatestFrom } from 'rxjs'; import { - catchError, concatMap, - map, mergeMap, of, switchMap, tap, - withLatestFrom, -} from 'rxjs'; -import { - amendVin, - amendVinSuccess, - amendVrm, - amendVrmFailure, - amendVrmSuccess, - archiveTechRecord, - archiveTechRecordFailure, - archiveTechRecordSuccess, - changeVehicleType, - createVehicle, - createVehicleRecord, - createVehicleRecordFailure, - createVehicleRecordSuccess, - generateADRCertificate, - generateADRCertificateFailure, - generateADRCertificateSuccess, - generateLetter, - generateLetterFailure, - generateLetterSuccess, - generatePlate, - generatePlateFailure, - generatePlateSuccess, - getBySystemNumber, - getBySystemNumberFailure, - getBySystemNumberSuccess, - getTechRecordV3, - getTechRecordV3Failure, - getTechRecordV3Success, - promoteTechRecord, - promoteTechRecordFailure, - promoteTechRecordSuccess, - unarchiveTechRecord, - unarchiveTechRecordFailure, - unarchiveTechRecordSuccess, - updateTechRecord, - updateTechRecordFailure, - updateTechRecordSuccess, + amendVin, + amendVinSuccess, + amendVrm, + amendVrmFailure, + amendVrmSuccess, + archiveTechRecord, + archiveTechRecordFailure, + archiveTechRecordSuccess, + changeVehicleType, + createVehicle, + createVehicleRecord, + createVehicleRecordFailure, + createVehicleRecordSuccess, + generateADRCertificate, + generateADRCertificateFailure, + generateADRCertificateSuccess, + generateLetter, + generateLetterFailure, + generateLetterSuccess, + generatePlate, + generatePlateFailure, + generatePlateSuccess, + getBySystemNumber, + getBySystemNumberFailure, + getBySystemNumberSuccess, + getTechRecordV3, + getTechRecordV3Failure, + getTechRecordV3Success, + promoteTechRecord, + promoteTechRecordFailure, + promoteTechRecordSuccess, + unarchiveTechRecord, + unarchiveTechRecordFailure, + unarchiveTechRecordSuccess, + updateTechRecord, + updateTechRecordFailure, + updateTechRecordSuccess, } from '../actions/technical-record-service.actions'; import { editingTechRecord, selectTechRecord } from '../selectors/technical-record-service.selectors'; @Injectable() export class TechnicalRecordServiceEffects { - constructor( - private actions$: Actions, - private techRecordHttpService: TechnicalRecordHttpService, - private technicalRecordService: TechnicalRecordService, - private batchTechRecordService: BatchTechnicalRecordService, - private userService: UserService, - private store: Store, - private dfs: DynamicFormService, - ) { } - - getTechnicalRecordHistory$ = createEffect(() => - this.actions$.pipe( - ofType(getBySystemNumber), - mergeMap((action) => { - const anchorLink = 'search-term'; + constructor( + private actions$: Actions, + private techRecordHttpService: TechnicalRecordHttpService, + private technicalRecordService: TechnicalRecordService, + private batchTechRecordService: BatchTechnicalRecordService, + private userService: UserService, + private store: Store, + private dfs: DynamicFormService + ) {} - return this.techRecordHttpService.getBySystemNumber$(action.systemNumber).pipe( - map((vehicleTechRecords) => { - return getBySystemNumberSuccess({ techRecordHistory: vehicleTechRecords }); - }), - catchError(() => of(getBySystemNumberFailure({ error: 'could not find technical record history', anchorLink }))), - ); - }), - )); + getTechnicalRecordHistory$ = createEffect(() => + this.actions$.pipe( + ofType(getBySystemNumber), + mergeMap((action) => { + const anchorLink = 'search-term'; - getTechRecordV3$ = createEffect(() => - this.actions$.pipe( - ofType(getTechRecordV3), - mergeMap((action) => { - const anchorLink = 'search-term'; + return this.techRecordHttpService.getBySystemNumber$(action.systemNumber).pipe( + map((vehicleTechRecords) => { + return getBySystemNumberSuccess({ techRecordHistory: vehicleTechRecords }); + }), + catchError(() => + of(getBySystemNumberFailure({ error: 'could not find technical record history', anchorLink })) + ) + ); + }) + ) + ); - return this.techRecordHttpService.getRecordV3$(action.systemNumber, action.createdTimestamp).pipe( - map((vehicleTechRecord) => { - return getTechRecordV3Success({ vehicleTechRecord }); - }), - catchError((error) => - of(getTechRecordV3Failure({ error: this.getTechRecordErrorMessage(error, 'getTechnicalRecords', 'systemNumber'), anchorLink }))), - ); - }), - )); + getTechRecordV3$ = createEffect(() => + this.actions$.pipe( + ofType(getTechRecordV3), + mergeMap((action) => { + const anchorLink = 'search-term'; - createVehicleRecord$ = createEffect(() => - this.actions$.pipe( - ofType(createVehicleRecord), - withLatestFrom(this.batchTechRecordService.applicationId$, this.userService.name$, this.userService.id$), - concatMap(([{ vehicle }, applicationId]) => { - const vehicleRecord = { ...vehicle, techRecord_applicationId: applicationId }; + return this.techRecordHttpService.getRecordV3$(action.systemNumber, action.createdTimestamp).pipe( + map((vehicleTechRecord) => { + return getTechRecordV3Success({ vehicleTechRecord }); + }), + catchError((error) => + of( + getTechRecordV3Failure({ + error: this.getTechRecordErrorMessage(error, 'getTechnicalRecords', 'systemNumber'), + anchorLink, + }) + ) + ) + ); + }) + ) + ); - return this.techRecordHttpService.createVehicleRecord$(vehicleRecord).pipe( - map((response) => createVehicleRecordSuccess({ vehicleTechRecord: response })), - catchError((error) => - of( - createVehicleRecordFailure({ - error: `Unable to create vehicle with VIN ${vehicle.vin}${error.error?.errors - ? ` because:${(error.error.errors?.map((e: string) => `\n${e}`) as string[]).join()}` - : '' - }`, - }), - )), - ); - }), - )); + createVehicleRecord$ = createEffect(() => + this.actions$.pipe( + ofType(createVehicleRecord), + withLatestFrom(this.batchTechRecordService.applicationId$, this.userService.name$, this.userService.id$), + concatMap(([{ vehicle }, applicationId]) => { + const vehicleRecord = { ...vehicle, techRecord_applicationId: applicationId }; - updateTechRecord$ = createEffect(() => - this.actions$.pipe( - ofType(updateTechRecord), - withLatestFrom(this.store.pipe(select(editingTechRecord))), - concatMap(([{ systemNumber, createdTimestamp }, techRecord]) => { - if (!techRecord) { - return of(updateTechRecordFailure({ error: 'There is not technical record in edit' })); - } - return this.techRecordHttpService.updateTechRecords$(systemNumber, createdTimestamp, techRecord).pipe( - map((vehicleTechRecord) => updateTechRecordSuccess({ vehicleTechRecord })), - catchError((error) => of(updateTechRecordFailure({ error: this.getTechRecordErrorMessage(error, 'updateTechnicalRecord') }))), - ); - }), - )); + return this.techRecordHttpService.createVehicleRecord$(vehicleRecord).pipe( + map((response) => createVehicleRecordSuccess({ vehicleTechRecord: response })), + catchError((error) => + of( + createVehicleRecordFailure({ + error: `Unable to create vehicle with VIN ${vehicle.vin}${ + error.error?.errors + ? ` because:${(error.error.errors?.map((e: string) => `\n${e}`) as string[]).join()}` + : '' + }`, + }) + ) + ) + ); + }) + ) + ); - amendVrm$ = createEffect(() => - this.actions$.pipe( - ofType(amendVrm), - switchMap(({ - newVrm, cherishedTransfer, systemNumber, createdTimestamp, thirdMark, - }) => { - return this.techRecordHttpService.amendVrm$(newVrm, cherishedTransfer, systemNumber, createdTimestamp, thirdMark).pipe( - map((vehicleTechRecord) => amendVrmSuccess({ vehicleTechRecord })), - catchError((error) => of(amendVrmFailure({ error: this.getTechRecordErrorMessage(error, 'updateTechnicalRecord') }))), - ); - }), - )); + updateTechRecord$ = createEffect(() => + this.actions$.pipe( + ofType(updateTechRecord), + withLatestFrom(this.store.pipe(select(editingTechRecord))), + concatMap(([{ systemNumber, createdTimestamp }, techRecord]) => { + if (!techRecord) { + return of(updateTechRecordFailure({ error: 'There is not technical record in edit' })); + } + return this.techRecordHttpService.updateTechRecords$(systemNumber, createdTimestamp, techRecord).pipe( + map((vehicleTechRecord) => updateTechRecordSuccess({ vehicleTechRecord })), + catchError((error) => + of(updateTechRecordFailure({ error: this.getTechRecordErrorMessage(error, 'updateTechnicalRecord') })) + ) + ); + }) + ) + ); - amendVin$ = createEffect(() => - this.actions$.pipe( - ofType(amendVin), - switchMap(({ newVin, systemNumber, createdTimestamp }) => { - return this.techRecordHttpService.amendVin$(newVin, systemNumber, createdTimestamp).pipe( - map((vehicleTechRecord) => amendVinSuccess({ vehicleTechRecord })), - catchError((error) => of(amendVrmFailure({ error: this.getTechRecordErrorMessage(error, 'updateTechnicalRecord') }))), - ); - }), - )); + amendVrm$ = createEffect(() => + this.actions$.pipe( + ofType(amendVrm), + switchMap(({ newVrm, cherishedTransfer, systemNumber, createdTimestamp, thirdMark }) => { + return this.techRecordHttpService + .amendVrm$(newVrm, cherishedTransfer, systemNumber, createdTimestamp, thirdMark) + .pipe( + map((vehicleTechRecord) => amendVrmSuccess({ vehicleTechRecord })), + catchError((error) => + of(amendVrmFailure({ error: this.getTechRecordErrorMessage(error, 'updateTechnicalRecord') })) + ) + ); + }) + ) + ); - archiveTechRecord$ = createEffect(() => - this.actions$.pipe( - ofType(archiveTechRecord), - switchMap(({ systemNumber, createdTimestamp, reasonForArchiving }) => - this.techRecordHttpService.archiveTechnicalRecord$(systemNumber, createdTimestamp, reasonForArchiving).pipe( - map((vehicleTechRecord) => archiveTechRecordSuccess({ vehicleTechRecord })), - catchError((error) => of(archiveTechRecordFailure({ error: this.getTechRecordErrorMessage(error, 'archiveTechRecord') }))), - )), - )); + amendVin$ = createEffect(() => + this.actions$.pipe( + ofType(amendVin), + switchMap(({ newVin, systemNumber, createdTimestamp }) => { + return this.techRecordHttpService.amendVin$(newVin, systemNumber, createdTimestamp).pipe( + map((vehicleTechRecord) => amendVinSuccess({ vehicleTechRecord })), + catchError((error) => + of(amendVrmFailure({ error: this.getTechRecordErrorMessage(error, 'updateTechnicalRecord') })) + ) + ); + }) + ) + ); - promoteTechRecord$ = createEffect(() => - this.actions$.pipe( - ofType(promoteTechRecord), - switchMap(({ systemNumber, createdTimestamp, reasonForPromoting }) => - this.techRecordHttpService.promoteTechnicalRecord$(systemNumber, createdTimestamp, reasonForPromoting).pipe( - map((vehicleTechRecord) => promoteTechRecordSuccess({ vehicleTechRecord })), - catchError((error) => of(promoteTechRecordFailure({ error: this.getTechRecordErrorMessage(error, 'promoteTechRecord') }))), - )), - )); - generateTechRecordBasedOnSectionTemplates$ = createEffect( - () => - this.actions$.pipe( - ofType(createVehicle), - withLatestFrom(this.store.pipe(select(editingTechRecord))), - concatMap(([{ techRecord_vehicleType }, editableTechRecord]) => { - const techRecord = { ...cloneDeep(editableTechRecord), techRecord_vehicleType }; + archiveTechRecord$ = createEffect(() => + this.actions$.pipe( + ofType(archiveTechRecord), + switchMap(({ systemNumber, createdTimestamp, reasonForArchiving }) => + this.techRecordHttpService.archiveTechnicalRecord$(systemNumber, createdTimestamp, reasonForArchiving).pipe( + map((vehicleTechRecord) => archiveTechRecordSuccess({ vehicleTechRecord })), + catchError((error) => + of(archiveTechRecordFailure({ error: this.getTechRecordErrorMessage(error, 'archiveTechRecord') })) + ) + ) + ) + ) + ); - if (techRecord_vehicleType === VehicleTypes.SMALL_TRL) { - techRecord.techRecord_vehicleType = VehicleTypes.TRL; - (techRecord as TechRecordGETTRL).techRecord_euVehicleCategory = EUVehicleCategory.O1; - } - if (techRecord.techRecord_vehicleType === VehicleTypes.HGV || techRecord.techRecord_vehicleType === VehicleTypes.PSV) { - (techRecord as TechRecordGETHGV | TechRecordGETPSV).techRecord_vehicleConfiguration = null; - } - if (techRecord_vehicleType === VehicleTypes.HGV) { - (techRecord as TechRecordGETHGV).techRecord_vehicleClass_description = VehicleClassDescription.HeavyGoodsVehicle; - } - if (techRecord_vehicleType === VehicleTypes.TRL) { - (techRecord as TechRecordGETTRL).techRecord_vehicleClass_description = VehicleClassDescription.Trailer; - } - const techRecordTemplate = vehicleTemplateMap.get(techRecord_vehicleType) || []; + promoteTechRecord$ = createEffect(() => + this.actions$.pipe( + ofType(promoteTechRecord), + switchMap(({ systemNumber, createdTimestamp, reasonForPromoting }) => + this.techRecordHttpService.promoteTechnicalRecord$(systemNumber, createdTimestamp, reasonForPromoting).pipe( + map((vehicleTechRecord) => promoteTechRecordSuccess({ vehicleTechRecord })), + catchError((error) => + of(promoteTechRecordFailure({ error: this.getTechRecordErrorMessage(error, 'promoteTechRecord') })) + ) + ) + ) + ) + ); + generateTechRecordBasedOnSectionTemplates$ = createEffect( + () => + this.actions$.pipe( + ofType(createVehicle), + withLatestFrom(this.store.pipe(select(editingTechRecord))), + concatMap(([{ techRecord_vehicleType }, editableTechRecord]) => { + const techRecord = { ...cloneDeep(editableTechRecord), techRecord_vehicleType }; - return of( - techRecordTemplate.reduce((mergedNodes, formNode) => { - const form = this.dfs.createForm(formNode, techRecord); - return merge(mergedNodes, form.getCleanValue(form)); - }, {}) as TechRecordType<'put'>, - ); - }), - tap((mergedForms) => this.technicalRecordService.updateEditingTechRecord(mergedForms)), - ), - { dispatch: false }, - ); + if (techRecord_vehicleType === VehicleTypes.SMALL_TRL) { + techRecord.techRecord_vehicleType = VehicleTypes.TRL; + (techRecord as TechRecordGETTRL).techRecord_euVehicleCategory = EUVehicleCategory.O1; + } + if ( + techRecord.techRecord_vehicleType === VehicleTypes.HGV || + techRecord.techRecord_vehicleType === VehicleTypes.PSV + ) { + (techRecord as TechRecordGETHGV | TechRecordGETPSV).techRecord_vehicleConfiguration = null; + } + if (techRecord_vehicleType === VehicleTypes.HGV) { + (techRecord as TechRecordGETHGV).techRecord_vehicleClass_description = + VehicleClassDescription.HeavyGoodsVehicle; + } + if (techRecord_vehicleType === VehicleTypes.TRL) { + (techRecord as TechRecordGETTRL).techRecord_vehicleClass_description = VehicleClassDescription.Trailer; + } + const techRecordTemplate = vehicleTemplateMap.get(techRecord_vehicleType) || []; - generateTechRecordBasedOnSectionTemplatesAfterVehicleTypeChange$ = createEffect( - () => - this.actions$.pipe( - ofType(changeVehicleType), - withLatestFrom(this.store.pipe(select(editingTechRecord))), - concatMap(([{ techRecord_vehicleType }, editableTechRecord]) => { - const techRecord = { ...cloneDeep(editableTechRecord), techRecord_vehicleType }; + return of( + techRecordTemplate.reduce((mergedNodes, formNode) => { + const form = this.dfs.createForm(formNode, techRecord); + return merge(mergedNodes, form.getCleanValue(form)); + }, {}) as TechRecordType<'put'> + ); + }), + tap((mergedForms) => this.technicalRecordService.updateEditingTechRecord(mergedForms)) + ), + { dispatch: false } + ); - if (techRecord.techRecord_vehicleType === VehicleTypes.SMALL_TRL) { - techRecord.techRecord_vehicleType = VehicleTypes.TRL; - (techRecord as TechRecordGETTRL).techRecord_euVehicleCategory = EUVehicleCategory.O1; - } + generateTechRecordBasedOnSectionTemplatesAfterVehicleTypeChange$ = createEffect( + () => + this.actions$.pipe( + ofType(changeVehicleType), + withLatestFrom(this.store.pipe(select(editingTechRecord))), + concatMap(([{ techRecord_vehicleType }, editableTechRecord]) => { + const techRecord = { ...cloneDeep(editableTechRecord), techRecord_vehicleType }; - if (techRecord_vehicleType === VehicleTypes.HGV || techRecord_vehicleType === VehicleTypes.PSV) { - (techRecord as TechRecordGETHGV | TechRecordGETPSV).techRecord_approvalType = null; - (techRecord as TechRecordGETHGV | TechRecordGETPSV).techRecord_vehicleConfiguration = null; - } + if (techRecord.techRecord_vehicleType === VehicleTypes.SMALL_TRL) { + techRecord.techRecord_vehicleType = VehicleTypes.TRL; + (techRecord as TechRecordGETTRL).techRecord_euVehicleCategory = EUVehicleCategory.O1; + } - if (techRecord_vehicleType === VehicleTypes.HGV) { - (techRecord as TechRecordGETHGV).techRecord_vehicleClass_description = VehicleClassDescription.HeavyGoodsVehicle; - } - if (techRecord_vehicleType === VehicleTypes.TRL) { - (techRecord as TechRecordGETTRL).techRecord_vehicleClass_description = VehicleClassDescription.Trailer; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (techRecord as any).euVehicleCategory = null; - } + if (techRecord_vehicleType === VehicleTypes.HGV || techRecord_vehicleType === VehicleTypes.PSV) { + (techRecord as TechRecordGETHGV | TechRecordGETPSV).techRecord_approvalType = null; + (techRecord as TechRecordGETHGV | TechRecordGETPSV).techRecord_vehicleConfiguration = null; + } - const techRecordTemplate = vehicleTemplateMap.get(techRecord_vehicleType) || []; - return of( - techRecordTemplate.reduce((mergedNodes, formNode) => { - const form = this.dfs.createForm(formNode, techRecord); - return merge(mergedNodes, form.getCleanValue(form)); - }, {}) as TechRecordType<'put'>, - ); - }), - tap((mergedForms) => this.technicalRecordService.updateEditingTechRecord(mergedForms)), - ), - { dispatch: false }, - ); + if (techRecord_vehicleType === VehicleTypes.HGV) { + (techRecord as TechRecordGETHGV).techRecord_vehicleClass_description = + VehicleClassDescription.HeavyGoodsVehicle; + } + if (techRecord_vehicleType === VehicleTypes.TRL) { + (techRecord as TechRecordGETTRL).techRecord_vehicleClass_description = VehicleClassDescription.Trailer; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (techRecord as any).euVehicleCategory = null; + } - generatePlate$ = createEffect(() => - this.actions$.pipe( - ofType(generatePlate), - withLatestFrom(this.store.select(selectTechRecord), this.userService.name$, this.userService.userEmail$), - switchMap(([{ reason }, vehicle, name, email]) => - this.techRecordHttpService.generatePlate$(vehicle as TechRecordType<'get'>, reason, { name, email }).pipe( - map(() => generatePlateSuccess()), - catchError((error) => of(generatePlateFailure({ error: this.getTechRecordErrorMessage(error, 'generatePlate') }))), - )), - )); + const techRecordTemplate = vehicleTemplateMap.get(techRecord_vehicleType) || []; + return of( + techRecordTemplate.reduce((mergedNodes, formNode) => { + const form = this.dfs.createForm(formNode, techRecord); + return merge(mergedNodes, form.getCleanValue(form)); + }, {}) as TechRecordType<'put'> + ); + }), + tap((mergedForms) => this.technicalRecordService.updateEditingTechRecord(mergedForms)) + ), + { dispatch: false } + ); - generateLetter$ = createEffect(() => - this.actions$.pipe( - ofType(generateLetter), - withLatestFrom(this.store.select(selectTechRecord), this.userService.name$, this.userService.userEmail$), - switchMap(([{ letterType, paragraphId }, vehicle, name, email]) => - this.techRecordHttpService.generateLetter$(vehicle as TechRecordType<'get'>, letterType, paragraphId, { name, email }).pipe( - map(() => generateLetterSuccess()), - catchError((error) => of(generateLetterFailure({ error: this.getTechRecordErrorMessage(error, 'generateLetter') }))), - )), - )); + generatePlate$ = createEffect(() => + this.actions$.pipe( + ofType(generatePlate), + withLatestFrom(this.store.select(selectTechRecord), this.userService.name$, this.userService.userEmail$), + switchMap(([{ reason }, vehicle, name, email]) => + this.techRecordHttpService.generatePlate$(vehicle as TechRecordType<'get'>, reason, { name, email }).pipe( + map(() => generatePlateSuccess()), + catchError((error) => + of(generatePlateFailure({ error: this.getTechRecordErrorMessage(error, 'generatePlate') })) + ) + ) + ) + ) + ); - unarchiveTechRecord$ = createEffect(() => - this.actions$.pipe( - ofType(unarchiveTechRecord), - switchMap(({ - systemNumber, createdTimestamp, reasonForUnarchiving, status, - }) => - this.techRecordHttpService.unarchiveTechnicalRecord$(systemNumber, createdTimestamp, reasonForUnarchiving, status).pipe( - map((vehicleTechRecord) => unarchiveTechRecordSuccess({ vehicleTechRecord })), - catchError((error) => of(unarchiveTechRecordFailure({ error: this.getTechRecordErrorMessage(error, 'unarchiveTechRecord') }))), - )), - )); + generateLetter$ = createEffect(() => + this.actions$.pipe( + ofType(generateLetter), + withLatestFrom(this.store.select(selectTechRecord), this.userService.name$, this.userService.userEmail$), + switchMap(([{ letterType, paragraphId }, vehicle, name, email]) => + this.techRecordHttpService + .generateLetter$(vehicle as TechRecordType<'get'>, letterType, paragraphId, { name, email }) + .pipe( + map(() => generateLetterSuccess()), + catchError((error) => + of(generateLetterFailure({ error: this.getTechRecordErrorMessage(error, 'generateLetter') })) + ) + ) + ) + ) + ); - generateADRCertificate$ = createEffect(() => - this.actions$.pipe( - ofType(generateADRCertificate), - switchMap(({ - systemNumber, createdTimestamp, certificateType, - }) => - this.techRecordHttpService.generateADRCertificate$(systemNumber, createdTimestamp, certificateType).pipe( - map((res) => generateADRCertificateSuccess({ id: res.id })), - catchError((error) => of(generateADRCertificateFailure({ error: this.getTechRecordErrorMessage(error, 'generateADRCertificate') }))), - )), - )); + unarchiveTechRecord$ = createEffect(() => + this.actions$.pipe( + ofType(unarchiveTechRecord), + switchMap(({ systemNumber, createdTimestamp, reasonForUnarchiving, status }) => + this.techRecordHttpService + .unarchiveTechnicalRecord$(systemNumber, createdTimestamp, reasonForUnarchiving, status) + .pipe( + map((vehicleTechRecord) => unarchiveTechRecordSuccess({ vehicleTechRecord })), + catchError((error) => + of(unarchiveTechRecordFailure({ error: this.getTechRecordErrorMessage(error, 'unarchiveTechRecord') })) + ) + ) + ) + ) + ); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - getTechRecordErrorMessage(error: any, type: string, search?: string): string { - if (typeof error !== 'object') { - return error; - } if (error.status === 404) { - return this.apiErrors[`${type}_404`]; - } - return `${this.apiErrors[`${type}_400`]} ${search ?? JSON.stringify(error.error)}`; + generateADRCertificate$ = createEffect(() => + this.actions$.pipe( + ofType(generateADRCertificate), + switchMap(({ systemNumber, createdTimestamp, certificateType }) => + this.techRecordHttpService.generateADRCertificate$(systemNumber, createdTimestamp, certificateType).pipe( + map((res) => generateADRCertificateSuccess({ id: res.id })), + catchError((error) => + of( + generateADRCertificateFailure({ error: this.getTechRecordErrorMessage(error, 'generateADRCertificate') }) + ) + ) + ) + ) + ) + ); - } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + getTechRecordErrorMessage(error: any, type: string, search?: string): string { + if (typeof error !== 'object') { + return error; + } + if (error.status === 404) { + return this.apiErrors[`${type}_404`]; + } + return `${this.apiErrors[`${type}_400`]} ${search ?? JSON.stringify(error.error)}`; + } - private apiErrors: Record = { - getTechnicalRecords_400: 'There was a problem getting the Tech Record by', - getTechnicalRecords_404: 'Vehicle not found, check the vehicle registration mark, trailer ID or vehicle identification number', - createVehicleRecord_400: 'Unable to create a new vehicle record', - // createProvisionalTechRecord_400: 'Unable to create a new provisional record', - updateTechnicalRecord_400: 'Unable to update technical record', - archiveTechRecord_400: 'Unable to archive technical record', - promoteTechRecord_400: 'Unable to promote technical record', - unarchiveTechRecord_400: 'Unable to unarchive technical record', - generateADRCertificate_400: 'Unable to generate ADR certificate', - }; + private apiErrors: Record = { + getTechnicalRecords_400: 'There was a problem getting the Tech Record by', + getTechnicalRecords_404: + 'Vehicle not found, check the vehicle registration mark, trailer ID or vehicle identification number', + createVehicleRecord_400: 'Unable to create a new vehicle record', + // createProvisionalTechRecord_400: 'Unable to create a new provisional record', + updateTechnicalRecord_400: 'Unable to update technical record', + archiveTechRecord_400: 'Unable to archive technical record', + promoteTechRecord_400: 'Unable to promote technical record', + unarchiveTechRecord_400: 'Unable to unarchive technical record', + generateADRCertificate_400: 'Unable to generate ADR certificate', + }; } diff --git a/src/app/store/technical-records/reducers/batch-create.reducer.ts b/src/app/store/technical-records/reducers/batch-create.reducer.ts index 856cdebc59..ffacd38f87 100644 --- a/src/app/store/technical-records/reducers/batch-create.reducer.ts +++ b/src/app/store/technical-records/reducers/batch-create.reducer.ts @@ -1,74 +1,84 @@ import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; import { StatusCodes, VehicleTypes } from '@models/vehicle-tech-record.model'; -import { - EntityAdapter, EntityState, Update, createEntityAdapter, -} from '@ngrx/entity'; +import { EntityAdapter, EntityState, Update, createEntityAdapter } from '@ngrx/entity'; import { createReducer, on } from '@ngrx/store'; import { - clearBatch, - setApplicationId, - setGenerateNumberFlag, - setVehicleStatus, - setVehicleType, - upsertVehicleBatch, + clearBatch, + setApplicationId, + setGenerateNumberFlag, + setVehicleStatus, + setVehicleType, + upsertVehicleBatch, } from '../actions/batch-create.actions'; import { createVehicleRecordSuccess, updateTechRecordSuccess } from '../actions/technical-record-service.actions'; export type BatchRecord = { - vin: string; - systemNumber?: string; - trailerIdOrVrm?: string; - vehicleType?: string; - status?: StatusCodes; - created?: boolean; - amendedRecord?: boolean; - createdTimestamp?: string; + vin: string; + systemNumber?: string; + trailerIdOrVrm?: string; + vehicleType?: string; + status?: StatusCodes; + created?: boolean; + amendedRecord?: boolean; + createdTimestamp?: string; }; export interface BatchRecords extends EntityState { - vehicleType?: VehicleTypes; - generateNumber: boolean; - applicationId?: string; - vehicleStatus?: string; + vehicleType?: VehicleTypes; + generateNumber: boolean; + applicationId?: string; + vehicleStatus?: string; } const selectId = (a: BatchRecord): string => { - return a.vin; + return a.vin; }; export const batchAdapter: EntityAdapter = createEntityAdapter({ selectId }); export const initialBatchState: BatchRecords = batchAdapter.getInitialState({ - generateNumber: false, + generateNumber: false, }); export const vehicleBatchCreateReducer = createReducer( - initialBatchState, - on(upsertVehicleBatch, (state, action) => batchAdapter.setAll(action.vehicles, state)), - on(setGenerateNumberFlag, (state, { generateNumber }) => ({ ...state, generateNumber })), - on(setApplicationId, (state, { applicationId }) => ({ ...state, applicationId })), - on(setVehicleStatus, (state, { vehicleStatus }) => ({ ...state, vehicleStatus })), - on(setVehicleType, (state, { vehicleType }) => ({ ...state, vehicleType })), - on(createVehicleRecordSuccess, (state, action) => batchAdapter.updateOne(vehicleRecordsToBatchRecordMapper(action.vehicleTechRecord), state)), - on(updateTechRecordSuccess, (state, action) => - batchAdapter.updateOne(vehicleRecordsToBatchRecordMapper(action.vehicleTechRecord, true, true), state)), - on(clearBatch, (state) => batchAdapter.removeAll({ - ...state, vehicleStatus: '', applicationId: '', vehicleType: undefined, - })), + initialBatchState, + on(upsertVehicleBatch, (state, action) => batchAdapter.setAll(action.vehicles, state)), + on(setGenerateNumberFlag, (state, { generateNumber }) => ({ ...state, generateNumber })), + on(setApplicationId, (state, { applicationId }) => ({ ...state, applicationId })), + on(setVehicleStatus, (state, { vehicleStatus }) => ({ ...state, vehicleStatus })), + on(setVehicleType, (state, { vehicleType }) => ({ ...state, vehicleType })), + on(createVehicleRecordSuccess, (state, action) => + batchAdapter.updateOne(vehicleRecordsToBatchRecordMapper(action.vehicleTechRecord), state) + ), + on(updateTechRecordSuccess, (state, action) => + batchAdapter.updateOne(vehicleRecordsToBatchRecordMapper(action.vehicleTechRecord, true, true), state) + ), + on(clearBatch, (state) => + batchAdapter.removeAll({ + ...state, + vehicleStatus: '', + applicationId: '', + vehicleType: undefined, + }) + ) ); -function vehicleRecordsToBatchRecordMapper(techRecord: TechRecordType<'get'>, created = true, amendedRecord = false): Update { - return { - id: techRecord.vin, - changes: { - vin: techRecord.vin, - systemNumber: techRecord.systemNumber, - trailerIdOrVrm: techRecord.techRecord_vehicleType !== 'trl' ? techRecord.primaryVrm ?? '' : techRecord.trailerId, - vehicleType: techRecord.techRecord_vehicleType, - status: (techRecord.techRecord_statusCode as StatusCodes) ?? undefined, - created, - amendedRecord, - createdTimestamp: techRecord.createdTimestamp, - }, - }; +function vehicleRecordsToBatchRecordMapper( + techRecord: TechRecordType<'get'>, + created = true, + amendedRecord = false +): Update { + return { + id: techRecord.vin, + changes: { + vin: techRecord.vin, + systemNumber: techRecord.systemNumber, + trailerIdOrVrm: techRecord.techRecord_vehicleType !== 'trl' ? techRecord.primaryVrm ?? '' : techRecord.trailerId, + vehicleType: techRecord.techRecord_vehicleType, + status: (techRecord.techRecord_statusCode as StatusCodes) ?? undefined, + created, + amendedRecord, + createdTimestamp: techRecord.createdTimestamp, + }, + }; } diff --git a/src/app/store/technical-records/reducers/technical-record-service.reducer.spec.ts b/src/app/store/technical-records/reducers/technical-record-service.reducer.spec.ts index 9bb48cd36b..8d2ae2ccc4 100644 --- a/src/app/store/technical-records/reducers/technical-record-service.reducer.spec.ts +++ b/src/app/store/technical-records/reducers/technical-record-service.reducer.spec.ts @@ -1,7 +1,11 @@ import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; +import { TechRecordType as NonVerbTechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; import { - TechRecordPUTHGV, TechRecordPUTLGV, TechRecordPUTTRL, TechRecordType as TechRecordTypeVehicleVerb, + TechRecordPUTHGV, + TechRecordPUTLGV, + TechRecordPUTTRL, + TechRecordType as TechRecordTypeVehicleVerb, } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb-vehicle-type'; import { createMockHgv } from '@mocks/hgv-record.mock'; import { createMockLgv } from '@mocks/lgv-record.mock'; @@ -9,615 +13,681 @@ import { createMockTrl } from '@mocks/trl-record.mock'; import { BodyTypeCode, BodyTypeDescription } from '@models/body-type-enum'; import { PsvMake } from '@models/reference-data.model'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; -import { - TechRecordType as NonVerbTechRecordType, -} from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; import { mockVehicleTechnicalRecord } from '../../../../mocks/mock-vehicle-technical-record.mock'; import { - addAxle, - addSectionState, - archiveTechRecord, - archiveTechRecordFailure, - archiveTechRecordSuccess, - clearADRDetailsBeforeUpdate, - clearAllSectionStates, - clearScrollPosition, - createVehicleRecord, - createVehicleRecordFailure, - createVehicleRecordSuccess, - getBySystemNumber, - getBySystemNumberFailure, - getBySystemNumberSuccess, - removeAxle, - removeSectionState, updateADRAdditionalExaminerNotes, - updateBody, - updateBrakeForces, - updateEditingTechRecord, - updateEditingTechRecordCancel, updateExistingADRAdditionalExaminerNote, - updateScrollPosition, - updateTechRecord, - updateTechRecordFailure, - updateTechRecordSuccess, + addAxle, + addSectionState, + archiveTechRecord, + archiveTechRecordFailure, + archiveTechRecordSuccess, + clearADRDetailsBeforeUpdate, + clearAllSectionStates, + clearScrollPosition, + createVehicleRecord, + createVehicleRecordFailure, + createVehicleRecordSuccess, + getBySystemNumber, + getBySystemNumberFailure, + getBySystemNumberSuccess, + removeAxle, + removeSectionState, + updateADRAdditionalExaminerNotes, + updateBody, + updateBrakeForces, + updateEditingTechRecord, + updateEditingTechRecordCancel, + updateExistingADRAdditionalExaminerNote, + updateScrollPosition, + updateTechRecord, + updateTechRecordFailure, + updateTechRecordSuccess, } from '../actions/technical-record-service.actions'; -import { TechnicalRecordServiceState, initialState, vehicleTechRecordReducer } from './technical-record-service.reducer'; +import { + TechnicalRecordServiceState, + initialState, + vehicleTechRecordReducer, +} from './technical-record-service.reducer'; describe('Vehicle Technical Record Reducer', () => { - describe('unknown action', () => { - it('should return the default state', () => { - const action = { - type: 'Unknown', - }; - const state = vehicleTechRecordReducer(initialState, action); - - expect(state).toBe(initialState); - }); - }); - - describe('getBySystemNumber', () => { - it('should set all vehicle technical records', () => { - const newState: TechnicalRecordServiceState = { ...initialState, loading: true }; - const action = getBySystemNumber({ systemNumber: '001' }); - const state = vehicleTechRecordReducer(initialState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('getBySystemNumberSuccess', () => { - it('should set all vehicle technical records', () => { - const record = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordSearchSchema; - const newState: TechnicalRecordServiceState = { - ...initialState, - techRecordHistory: [{ systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordSearchSchema], - }; - const action = getBySystemNumberSuccess({ techRecordHistory: [record] }); - const state = vehicleTechRecordReducer(initialState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('getBySystemNumberFailure', () => { - it('should history to an empty array', () => { - const newState = { ...initialState, techRecordHistory: [] }; - const action = getBySystemNumberFailure({ error: 'error' }); - const state = vehicleTechRecordReducer(initialState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('createVehicleRecord', () => { - it('should set loading to true', () => { - const expectedVehicle = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>; - - const oldState: TechnicalRecordServiceState = { ...initialState, vehicleTechRecord: expectedVehicle, loading: false }; - - const newState = vehicleTechRecordReducer(oldState, createVehicleRecord({ vehicle: {} as TechRecordType<'put'> })); - - expect(newState).not.toBe(oldState); - expect(newState.vehicleTechRecord).toEqual(expectedVehicle); - expect(newState.loading).toBeTruthy(); - }); - }); - - describe('createVehicleRecordSuccess', () => { - it('should update the vehicleTechRecords property of the state with the newly created vehicle and set loading to false', () => { - const oldState: TechnicalRecordServiceState = { - ...initialState, - vehicleTechRecord: { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>, - }; - - const expectedVehicle = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>; - - const action = createVehicleRecordSuccess({ vehicleTechRecord: expectedVehicle }); - - const newState = vehicleTechRecordReducer(oldState, action); - - expect(newState.loading).toBeFalsy(); - }); - }); - - describe('createVehicleRecordFailure', () => { - it('should add an error to the state and set loading to false', () => { - const action = createVehicleRecordFailure({ error: 'something bad happened' }); - const newState = vehicleTechRecordReducer(initialState, action); - - expect(newState.loading).toBeFalsy(); - }); - }); - - describe('updateTechRecords', () => { - it('should set the new vehicle tech records state after update', () => { - const state: TechnicalRecordServiceState = { - ...initialState, - vehicleTechRecord: { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>, - loading: true, - }; - const action = updateTechRecord({ systemNumber: 'foo', createdTimestamp: 'bar' }); - const newState = vehicleTechRecordReducer(state, action); - - expect(newState).toEqual(state); - expect(newState).not.toBe(state); - expect(newState.loading).toBe(true); - }); - }); - - describe('updateTechRecordsSuccess', () => { - it('should set the new vehicle tech records state after update success', () => { - const oldRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>; - const newRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVinNew' } as TechRecordType<'get'>; - - const state: TechnicalRecordServiceState = { - ...initialState, - vehicleTechRecord: oldRecord, - }; - const action = updateTechRecordSuccess({ vehicleTechRecord: newRecord }); - const newState = vehicleTechRecordReducer(state, action); - - expect(state).not.toEqual(newState); - expect(newState.vehicleTechRecord).toEqual(newRecord); - }); - }); - - describe('updateTechRecordsFailure', () => { - it('should set error state', () => { - const error = 'fetching vehicle tech records failed'; - const action = updateTechRecordFailure({ error }); - const newState = vehicleTechRecordReducer(initialState, action); - - expect(initialState).not.toEqual(newState); - expect(newState.error).toEqual(error); - expect(initialState).not.toBe(newState); - }); - }); - - describe('archiveTechRecord', () => { - it('should set the state to loading', () => { - const state: TechnicalRecordServiceState = { - ...initialState, - vehicleTechRecord: { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>, - loading: true, - }; - const action = archiveTechRecord({ systemNumber: 'foo', createdTimestamp: 'bar', reasonForArchiving: 'some reason' }); - const newState = vehicleTechRecordReducer(state, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - expect(state.loading).toBe(true); - }); - }); - - describe('archiveTechRecordSuccess', () => { - it('should set the new vehicle tech records state after update success', () => { - const oldRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as unknown as TechRecordType<'get'>; - const newRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVinNew' } as unknown as TechRecordType<'get'>; - - const state: TechnicalRecordServiceState = { - ...initialState, - vehicleTechRecord: oldRecord, - }; - const action = archiveTechRecordSuccess({ vehicleTechRecord: newRecord }); - const newState = vehicleTechRecordReducer(state, action); - - expect(state).not.toEqual(newState); - expect(newState.vehicleTechRecord).toEqual(newRecord); - }); - }); - - describe('archiveTechRecordFailure', () => { - it('should set error state', () => { - const error = 'fetching vehicle tech records failed'; - const action = archiveTechRecordFailure({ error }); - const newState = vehicleTechRecordReducer(initialState, action); - - expect(initialState).not.toEqual(newState); - expect(newState.error).toEqual(error); - expect(initialState).not.toBe(newState); - }); - }); - - describe('updateEditingTechRecord', () => { - it('should set the editingTechRecord', () => { - const vehicleTechRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as unknown as TechRecordType<'put'>; - const action = updateEditingTechRecord({ vehicleTechRecord }); - const newState = vehicleTechRecordReducer(initialState, action); - - expect(initialState).not.toEqual(newState); - expect(newState.editingTechRecord).toEqual(vehicleTechRecord); - expect(initialState).not.toBe(newState); - }); - }); - - describe('updateEditingTechRecordCancel', () => { - it('should clear the state', () => { - initialState.editingTechRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as unknown as TechRecordType<'put'>; - const action = updateEditingTechRecordCancel(); - const newState = vehicleTechRecordReducer(initialState, action); - - expect(initialState).not.toEqual(newState); - expect(newState.editingTechRecord).toBeUndefined(); - expect(initialState).not.toBe(newState); - }); - }); - - describe('Section state changes', () => { - it('should add the section name to the state', () => { - initialState.sectionState = []; - const action = addSectionState({ section: 'TEST_SECTION' }); - const newState = vehicleTechRecordReducer(initialState, action); - - expect(initialState).not.toEqual(newState); - expect(newState.sectionState).toEqual(['TEST_SECTION']); - expect(initialState).not.toBe(newState); - }); - - it('should avoid duplicating the section name', () => { - initialState.sectionState = ['TEST_SECTION']; - const action = addSectionState({ section: 'TEST_SECTION' }); - const newState = vehicleTechRecordReducer(initialState, action); - - expect(initialState).toEqual(newState); - expect(newState.sectionState).toEqual(['TEST_SECTION']); - expect(initialState).not.toBe(newState); - }); - - it('should remove the section name from the state', () => { - initialState.sectionState = ['TEST_SECTION1', 'TEST_SECTION2']; - const action = removeSectionState({ section: 'TEST_SECTION1' }); - const newState = vehicleTechRecordReducer(initialState, action); - - expect(initialState).not.toEqual(newState); - expect(newState.sectionState).toEqual(['TEST_SECTION2']); - expect(initialState).not.toBe(newState); - }); - - it('should clear all the section names from the state', () => { - initialState.sectionState = ['TEST_SECTION1', 'TEST_SECTION2']; - const action = clearAllSectionStates(); - const newState = vehicleTechRecordReducer(initialState, action); - - expect(initialState).not.toEqual(newState); - expect(newState.sectionState).toEqual([]); - expect(initialState).not.toBe(newState); - }); - }); - // TODO V3 HGV/PSV tests - describe('updating properties of the tech record in edit', () => { - beforeEach(() => { - initialState.editingTechRecord = mockVehicleTechnicalRecord(VehicleTypes.PSV) as TechRecordType<'put'>; - }); - - describe('updateBrakeForces', () => { - it('should not update half locked brake forces with no gross kerb weight', () => { - const asPSV = initialState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; - asPSV.techRecord_brakes_brakeCodeOriginal = '80'; - asPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_parkingBrakeForceB = 50; - asPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_secondaryBrakeForceB = 30; - asPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_serviceBrakeForceB = 10; - expect(asPSV.techRecord_brakes_brakeCode).toBe('1234'); - - const newState = vehicleTechRecordReducer(initialState, updateBrakeForces({ grossLadenWeight: 2000 })); - - const newPSV = newState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; - - expect(newPSV.techRecord_brakes_brakeCode).toBe(`0${2000 / 100}${asPSV.techRecord_brakes_brakeCodeOriginal}`); - - expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_serviceBrakeForceA).toBe(Math.round((2000 * 16) / 100)); - expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_secondaryBrakeForceA).toBe(Math.round((2000 * 22.5) / 100)); - expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_parkingBrakeForceA).toBe(Math.round((2000 * 45) / 100)); - - expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_serviceBrakeForceB).toBe(10); - expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_secondaryBrakeForceB).toBe(30); - expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_parkingBrakeForceB).toBe(50); - }); - - it('should not update half locked brake forces with no gross laden weight', () => { - const asPSV = initialState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; - asPSV.techRecord_brakes_brakeCodeOriginal = '80'; - asPSV.techRecord_brakes_brakeForceWheelsNotLocked_parkingBrakeForceA = 50; - asPSV.techRecord_brakes_brakeForceWheelsNotLocked_secondaryBrakeForceA = 30; - asPSV.techRecord_brakes_brakeForceWheelsNotLocked_serviceBrakeForceA = 10; - - const newState = vehicleTechRecordReducer(initialState, updateBrakeForces({ grossKerbWeight: 1000 })); - - const newPSV = newState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; - - expect(newPSV.techRecord_brakes_brakeCode).toBe('1234'); - - expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_serviceBrakeForceA).toBe(10); - expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_secondaryBrakeForceA).toBe(30); - expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_parkingBrakeForceA).toBe(50); - - expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_serviceBrakeForceB).toBe(Math.round((1000 * 16) / 100)); - expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_secondaryBrakeForceB).toBe(Math.round((1000 * 25) / 100)); - expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_parkingBrakeForceB).toBe(Math.round((1000 * 50) / 100)); - }); - - it('should not update brakeCode with no gross laden weight', () => { - const asPSV = initialState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; - asPSV.techRecord_brakes_brakeCodeOriginal = '80'; - asPSV.techRecord_brakes_brakeCode = '37'; - - const newState = vehicleTechRecordReducer(initialState, updateBrakeForces({ grossKerbWeight: 1000 })); - expect((newState?.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>).techRecord_brakes_brakeCode).toBe('37'); - }); - - it('should update brake forces', () => { - const asPSV = initialState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; - asPSV.techRecord_brakes_brakeCodeOriginal = '80'; - expect(asPSV.techRecord_brakes_brakeCode).toBe('1234'); - - const newState = vehicleTechRecordReducer(initialState, updateBrakeForces({ grossKerbWeight: 1000, grossLadenWeight: 2000 })); - - expect(newState).not.toBe(initialState); - expect(newState).not.toEqual(initialState); - - const newPSV = newState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; - expect(newPSV.techRecord_brakes_brakeCode).toBe(`0${2000 / 100}${asPSV.techRecord_brakes_brakeCodeOriginal}`); - - expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_serviceBrakeForceA).toBe(Math.round((2000 * 16) / 100)); - expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_secondaryBrakeForceA).toBe(Math.round((2000 * 22.5) / 100)); - expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_parkingBrakeForceA).toBe(Math.round((2000 * 45) / 100)); - - expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_serviceBrakeForceB).toBe(Math.round((1000 * 16) / 100)); - expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_secondaryBrakeForceB).toBe(Math.round((1000 * 25) / 100)); - expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_parkingBrakeForceB).toBe(Math.round((1000 * 50) / 100)); - }); - }); - - describe('updateBody', () => { - it('should update body', () => { - expect((initialState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>).techRecord_bodyType_description).toBe( - BodyTypeDescription.DOUBLE_DECKER, - ); - - const expectedData = { - dtpNumber: '9999', - psvChassisMake: 'Toyota', - psvChassisModel: 'Supra', - psvBodyMake: 'Random', - psvBodyType: 'o', - } as PsvMake; - - const newState = vehicleTechRecordReducer(initialState, updateBody({ psvMake: expectedData })); - - expect(newState).not.toBe(initialState); - expect(newState).not.toEqual(initialState); - - const updatedTechRecord = newState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; - expect(updatedTechRecord?.techRecord_bodyType_code).toBe(BodyTypeCode.O); - expect(updatedTechRecord?.techRecord_bodyType_description).toBe(BodyTypeDescription.OTHER); - expect(updatedTechRecord?.techRecord_bodyMake).toBe(expectedData.psvBodyMake); - expect(updatedTechRecord?.techRecord_chassisMake).toBe(expectedData.psvChassisMake); - expect(updatedTechRecord?.techRecord_chassisModel).toBe(expectedData.psvChassisModel); - }); - }); - - describe('addAxle', () => { - describe('it should add an axle', () => { - it('with the axles property defined', () => { - const techRecord = initialState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; - expect(techRecord?.techRecord_noOfAxles).toBe(2); - expect(techRecord?.techRecord_axles?.length).toBe(3); - - const newState = vehicleTechRecordReducer(initialState, addAxle()); - - expect(newState).not.toBe(initialState); - expect(newState).not.toEqual(initialState); - - const updatedTechRecord = newState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; - expect(updatedTechRecord?.techRecord_noOfAxles).toBe(4); - expect(updatedTechRecord?.techRecord_axles?.length).toBe(4); - - const newAxleField = updatedTechRecord?.techRecord_axles ?? []; - - expect(newAxleField[3].tyres_dataTrAxles).toBeNull(); - expect(newAxleField[3].tyres_fitmentCode).toBeNull(); - expect(newAxleField[3].tyres_plyRating).toBeNull(); - expect(newAxleField[3].tyres_speedCategorySymbol).toBeNull(); - expect(newAxleField[3].tyres_tyreCode).toBeNull(); - expect(newAxleField[3].tyres_tyreSize).toBeNull(); - - expect(newAxleField[3].weights_designWeight).toBeDefined(); - expect(newAxleField[3].weights_gbWeight).toBeDefined(); - expect(newAxleField[3].weights_kerbWeight).toBeDefined(); - expect(newAxleField[3].weights_ladenWeight).toBeDefined(); - expect(updatedTechRecord?.techRecord_axles?.pop()?.axleNumber).toBe(4); - }); - - it('without the axles property defined', () => { - const techRecord = initialState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; - delete techRecord?.techRecord_axles; - techRecord.techRecord_noOfAxles = 0; - expect(techRecord?.techRecord_noOfAxles).toBe(0); - - const newState = vehicleTechRecordReducer(initialState, addAxle()); - - expect(newState).not.toBe(initialState); - expect(newState).not.toEqual(initialState); - - const updatedTechRecord = newState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; - expect(updatedTechRecord?.techRecord_noOfAxles).toBe(1); - expect(updatedTechRecord?.techRecord_axles?.length).toBe(1); - - const newAxleField = updatedTechRecord?.techRecord_axles || []; - - expect(newAxleField[0].tyres_dataTrAxles).toBeNull(); - expect(newAxleField[0].tyres_fitmentCode).toBeNull(); - expect(newAxleField[0].tyres_plyRating).toBeNull(); - expect(newAxleField[0].tyres_speedCategorySymbol).toBeNull(); - expect(newAxleField[0].tyres_tyreCode).toBeNull(); - expect(newAxleField[0].tyres_tyreSize).toBeNull(); - - expect(newAxleField[0].weights_designWeight).toBeDefined(); - expect(newAxleField[0].weights_gbWeight).toBeDefined(); - expect(newAxleField[0].weights_kerbWeight).toBeDefined(); - expect(newAxleField[0].weights_ladenWeight).toBeDefined(); - expect(updatedTechRecord?.techRecord_axles?.pop()?.axleNumber).toBe(1); - }); - }); - }); - - describe('removeAxle', () => { - it('should remove specified axle', () => { - const techRecord = initialState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; - expect(techRecord?.techRecord_noOfAxles).toBe(2); - expect(techRecord?.techRecord_axles?.length).toBe(3); - - const newState = vehicleTechRecordReducer(initialState, removeAxle({ index: 0 })); - - expect(newState).not.toBe(initialState); - expect(newState).not.toEqual(initialState); - - const updatedTechRecord = newState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; - expect(updatedTechRecord?.techRecord_noOfAxles).toBe(2); - expect(updatedTechRecord?.techRecord_axles?.length).toBe(2); - expect(updatedTechRecord?.techRecord_axles?.pop()?.axleNumber).toBe(2); - }); - }); - describe('updateScrollPosition', () => { - it('should update the scroll position state', () => { - const newState = vehicleTechRecordReducer(initialState, updateScrollPosition({ position: [1, 2] })); - - expect(newState.scrollPosition).toEqual([1, 2]); - }); - }); - describe('clearScrollPosition', () => { - it('should reset the scroll position', () => { - initialState.scrollPosition = [2, 2]; - const newState = vehicleTechRecordReducer(initialState, clearScrollPosition()); - - expect(newState.scrollPosition).toEqual([0, 0]); - }); - }); - }); - - describe('clearADRDetailsBeforeUpdate', () => { - it('should set all ADR fields to null when: vehicleType = HGV and dangerousGoods = false', () => { - initialState.editingTechRecord = createMockHgv(1234) as TechRecordPUTHGV; - initialState.editingTechRecord.techRecord_adrDetails_dangerousGoods = false; - initialState.editingTechRecord.techRecord_adrDetails_applicantDetails_city = 'Test City'; - - const newState = vehicleTechRecordReducer(initialState, clearADRDetailsBeforeUpdate()); - expect(newState.editingTechRecord).toBeDefined(); - expect((newState.editingTechRecord as TechRecordPUTHGV).techRecord_adrDetails_applicantDetails_city).toBeNull(); - }); - - it('should set all ADR fields to null when: vehicleType = TRL and dangerousGoods = false', () => { - initialState.editingTechRecord = createMockTrl(1234) as TechRecordPUTTRL; - initialState.editingTechRecord.techRecord_adrDetails_dangerousGoods = false; - initialState.editingTechRecord.techRecord_adrDetails_applicantDetails_street = 'Test Street'; - - const newState = vehicleTechRecordReducer(initialState, clearADRDetailsBeforeUpdate()); - expect(newState.editingTechRecord).toBeDefined(); - expect((newState.editingTechRecord as TechRecordPUTTRL).techRecord_adrDetails_applicantDetails_street).toBeNull(); - }); - - it('should set all ADR fields to null when: vehicleType = LGV and dangerousGoods = false', () => { - initialState.editingTechRecord = createMockLgv(1234) as TechRecordPUTLGV; - initialState.editingTechRecord.techRecord_adrDetails_dangerousGoods = false; - initialState.editingTechRecord.techRecord_adrDetails_adrCertificateNotes = 'Test notes'; - - const newState = vehicleTechRecordReducer(initialState, clearADRDetailsBeforeUpdate()); - expect(newState.editingTechRecord).toBeDefined(); - expect((newState.editingTechRecord as TechRecordPUTLGV).techRecord_adrDetails_applicantDetails_street).toBeNull(); - }); - - it('should not set all ADR fields to null when: vehicleType = HGV and dangerousGoods = true', () => { - initialState.editingTechRecord = createMockHgv(1234) as TechRecordPUTHGV; - initialState.editingTechRecord.techRecord_adrDetails_dangerousGoods = true; - initialState.editingTechRecord.techRecord_adrDetails_applicantDetails_town = 'Test Town'; - - const newState = vehicleTechRecordReducer(initialState, clearADRDetailsBeforeUpdate()); - expect(newState.editingTechRecord).toBeDefined(); - expect((newState.editingTechRecord as TechRecordPUTHGV).techRecord_adrDetails_applicantDetails_town).toBe('Test Town'); - }); - - it('should not set all ADR fields to null when: vehicleType = TRL and dangerousGoods = true', () => { - initialState.editingTechRecord = createMockTrl(1234) as TechRecordPUTTRL; - initialState.editingTechRecord.techRecord_adrDetails_dangerousGoods = true; - initialState.editingTechRecord.techRecord_adrDetails_applicantDetails_postcode = 'Test Postcode'; - - const newState = vehicleTechRecordReducer(initialState, clearADRDetailsBeforeUpdate()); - expect(newState.editingTechRecord).toBeDefined(); - expect((newState.editingTechRecord as TechRecordPUTTRL).techRecord_adrDetails_applicantDetails_postcode).toBe('Test Postcode'); - }); - - it('should not set all ADR fields to null when: vehicleType = LGV and dangerousGoods = true', () => { - initialState.editingTechRecord = createMockLgv(1234) as TechRecordPUTLGV; - initialState.editingTechRecord.techRecord_adrDetails_dangerousGoods = true; - initialState.editingTechRecord.techRecord_adrDetails_adrCertificateNotes = 'Test notes'; - - const newState = vehicleTechRecordReducer(initialState, clearADRDetailsBeforeUpdate()); - expect(newState.editingTechRecord).toBeDefined(); - expect((newState.editingTechRecord as TechRecordPUTLGV).techRecord_adrDetails_adrCertificateNotes).toBe('Test notes'); - }); - - }); - describe('handleADRExaminerNoteChanges', () => { - beforeEach(() => { - const mockedDate = new Date(2024, 5, 20); - jest.useFakeTimers(); - jest.setSystemTime(mockedDate); - }); - - afterEach(() => { - jest.useRealTimers(); - }); - it('should handle any changes made to the adr examiner notes', () => { - const testNote = { - note: 'testNote', - createdAtDate: new Date().toISOString(), - lastUpdatedBy: 'someone', - }; - const state: TechnicalRecordServiceState = { - ...initialState, - vehicleTechRecord: { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - } as unknown as TechRecordType<'get'>, - editingTechRecord: { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_adrDetails_additionalExaminerNotes_note: testNote.note, - } as unknown as TechRecordType<'put'>, - loading: true, - }; - const action = updateADRAdditionalExaminerNotes({ username: testNote.lastUpdatedBy }); - const newState = vehicleTechRecordReducer(state, action); - expect((newState.editingTechRecord as unknown as (NonVerbTechRecordType<'hgv' | 'lgv' | 'trl'>))?.techRecord_adrDetails_additionalExaminerNotes) - .toContainEqual(testNote); - }); - }); - describe('handleUpdateExistingADRExaminerNote', () => { - it('should', () => { - const state: TechnicalRecordServiceState = { - ...initialState, - editingTechRecord: { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_adrDetails_additionalExaminerNotes: [ - { - note: 'foo', - createdAtDate: 'bar', - lastUpdatedBy: 'foo', - }, - ], - } as unknown as TechRecordType<'put'>, - loading: true, - }; - const newNote = 'foobar'; - const action = updateExistingADRAdditionalExaminerNote({ additionalExaminerNote: newNote, examinerNoteIndex: 0 }); - const newState = vehicleTechRecordReducer(state, action); - const editingTechRecord = newState.editingTechRecord as unknown as (NonVerbTechRecordType<'hgv' | 'lgv' | 'trl'>); - expect(editingTechRecord.techRecord_adrDetails_additionalExaminerNotes![0].note).toEqual(newNote); - }); - }); + describe('unknown action', () => { + it('should return the default state', () => { + const action = { + type: 'Unknown', + }; + const state = vehicleTechRecordReducer(initialState, action); + + expect(state).toBe(initialState); + }); + }); + + describe('getBySystemNumber', () => { + it('should set all vehicle technical records', () => { + const newState: TechnicalRecordServiceState = { ...initialState, loading: true }; + const action = getBySystemNumber({ systemNumber: '001' }); + const state = vehicleTechRecordReducer(initialState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('getBySystemNumberSuccess', () => { + it('should set all vehicle technical records', () => { + const record = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordSearchSchema; + const newState: TechnicalRecordServiceState = { + ...initialState, + techRecordHistory: [{ systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordSearchSchema], + }; + const action = getBySystemNumberSuccess({ techRecordHistory: [record] }); + const state = vehicleTechRecordReducer(initialState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('getBySystemNumberFailure', () => { + it('should history to an empty array', () => { + const newState = { ...initialState, techRecordHistory: [] }; + const action = getBySystemNumberFailure({ error: 'error' }); + const state = vehicleTechRecordReducer(initialState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('createVehicleRecord', () => { + it('should set loading to true', () => { + const expectedVehicle = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>; + + const oldState: TechnicalRecordServiceState = { + ...initialState, + vehicleTechRecord: expectedVehicle, + loading: false, + }; + + const newState = vehicleTechRecordReducer( + oldState, + createVehicleRecord({ vehicle: {} as TechRecordType<'put'> }) + ); + + expect(newState).not.toBe(oldState); + expect(newState.vehicleTechRecord).toEqual(expectedVehicle); + expect(newState.loading).toBeTruthy(); + }); + }); + + describe('createVehicleRecordSuccess', () => { + it('should update the vehicleTechRecords property of the state with the newly created vehicle and set loading to false', () => { + const oldState: TechnicalRecordServiceState = { + ...initialState, + vehicleTechRecord: { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>, + }; + + const expectedVehicle = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>; + + const action = createVehicleRecordSuccess({ vehicleTechRecord: expectedVehicle }); + + const newState = vehicleTechRecordReducer(oldState, action); + + expect(newState.loading).toBeFalsy(); + }); + }); + + describe('createVehicleRecordFailure', () => { + it('should add an error to the state and set loading to false', () => { + const action = createVehicleRecordFailure({ error: 'something bad happened' }); + const newState = vehicleTechRecordReducer(initialState, action); + + expect(newState.loading).toBeFalsy(); + }); + }); + + describe('updateTechRecords', () => { + it('should set the new vehicle tech records state after update', () => { + const state: TechnicalRecordServiceState = { + ...initialState, + vehicleTechRecord: { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>, + loading: true, + }; + const action = updateTechRecord({ systemNumber: 'foo', createdTimestamp: 'bar' }); + const newState = vehicleTechRecordReducer(state, action); + + expect(newState).toEqual(state); + expect(newState).not.toBe(state); + expect(newState.loading).toBe(true); + }); + }); + + describe('updateTechRecordsSuccess', () => { + it('should set the new vehicle tech records state after update success', () => { + const oldRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>; + const newRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVinNew' } as TechRecordType<'get'>; + + const state: TechnicalRecordServiceState = { + ...initialState, + vehicleTechRecord: oldRecord, + }; + const action = updateTechRecordSuccess({ vehicleTechRecord: newRecord }); + const newState = vehicleTechRecordReducer(state, action); + + expect(state).not.toEqual(newState); + expect(newState.vehicleTechRecord).toEqual(newRecord); + }); + }); + + describe('updateTechRecordsFailure', () => { + it('should set error state', () => { + const error = 'fetching vehicle tech records failed'; + const action = updateTechRecordFailure({ error }); + const newState = vehicleTechRecordReducer(initialState, action); + + expect(initialState).not.toEqual(newState); + expect(newState.error).toEqual(error); + expect(initialState).not.toBe(newState); + }); + }); + + describe('archiveTechRecord', () => { + it('should set the state to loading', () => { + const state: TechnicalRecordServiceState = { + ...initialState, + vehicleTechRecord: { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>, + loading: true, + }; + const action = archiveTechRecord({ + systemNumber: 'foo', + createdTimestamp: 'bar', + reasonForArchiving: 'some reason', + }); + const newState = vehicleTechRecordReducer(state, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + expect(state.loading).toBe(true); + }); + }); + + describe('archiveTechRecordSuccess', () => { + it('should set the new vehicle tech records state after update success', () => { + const oldRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + } as unknown as TechRecordType<'get'>; + const newRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVinNew', + } as unknown as TechRecordType<'get'>; + + const state: TechnicalRecordServiceState = { + ...initialState, + vehicleTechRecord: oldRecord, + }; + const action = archiveTechRecordSuccess({ vehicleTechRecord: newRecord }); + const newState = vehicleTechRecordReducer(state, action); + + expect(state).not.toEqual(newState); + expect(newState.vehicleTechRecord).toEqual(newRecord); + }); + }); + + describe('archiveTechRecordFailure', () => { + it('should set error state', () => { + const error = 'fetching vehicle tech records failed'; + const action = archiveTechRecordFailure({ error }); + const newState = vehicleTechRecordReducer(initialState, action); + + expect(initialState).not.toEqual(newState); + expect(newState.error).toEqual(error); + expect(initialState).not.toBe(newState); + }); + }); + + describe('updateEditingTechRecord', () => { + it('should set the editingTechRecord', () => { + const vehicleTechRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + } as unknown as TechRecordType<'put'>; + const action = updateEditingTechRecord({ vehicleTechRecord }); + const newState = vehicleTechRecordReducer(initialState, action); + + expect(initialState).not.toEqual(newState); + expect(newState.editingTechRecord).toEqual(vehicleTechRecord); + expect(initialState).not.toBe(newState); + }); + }); + + describe('updateEditingTechRecordCancel', () => { + it('should clear the state', () => { + initialState.editingTechRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + } as unknown as TechRecordType<'put'>; + const action = updateEditingTechRecordCancel(); + const newState = vehicleTechRecordReducer(initialState, action); + + expect(initialState).not.toEqual(newState); + expect(newState.editingTechRecord).toBeUndefined(); + expect(initialState).not.toBe(newState); + }); + }); + + describe('Section state changes', () => { + it('should add the section name to the state', () => { + initialState.sectionState = []; + const action = addSectionState({ section: 'TEST_SECTION' }); + const newState = vehicleTechRecordReducer(initialState, action); + + expect(initialState).not.toEqual(newState); + expect(newState.sectionState).toEqual(['TEST_SECTION']); + expect(initialState).not.toBe(newState); + }); + + it('should avoid duplicating the section name', () => { + initialState.sectionState = ['TEST_SECTION']; + const action = addSectionState({ section: 'TEST_SECTION' }); + const newState = vehicleTechRecordReducer(initialState, action); + + expect(initialState).toEqual(newState); + expect(newState.sectionState).toEqual(['TEST_SECTION']); + expect(initialState).not.toBe(newState); + }); + + it('should remove the section name from the state', () => { + initialState.sectionState = ['TEST_SECTION1', 'TEST_SECTION2']; + const action = removeSectionState({ section: 'TEST_SECTION1' }); + const newState = vehicleTechRecordReducer(initialState, action); + + expect(initialState).not.toEqual(newState); + expect(newState.sectionState).toEqual(['TEST_SECTION2']); + expect(initialState).not.toBe(newState); + }); + + it('should clear all the section names from the state', () => { + initialState.sectionState = ['TEST_SECTION1', 'TEST_SECTION2']; + const action = clearAllSectionStates(); + const newState = vehicleTechRecordReducer(initialState, action); + + expect(initialState).not.toEqual(newState); + expect(newState.sectionState).toEqual([]); + expect(initialState).not.toBe(newState); + }); + }); + // TODO V3 HGV/PSV tests + describe('updating properties of the tech record in edit', () => { + beforeEach(() => { + initialState.editingTechRecord = mockVehicleTechnicalRecord(VehicleTypes.PSV) as TechRecordType<'put'>; + }); + + describe('updateBrakeForces', () => { + it('should not update half locked brake forces with no gross kerb weight', () => { + const asPSV = initialState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; + asPSV.techRecord_brakes_brakeCodeOriginal = '80'; + asPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_parkingBrakeForceB = 50; + asPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_secondaryBrakeForceB = 30; + asPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_serviceBrakeForceB = 10; + expect(asPSV.techRecord_brakes_brakeCode).toBe('1234'); + + const newState = vehicleTechRecordReducer(initialState, updateBrakeForces({ grossLadenWeight: 2000 })); + + const newPSV = newState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; + + expect(newPSV.techRecord_brakes_brakeCode).toBe(`0${2000 / 100}${asPSV.techRecord_brakes_brakeCodeOriginal}`); + + expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_serviceBrakeForceA).toBe( + Math.round((2000 * 16) / 100) + ); + expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_secondaryBrakeForceA).toBe( + Math.round((2000 * 22.5) / 100) + ); + expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_parkingBrakeForceA).toBe( + Math.round((2000 * 45) / 100) + ); + + expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_serviceBrakeForceB).toBe(10); + expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_secondaryBrakeForceB).toBe(30); + expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_parkingBrakeForceB).toBe(50); + }); + + it('should not update half locked brake forces with no gross laden weight', () => { + const asPSV = initialState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; + asPSV.techRecord_brakes_brakeCodeOriginal = '80'; + asPSV.techRecord_brakes_brakeForceWheelsNotLocked_parkingBrakeForceA = 50; + asPSV.techRecord_brakes_brakeForceWheelsNotLocked_secondaryBrakeForceA = 30; + asPSV.techRecord_brakes_brakeForceWheelsNotLocked_serviceBrakeForceA = 10; + + const newState = vehicleTechRecordReducer(initialState, updateBrakeForces({ grossKerbWeight: 1000 })); + + const newPSV = newState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; + + expect(newPSV.techRecord_brakes_brakeCode).toBe('1234'); + + expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_serviceBrakeForceA).toBe(10); + expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_secondaryBrakeForceA).toBe(30); + expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_parkingBrakeForceA).toBe(50); + + expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_serviceBrakeForceB).toBe( + Math.round((1000 * 16) / 100) + ); + expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_secondaryBrakeForceB).toBe( + Math.round((1000 * 25) / 100) + ); + expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_parkingBrakeForceB).toBe( + Math.round((1000 * 50) / 100) + ); + }); + + it('should not update brakeCode with no gross laden weight', () => { + const asPSV = initialState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; + asPSV.techRecord_brakes_brakeCodeOriginal = '80'; + asPSV.techRecord_brakes_brakeCode = '37'; + + const newState = vehicleTechRecordReducer(initialState, updateBrakeForces({ grossKerbWeight: 1000 })); + expect( + (newState?.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>).techRecord_brakes_brakeCode + ).toBe('37'); + }); + + it('should update brake forces', () => { + const asPSV = initialState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; + asPSV.techRecord_brakes_brakeCodeOriginal = '80'; + expect(asPSV.techRecord_brakes_brakeCode).toBe('1234'); + + const newState = vehicleTechRecordReducer( + initialState, + updateBrakeForces({ grossKerbWeight: 1000, grossLadenWeight: 2000 }) + ); + + expect(newState).not.toBe(initialState); + expect(newState).not.toEqual(initialState); + + const newPSV = newState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; + expect(newPSV.techRecord_brakes_brakeCode).toBe(`0${2000 / 100}${asPSV.techRecord_brakes_brakeCodeOriginal}`); + + expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_serviceBrakeForceA).toBe( + Math.round((2000 * 16) / 100) + ); + expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_secondaryBrakeForceA).toBe( + Math.round((2000 * 22.5) / 100) + ); + expect(newPSV.techRecord_brakes_brakeForceWheelsNotLocked_parkingBrakeForceA).toBe( + Math.round((2000 * 45) / 100) + ); + + expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_serviceBrakeForceB).toBe( + Math.round((1000 * 16) / 100) + ); + expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_secondaryBrakeForceB).toBe( + Math.round((1000 * 25) / 100) + ); + expect(newPSV.techRecord_brakes_brakeForceWheelsUpToHalfLocked_parkingBrakeForceB).toBe( + Math.round((1000 * 50) / 100) + ); + }); + }); + + describe('updateBody', () => { + it('should update body', () => { + expect( + (initialState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>).techRecord_bodyType_description + ).toBe(BodyTypeDescription.DOUBLE_DECKER); + + const expectedData = { + dtpNumber: '9999', + psvChassisMake: 'Toyota', + psvChassisModel: 'Supra', + psvBodyMake: 'Random', + psvBodyType: 'o', + } as PsvMake; + + const newState = vehicleTechRecordReducer(initialState, updateBody({ psvMake: expectedData })); + + expect(newState).not.toBe(initialState); + expect(newState).not.toEqual(initialState); + + const updatedTechRecord = newState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; + expect(updatedTechRecord?.techRecord_bodyType_code).toBe(BodyTypeCode.O); + expect(updatedTechRecord?.techRecord_bodyType_description).toBe(BodyTypeDescription.OTHER); + expect(updatedTechRecord?.techRecord_bodyMake).toBe(expectedData.psvBodyMake); + expect(updatedTechRecord?.techRecord_chassisMake).toBe(expectedData.psvChassisMake); + expect(updatedTechRecord?.techRecord_chassisModel).toBe(expectedData.psvChassisModel); + }); + }); + + describe('addAxle', () => { + describe('it should add an axle', () => { + it('with the axles property defined', () => { + const techRecord = initialState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; + expect(techRecord?.techRecord_noOfAxles).toBe(2); + expect(techRecord?.techRecord_axles?.length).toBe(3); + + const newState = vehicleTechRecordReducer(initialState, addAxle()); + + expect(newState).not.toBe(initialState); + expect(newState).not.toEqual(initialState); + + const updatedTechRecord = newState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; + expect(updatedTechRecord?.techRecord_noOfAxles).toBe(4); + expect(updatedTechRecord?.techRecord_axles?.length).toBe(4); + + const newAxleField = updatedTechRecord?.techRecord_axles ?? []; + + expect(newAxleField[3].tyres_dataTrAxles).toBeNull(); + expect(newAxleField[3].tyres_fitmentCode).toBeNull(); + expect(newAxleField[3].tyres_plyRating).toBeNull(); + expect(newAxleField[3].tyres_speedCategorySymbol).toBeNull(); + expect(newAxleField[3].tyres_tyreCode).toBeNull(); + expect(newAxleField[3].tyres_tyreSize).toBeNull(); + + expect(newAxleField[3].weights_designWeight).toBeDefined(); + expect(newAxleField[3].weights_gbWeight).toBeDefined(); + expect(newAxleField[3].weights_kerbWeight).toBeDefined(); + expect(newAxleField[3].weights_ladenWeight).toBeDefined(); + expect(updatedTechRecord?.techRecord_axles?.pop()?.axleNumber).toBe(4); + }); + + it('without the axles property defined', () => { + const techRecord = initialState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; + delete techRecord?.techRecord_axles; + techRecord.techRecord_noOfAxles = 0; + expect(techRecord?.techRecord_noOfAxles).toBe(0); + + const newState = vehicleTechRecordReducer(initialState, addAxle()); + + expect(newState).not.toBe(initialState); + expect(newState).not.toEqual(initialState); + + const updatedTechRecord = newState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; + expect(updatedTechRecord?.techRecord_noOfAxles).toBe(1); + expect(updatedTechRecord?.techRecord_axles?.length).toBe(1); + + const newAxleField = updatedTechRecord?.techRecord_axles || []; + + expect(newAxleField[0].tyres_dataTrAxles).toBeNull(); + expect(newAxleField[0].tyres_fitmentCode).toBeNull(); + expect(newAxleField[0].tyres_plyRating).toBeNull(); + expect(newAxleField[0].tyres_speedCategorySymbol).toBeNull(); + expect(newAxleField[0].tyres_tyreCode).toBeNull(); + expect(newAxleField[0].tyres_tyreSize).toBeNull(); + + expect(newAxleField[0].weights_designWeight).toBeDefined(); + expect(newAxleField[0].weights_gbWeight).toBeDefined(); + expect(newAxleField[0].weights_kerbWeight).toBeDefined(); + expect(newAxleField[0].weights_ladenWeight).toBeDefined(); + expect(updatedTechRecord?.techRecord_axles?.pop()?.axleNumber).toBe(1); + }); + }); + }); + + describe('removeAxle', () => { + it('should remove specified axle', () => { + const techRecord = initialState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; + expect(techRecord?.techRecord_noOfAxles).toBe(2); + expect(techRecord?.techRecord_axles?.length).toBe(3); + + const newState = vehicleTechRecordReducer(initialState, removeAxle({ index: 0 })); + + expect(newState).not.toBe(initialState); + expect(newState).not.toEqual(initialState); + + const updatedTechRecord = newState.editingTechRecord as TechRecordTypeVehicleVerb<'psv', 'put'>; + expect(updatedTechRecord?.techRecord_noOfAxles).toBe(2); + expect(updatedTechRecord?.techRecord_axles?.length).toBe(2); + expect(updatedTechRecord?.techRecord_axles?.pop()?.axleNumber).toBe(2); + }); + }); + describe('updateScrollPosition', () => { + it('should update the scroll position state', () => { + const newState = vehicleTechRecordReducer(initialState, updateScrollPosition({ position: [1, 2] })); + + expect(newState.scrollPosition).toEqual([1, 2]); + }); + }); + describe('clearScrollPosition', () => { + it('should reset the scroll position', () => { + initialState.scrollPosition = [2, 2]; + const newState = vehicleTechRecordReducer(initialState, clearScrollPosition()); + + expect(newState.scrollPosition).toEqual([0, 0]); + }); + }); + }); + + describe('clearADRDetailsBeforeUpdate', () => { + it('should set all ADR fields to null when: vehicleType = HGV and dangerousGoods = false', () => { + initialState.editingTechRecord = createMockHgv(1234) as TechRecordPUTHGV; + initialState.editingTechRecord.techRecord_adrDetails_dangerousGoods = false; + initialState.editingTechRecord.techRecord_adrDetails_applicantDetails_city = 'Test City'; + + const newState = vehicleTechRecordReducer(initialState, clearADRDetailsBeforeUpdate()); + expect(newState.editingTechRecord).toBeDefined(); + expect((newState.editingTechRecord as TechRecordPUTHGV).techRecord_adrDetails_applicantDetails_city).toBeNull(); + }); + + it('should set all ADR fields to null when: vehicleType = TRL and dangerousGoods = false', () => { + initialState.editingTechRecord = createMockTrl(1234) as TechRecordPUTTRL; + initialState.editingTechRecord.techRecord_adrDetails_dangerousGoods = false; + initialState.editingTechRecord.techRecord_adrDetails_applicantDetails_street = 'Test Street'; + + const newState = vehicleTechRecordReducer(initialState, clearADRDetailsBeforeUpdate()); + expect(newState.editingTechRecord).toBeDefined(); + expect((newState.editingTechRecord as TechRecordPUTTRL).techRecord_adrDetails_applicantDetails_street).toBeNull(); + }); + + it('should set all ADR fields to null when: vehicleType = LGV and dangerousGoods = false', () => { + initialState.editingTechRecord = createMockLgv(1234) as TechRecordPUTLGV; + initialState.editingTechRecord.techRecord_adrDetails_dangerousGoods = false; + initialState.editingTechRecord.techRecord_adrDetails_adrCertificateNotes = 'Test notes'; + + const newState = vehicleTechRecordReducer(initialState, clearADRDetailsBeforeUpdate()); + expect(newState.editingTechRecord).toBeDefined(); + expect((newState.editingTechRecord as TechRecordPUTLGV).techRecord_adrDetails_applicantDetails_street).toBeNull(); + }); + + it('should not set all ADR fields to null when: vehicleType = HGV and dangerousGoods = true', () => { + initialState.editingTechRecord = createMockHgv(1234) as TechRecordPUTHGV; + initialState.editingTechRecord.techRecord_adrDetails_dangerousGoods = true; + initialState.editingTechRecord.techRecord_adrDetails_applicantDetails_town = 'Test Town'; + + const newState = vehicleTechRecordReducer(initialState, clearADRDetailsBeforeUpdate()); + expect(newState.editingTechRecord).toBeDefined(); + expect((newState.editingTechRecord as TechRecordPUTHGV).techRecord_adrDetails_applicantDetails_town).toBe( + 'Test Town' + ); + }); + + it('should not set all ADR fields to null when: vehicleType = TRL and dangerousGoods = true', () => { + initialState.editingTechRecord = createMockTrl(1234) as TechRecordPUTTRL; + initialState.editingTechRecord.techRecord_adrDetails_dangerousGoods = true; + initialState.editingTechRecord.techRecord_adrDetails_applicantDetails_postcode = 'Test Postcode'; + + const newState = vehicleTechRecordReducer(initialState, clearADRDetailsBeforeUpdate()); + expect(newState.editingTechRecord).toBeDefined(); + expect((newState.editingTechRecord as TechRecordPUTTRL).techRecord_adrDetails_applicantDetails_postcode).toBe( + 'Test Postcode' + ); + }); + + it('should not set all ADR fields to null when: vehicleType = LGV and dangerousGoods = true', () => { + initialState.editingTechRecord = createMockLgv(1234) as TechRecordPUTLGV; + initialState.editingTechRecord.techRecord_adrDetails_dangerousGoods = true; + initialState.editingTechRecord.techRecord_adrDetails_adrCertificateNotes = 'Test notes'; + + const newState = vehicleTechRecordReducer(initialState, clearADRDetailsBeforeUpdate()); + expect(newState.editingTechRecord).toBeDefined(); + expect((newState.editingTechRecord as TechRecordPUTLGV).techRecord_adrDetails_adrCertificateNotes).toBe( + 'Test notes' + ); + }); + }); + describe('handleADRExaminerNoteChanges', () => { + beforeEach(() => { + const mockedDate = new Date(2024, 5, 20); + jest.useFakeTimers(); + jest.setSystemTime(mockedDate); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + it('should handle any changes made to the adr examiner notes', () => { + const testNote = { + note: 'testNote', + createdAtDate: new Date().toISOString(), + lastUpdatedBy: 'someone', + }; + const state: TechnicalRecordServiceState = { + ...initialState, + vehicleTechRecord: { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + } as unknown as TechRecordType<'get'>, + editingTechRecord: { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_adrDetails_additionalExaminerNotes_note: testNote.note, + } as unknown as TechRecordType<'put'>, + loading: true, + }; + const action = updateADRAdditionalExaminerNotes({ username: testNote.lastUpdatedBy }); + const newState = vehicleTechRecordReducer(state, action); + expect( + (newState.editingTechRecord as unknown as NonVerbTechRecordType<'hgv' | 'lgv' | 'trl'>) + ?.techRecord_adrDetails_additionalExaminerNotes + ).toContainEqual(testNote); + }); + }); + describe('handleUpdateExistingADRExaminerNote', () => { + it('should', () => { + const state: TechnicalRecordServiceState = { + ...initialState, + editingTechRecord: { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_adrDetails_additionalExaminerNotes: [ + { + note: 'foo', + createdAtDate: 'bar', + lastUpdatedBy: 'foo', + }, + ], + } as unknown as TechRecordType<'put'>, + loading: true, + }; + const newNote = 'foobar'; + const action = updateExistingADRAdditionalExaminerNote({ additionalExaminerNote: newNote, examinerNoteIndex: 0 }); + const newState = vehicleTechRecordReducer(state, action); + const editingTechRecord = newState.editingTechRecord as unknown as NonVerbTechRecordType<'hgv' | 'lgv' | 'trl'>; + expect(editingTechRecord.techRecord_adrDetails_additionalExaminerNotes![0].note).toEqual(newNote); + }); + }); }); diff --git a/src/app/store/technical-records/reducers/technical-record-service.reducer.ts b/src/app/store/technical-records/reducers/technical-record-service.reducer.ts index 320ce60951..26c805c29d 100644 --- a/src/app/store/technical-records/reducers/technical-record-service.reducer.ts +++ b/src/app/store/technical-records/reducers/technical-record-service.reducer.ts @@ -12,556 +12,600 @@ import { createFeatureSelector, createReducer, on } from '@ngrx/store'; import { AxlesService } from '@services/axles/axles.service'; import { cloneDeep } from 'lodash'; import { - clearBatch, - setApplicationId, - setGenerateNumberFlag, - setVehicleStatus, - setVehicleType, - upsertVehicleBatch, + clearBatch, + setApplicationId, + setGenerateNumberFlag, + setVehicleStatus, + setVehicleType, + upsertVehicleBatch, } from '../actions/batch-create.actions'; import { - addAxle, - addSectionState, amendVin, amendVinFailure, amendVinSuccess, - amendVrm, - amendVrmFailure, - amendVrmSuccess, - archiveTechRecord, - archiveTechRecordFailure, - archiveTechRecordSuccess, - canGeneratePlate, - cannotGeneratePlate, - clearADRDetailsBeforeUpdate, - clearAllSectionStates, - clearScrollPosition, - createVehicleRecord, - createVehicleRecordFailure, - createVehicleRecordSuccess, - generateADRCertificate, - generateADRCertificateFailure, - generateADRCertificateSuccess, - generateContingencyADRCertificate, - generateLetter, - generateLetterFailure, - generateLetterSuccess, - generatePlate, - generatePlateFailure, - generatePlateSuccess, - getBySystemNumber, - getBySystemNumberFailure, - getBySystemNumberSuccess, - getTechRecordV3Success, - promoteTechRecord, - promoteTechRecordFailure, - promoteTechRecordSuccess, - removeAxle, - removeSectionState, - unarchiveTechRecord, - unarchiveTechRecordFailure, - unarchiveTechRecordSuccess, updateADRAdditionalExaminerNotes, - updateBody, - updateBrakeForces, - updateEditingTechRecord, - updateEditingTechRecordCancel, updateExistingADRAdditionalExaminerNote, - updateScrollPosition, - updateTechRecord, - updateTechRecordFailure, - updateTechRecordSuccess, + addAxle, + addSectionState, + amendVin, + amendVinFailure, + amendVinSuccess, + amendVrm, + amendVrmFailure, + amendVrmSuccess, + archiveTechRecord, + archiveTechRecordFailure, + archiveTechRecordSuccess, + canGeneratePlate, + cannotGeneratePlate, + clearADRDetailsBeforeUpdate, + clearAllSectionStates, + clearScrollPosition, + createVehicleRecord, + createVehicleRecordFailure, + createVehicleRecordSuccess, + generateADRCertificate, + generateADRCertificateFailure, + generateADRCertificateSuccess, + generateContingencyADRCertificate, + generateLetter, + generateLetterFailure, + generateLetterSuccess, + generatePlate, + generatePlateFailure, + generatePlateSuccess, + getBySystemNumber, + getBySystemNumberFailure, + getBySystemNumberSuccess, + getTechRecordV3Success, + promoteTechRecord, + promoteTechRecordFailure, + promoteTechRecordSuccess, + removeAxle, + removeSectionState, + unarchiveTechRecord, + unarchiveTechRecordFailure, + unarchiveTechRecordSuccess, + updateADRAdditionalExaminerNotes, + updateBody, + updateBrakeForces, + updateEditingTechRecord, + updateEditingTechRecordCancel, + updateExistingADRAdditionalExaminerNote, + updateScrollPosition, + updateTechRecord, + updateTechRecordFailure, + updateTechRecordSuccess, } from '../actions/technical-record-service.actions'; import { BatchRecords, initialBatchState, vehicleBatchCreateReducer } from './batch-create.reducer'; export const STORE_FEATURE_TECHNICAL_RECORDS_KEY = 'TechnicalRecords'; export interface TechnicalRecordServiceState { - vehicleTechRecord: TechRecordType<'get'> | undefined; - loading: boolean; - editingTechRecord?: TechRecordType<'put'>; - error?: unknown; - techRecordHistory?: TechRecordSearchSchema[]; - batchVehicles: BatchRecords; - sectionState?: (string | number)[]; - canGeneratePlate: boolean; - scrollPosition: [number, number]; + vehicleTechRecord: TechRecordType<'get'> | undefined; + loading: boolean; + editingTechRecord?: TechRecordType<'put'>; + error?: unknown; + techRecordHistory?: TechRecordSearchSchema[]; + batchVehicles: BatchRecords; + sectionState?: (string | number)[]; + canGeneratePlate: boolean; + scrollPosition: [number, number]; } export const initialState: TechnicalRecordServiceState = { - vehicleTechRecord: undefined, - batchVehicles: initialBatchState, - loading: false, - sectionState: [], - canGeneratePlate: false, - scrollPosition: [0, 0], + vehicleTechRecord: undefined, + batchVehicles: initialBatchState, + loading: false, + sectionState: [], + canGeneratePlate: false, + scrollPosition: [0, 0], }; -export const getTechRecordState = createFeatureSelector(STORE_FEATURE_TECHNICAL_RECORDS_KEY); +export const getTechRecordState = createFeatureSelector( + STORE_FEATURE_TECHNICAL_RECORDS_KEY +); export const vehicleTechRecordReducer = createReducer( - initialState, - - on(createVehicleRecord, defaultArgs), - on(createVehicleRecordSuccess, successArgs), - on(createVehicleRecordFailure, (state) => ({ ...state, loading: false })), - - on(getBySystemNumber, (state) => ({ ...state, loading: true })), - on(getBySystemNumberSuccess, (state, action) => ({ ...state, loading: false, techRecordHistory: action.techRecordHistory })), - on(getBySystemNumberFailure, (state) => ({ ...state, loading: false, techRecordHistory: [] })), - - on(updateTechRecord, defaultArgs), - on(updateTechRecordSuccess, successArgs), - on(updateTechRecordFailure, updateFailureArgs), - - on(archiveTechRecord, defaultArgs), - on(archiveTechRecordSuccess, successArgs), - on(archiveTechRecordFailure, updateFailureArgs), - - on(unarchiveTechRecord, defaultArgs), - on(unarchiveTechRecordSuccess, successArgs), - on(unarchiveTechRecordFailure, updateFailureArgs), - - on(promoteTechRecord, defaultArgs), - on(promoteTechRecordSuccess, successArgs), - on(promoteTechRecordFailure, updateFailureArgs), - - on(amendVrm, defaultArgs), - on(amendVrmSuccess, successArgs), - on(amendVrmFailure, updateFailureArgs), - - on(amendVin, defaultArgs), - on(amendVinSuccess, successArgs), - on(amendVinFailure, updateFailureArgs), - - on(generatePlate, defaultArgs), - on(generatePlateSuccess, (state) => ({ ...state, editingTechRecord: undefined, loading: false })), - on(generatePlateFailure, failureArgs), - on(canGeneratePlate, (state) => ({ ...state, canGeneratePlate: true })), - on(cannotGeneratePlate, (state) => ({ ...state, canGeneratePlate: false })), - - on(generateLetter, defaultArgs), - on(generateLetterSuccess, (state) => ({ ...state, editingTechRecord: undefined })), - on(generateLetterFailure, failureArgs), - - on(generateADRCertificate, defaultArgs), - on(generateContingencyADRCertificate, defaultArgs), - on(generateADRCertificateSuccess, (state) => ({ ...state, editingTechRecord: undefined, loading: false })), - on(generateADRCertificateFailure, failureArgs), - - on(updateEditingTechRecord, (state, action) => updateEditingTechRec(state, action)), - on(updateEditingTechRecordCancel, (state) => ({ ...state, editingTechRecord: undefined })), - - on(updateBrakeForces, (state, action) => handleUpdateBrakeForces(state, action)), - - on(updateBody, (state, action) => handleUpdateBody(state, action)), - - on(updateADRAdditionalExaminerNotes, (state, action) => handleADRExaminerNoteChanges(state, action.username)), - - on(updateExistingADRAdditionalExaminerNote, (state, action) => handleUpdateExistingADRExaminerNote(state, action)), - - on(addAxle, (state) => handleAddAxle(state)), - on(removeAxle, (state, action) => handleRemoveAxle(state, action)), - - on(addSectionState, (state, action) => handleAddSection(state, action)), - on(removeSectionState, (state, action) => handleRemoveSection(state, action)), - on(clearAllSectionStates, (state) => ({ ...state, sectionState: [] })), - - on( - upsertVehicleBatch, - createVehicleRecordSuccess, - updateTechRecordSuccess, - setApplicationId, - setVehicleStatus, - setVehicleType, - setGenerateNumberFlag, - clearBatch, - (state, action) => ({ - ...state, - batchVehicles: vehicleBatchCreateReducer(state.batchVehicles, action), - }), - ), - - on(getTechRecordV3Success, (state, action) => ({ ...state, vehicleTechRecord: action.vehicleTechRecord })), - - on(updateScrollPosition, (state, action) => ({ ...state, scrollPosition: action.position })), - on(clearScrollPosition, (state) => ({ ...state, scrollPosition: [0, 0] as [number, number] })), - - on(clearADRDetailsBeforeUpdate, (state) => handleClearADRDetails(state)), + initialState, + + on(createVehicleRecord, defaultArgs), + on(createVehicleRecordSuccess, successArgs), + on(createVehicleRecordFailure, (state) => ({ ...state, loading: false })), + + on(getBySystemNumber, (state) => ({ ...state, loading: true })), + on(getBySystemNumberSuccess, (state, action) => ({ + ...state, + loading: false, + techRecordHistory: action.techRecordHistory, + })), + on(getBySystemNumberFailure, (state) => ({ ...state, loading: false, techRecordHistory: [] })), + + on(updateTechRecord, defaultArgs), + on(updateTechRecordSuccess, successArgs), + on(updateTechRecordFailure, updateFailureArgs), + + on(archiveTechRecord, defaultArgs), + on(archiveTechRecordSuccess, successArgs), + on(archiveTechRecordFailure, updateFailureArgs), + + on(unarchiveTechRecord, defaultArgs), + on(unarchiveTechRecordSuccess, successArgs), + on(unarchiveTechRecordFailure, updateFailureArgs), + + on(promoteTechRecord, defaultArgs), + on(promoteTechRecordSuccess, successArgs), + on(promoteTechRecordFailure, updateFailureArgs), + + on(amendVrm, defaultArgs), + on(amendVrmSuccess, successArgs), + on(amendVrmFailure, updateFailureArgs), + + on(amendVin, defaultArgs), + on(amendVinSuccess, successArgs), + on(amendVinFailure, updateFailureArgs), + + on(generatePlate, defaultArgs), + on(generatePlateSuccess, (state) => ({ ...state, editingTechRecord: undefined, loading: false })), + on(generatePlateFailure, failureArgs), + on(canGeneratePlate, (state) => ({ ...state, canGeneratePlate: true })), + on(cannotGeneratePlate, (state) => ({ ...state, canGeneratePlate: false })), + + on(generateLetter, defaultArgs), + on(generateLetterSuccess, (state) => ({ ...state, editingTechRecord: undefined })), + on(generateLetterFailure, failureArgs), + + on(generateADRCertificate, defaultArgs), + on(generateContingencyADRCertificate, defaultArgs), + on(generateADRCertificateSuccess, (state) => ({ ...state, editingTechRecord: undefined, loading: false })), + on(generateADRCertificateFailure, failureArgs), + + on(updateEditingTechRecord, (state, action) => updateEditingTechRec(state, action)), + on(updateEditingTechRecordCancel, (state) => ({ ...state, editingTechRecord: undefined })), + + on(updateBrakeForces, (state, action) => handleUpdateBrakeForces(state, action)), + + on(updateBody, (state, action) => handleUpdateBody(state, action)), + + on(updateADRAdditionalExaminerNotes, (state, action) => handleADRExaminerNoteChanges(state, action.username)), + + on(updateExistingADRAdditionalExaminerNote, (state, action) => handleUpdateExistingADRExaminerNote(state, action)), + + on(addAxle, (state) => handleAddAxle(state)), + on(removeAxle, (state, action) => handleRemoveAxle(state, action)), + + on(addSectionState, (state, action) => handleAddSection(state, action)), + on(removeSectionState, (state, action) => handleRemoveSection(state, action)), + on(clearAllSectionStates, (state) => ({ ...state, sectionState: [] })), + + on( + upsertVehicleBatch, + createVehicleRecordSuccess, + updateTechRecordSuccess, + setApplicationId, + setVehicleStatus, + setVehicleType, + setGenerateNumberFlag, + clearBatch, + (state, action) => ({ + ...state, + batchVehicles: vehicleBatchCreateReducer(state.batchVehicles, action), + }) + ), + + on(getTechRecordV3Success, (state, action) => ({ ...state, vehicleTechRecord: action.vehicleTechRecord })), + + on(updateScrollPosition, (state, action) => ({ ...state, scrollPosition: action.position })), + on(clearScrollPosition, (state) => ({ ...state, scrollPosition: [0, 0] as [number, number] })), + + on(clearADRDetailsBeforeUpdate, (state) => handleClearADRDetails(state)) ); function defaultArgs(state: TechnicalRecordServiceState) { - return { ...state, loading: true }; + return { ...state, loading: true }; } function successArgs(state: TechnicalRecordServiceState, data: { vehicleTechRecord: TechRecordType<'get'> }) { - return { ...state, vehicleTechRecord: data.vehicleTechRecord, loading: false }; + return { ...state, vehicleTechRecord: data.vehicleTechRecord, loading: false }; } function updateFailureArgs(state: TechnicalRecordServiceState, data: { error: unknown }) { - return { ...state, error: data.error, loading: false }; + return { ...state, error: data.error, loading: false }; } function failureArgs(state: TechnicalRecordServiceState, data: { error: unknown }) { - return { - ...state, vehicleTechRecord: undefined, error: data.error, loading: false, - }; + return { + ...state, + vehicleTechRecord: undefined, + error: data.error, + loading: false, + }; } function handleUpdateBrakeForces( - state: TechnicalRecordServiceState, - data: { grossLadenWeight?: number; grossKerbWeight?: number }, + state: TechnicalRecordServiceState, + data: { grossLadenWeight?: number; grossKerbWeight?: number } ): TechnicalRecordServiceState { - const newState = cloneDeep(state); - if (!newState.editingTechRecord) return newState; - if (newState.editingTechRecord.techRecord_vehicleType !== 'psv') { - return newState; - } - - if (data.grossLadenWeight) { - const prefix = `${Math.round(data.grossLadenWeight / 100)}`; - - newState.editingTechRecord.techRecord_brakes_brakeCode = (prefix.length <= 2 - ? `0${prefix}` - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - : prefix) + newState.editingTechRecord.techRecord_brakes_brakeCodeOriginal!; - newState.editingTechRecord.techRecord_brakes_brakeForceWheelsNotLocked_serviceBrakeForceA = Math.round((data.grossLadenWeight * 16) / 100); - newState.editingTechRecord.techRecord_brakes_brakeForceWheelsNotLocked_secondaryBrakeForceA = Math.round((data.grossLadenWeight * 22.5) / 100); - newState.editingTechRecord.techRecord_brakes_brakeForceWheelsNotLocked_parkingBrakeForceA = Math.round((data.grossLadenWeight * 45) / 100); - } - - if (data.grossKerbWeight) { - newState.editingTechRecord.techRecord_brakes_brakeForceWheelsUpToHalfLocked_serviceBrakeForceB = Math.round((data.grossKerbWeight * 16) / 100); - newState.editingTechRecord.techRecord_brakes_brakeForceWheelsUpToHalfLocked_secondaryBrakeForceB = Math.round((data.grossKerbWeight * 25) / 100); - newState.editingTechRecord.techRecord_brakes_brakeForceWheelsUpToHalfLocked_parkingBrakeForceB = Math.round((data.grossKerbWeight * 50) / 100); - } - - return newState; + const newState = cloneDeep(state); + if (!newState.editingTechRecord) return newState; + if (newState.editingTechRecord.techRecord_vehicleType !== 'psv') { + return newState; + } + + if (data.grossLadenWeight) { + const prefix = `${Math.round(data.grossLadenWeight / 100)}`; + + newState.editingTechRecord.techRecord_brakes_brakeCode = + (prefix.length <= 2 + ? `0${prefix}` + : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + prefix) + newState.editingTechRecord.techRecord_brakes_brakeCodeOriginal!; + newState.editingTechRecord.techRecord_brakes_brakeForceWheelsNotLocked_serviceBrakeForceA = Math.round( + (data.grossLadenWeight * 16) / 100 + ); + newState.editingTechRecord.techRecord_brakes_brakeForceWheelsNotLocked_secondaryBrakeForceA = Math.round( + (data.grossLadenWeight * 22.5) / 100 + ); + newState.editingTechRecord.techRecord_brakes_brakeForceWheelsNotLocked_parkingBrakeForceA = Math.round( + (data.grossLadenWeight * 45) / 100 + ); + } + + if (data.grossKerbWeight) { + newState.editingTechRecord.techRecord_brakes_brakeForceWheelsUpToHalfLocked_serviceBrakeForceB = Math.round( + (data.grossKerbWeight * 16) / 100 + ); + newState.editingTechRecord.techRecord_brakes_brakeForceWheelsUpToHalfLocked_secondaryBrakeForceB = Math.round( + (data.grossKerbWeight * 25) / 100 + ); + newState.editingTechRecord.techRecord_brakes_brakeForceWheelsUpToHalfLocked_parkingBrakeForceB = Math.round( + (data.grossKerbWeight * 50) / 100 + ); + } + + return newState; } -function handleUpdateBody(state: TechnicalRecordServiceState, action: { psvMake: PsvMake }): TechnicalRecordServiceState { - const newState = cloneDeep(state); +function handleUpdateBody( + state: TechnicalRecordServiceState, + action: { psvMake: PsvMake } +): TechnicalRecordServiceState { + const newState = cloneDeep(state); - if (!newState.editingTechRecord) return newState; - if (newState.editingTechRecord.techRecord_vehicleType !== 'psv') { - return newState; - } + if (!newState.editingTechRecord) return newState; + if (newState.editingTechRecord.techRecord_vehicleType !== 'psv') { + return newState; + } - const code = action.psvMake.psvBodyType.toLowerCase() as BodyTypeCode; + const code = action.psvMake.psvBodyType.toLowerCase() as BodyTypeCode; - newState.editingTechRecord.techRecord_bodyType_code = code; - newState.editingTechRecord.techRecord_bodyType_description = vehicleBodyTypeCodeMap.get(VehicleTypes.PSV)?.get(code); - newState.editingTechRecord.techRecord_bodyMake = action.psvMake.psvBodyMake; - newState.editingTechRecord.techRecord_chassisMake = action.psvMake.psvChassisMake; - newState.editingTechRecord.techRecord_chassisModel = action.psvMake.psvChassisModel; + newState.editingTechRecord.techRecord_bodyType_code = code; + newState.editingTechRecord.techRecord_bodyType_description = vehicleBodyTypeCodeMap.get(VehicleTypes.PSV)?.get(code); + newState.editingTechRecord.techRecord_bodyMake = action.psvMake.psvBodyMake; + newState.editingTechRecord.techRecord_chassisMake = action.psvMake.psvChassisMake; + newState.editingTechRecord.techRecord_chassisModel = action.psvMake.psvChassisModel; - return newState; + return newState; } function handleAddAxle(state: TechnicalRecordServiceState): TechnicalRecordServiceState { - const newState = cloneDeep(state); - - if (!newState.editingTechRecord) return newState; - if ( - newState.editingTechRecord.techRecord_vehicleType === 'car' - || newState.editingTechRecord.techRecord_vehicleType === 'lgv' - || newState.editingTechRecord.techRecord_vehicleType === 'motorcycle' - ) { - return newState; - } - if (!newState.editingTechRecord.techRecord_axles) newState.editingTechRecord.techRecord_axles = []; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const newAxle: any = { - axleNumber: newState.editingTechRecord.techRecord_axles.length + 1, - tyres_tyreSize: null, - tyres_fitmentCode: null, - tyres_dataTrAxles: null, - tyres_plyRating: null, - tyres_tyreCode: null, - weights_gbWeight: null, - weights_designWeight: null, - parkingBrakeMrk: false, - }; - - if ( - newState.editingTechRecord.techRecord_vehicleType === VehicleTypes.HGV - || newState.editingTechRecord.techRecord_vehicleType === VehicleTypes.TRL - ) { - newAxle.weights_eecWeight = null; - } - if (newState.editingTechRecord.techRecord_vehicleType === VehicleTypes.PSV) { - newAxle.weights_kerbWeight = null; - newAxle.weights_ladenWeight = null; - newAxle.tyres_speedCategorySymbol = null; - } - - newState.editingTechRecord.techRecord_axles.push(newAxle); - - newState.editingTechRecord.techRecord_noOfAxles = newState.editingTechRecord.techRecord_axles.length; - - if ( - newState.editingTechRecord.techRecord_vehicleType === VehicleTypes.HGV - || newState.editingTechRecord.techRecord_vehicleType === VehicleTypes.TRL - ) { - newState.editingTechRecord.techRecord_dimensions_axleSpacing = new AxlesService().generateAxleSpacing( - newState.editingTechRecord.techRecord_axles.length, - newState.editingTechRecord.techRecord_dimensions_axleSpacing, - ); - } - - return newState; + const newState = cloneDeep(state); + + if (!newState.editingTechRecord) return newState; + if ( + newState.editingTechRecord.techRecord_vehicleType === 'car' || + newState.editingTechRecord.techRecord_vehicleType === 'lgv' || + newState.editingTechRecord.techRecord_vehicleType === 'motorcycle' + ) { + return newState; + } + if (!newState.editingTechRecord.techRecord_axles) newState.editingTechRecord.techRecord_axles = []; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const newAxle: any = { + axleNumber: newState.editingTechRecord.techRecord_axles.length + 1, + tyres_tyreSize: null, + tyres_fitmentCode: null, + tyres_dataTrAxles: null, + tyres_plyRating: null, + tyres_tyreCode: null, + weights_gbWeight: null, + weights_designWeight: null, + parkingBrakeMrk: false, + }; + + if ( + newState.editingTechRecord.techRecord_vehicleType === VehicleTypes.HGV || + newState.editingTechRecord.techRecord_vehicleType === VehicleTypes.TRL + ) { + newAxle.weights_eecWeight = null; + } + if (newState.editingTechRecord.techRecord_vehicleType === VehicleTypes.PSV) { + newAxle.weights_kerbWeight = null; + newAxle.weights_ladenWeight = null; + newAxle.tyres_speedCategorySymbol = null; + } + + newState.editingTechRecord.techRecord_axles.push(newAxle); + + newState.editingTechRecord.techRecord_noOfAxles = newState.editingTechRecord.techRecord_axles.length; + + if ( + newState.editingTechRecord.techRecord_vehicleType === VehicleTypes.HGV || + newState.editingTechRecord.techRecord_vehicleType === VehicleTypes.TRL + ) { + newState.editingTechRecord.techRecord_dimensions_axleSpacing = new AxlesService().generateAxleSpacing( + newState.editingTechRecord.techRecord_axles.length, + newState.editingTechRecord.techRecord_dimensions_axleSpacing + ); + } + + return newState; } function handleRemoveAxle(state: TechnicalRecordServiceState, action: { index: number }): TechnicalRecordServiceState { - const newState = cloneDeep(state); - if ( - !newState.editingTechRecord - || newState.editingTechRecord.techRecord_vehicleType === 'car' - || newState.editingTechRecord.techRecord_vehicleType === 'lgv' - || newState.editingTechRecord.techRecord_vehicleType === 'motorcycle' - || !newState.editingTechRecord.techRecord_axles - || !newState.editingTechRecord.techRecord_axles.length - ) { - return newState; - } - - newState.editingTechRecord.techRecord_axles.splice(action.index, 1); - - // eslint-disable-next-line no-return-assign - newState.editingTechRecord.techRecord_axles.forEach((axle, i) => (axle.axleNumber = i + 1)); - - newState.editingTechRecord.techRecord_noOfAxles = newState.editingTechRecord.techRecord_axles.length; - - if ( - newState.editingTechRecord?.techRecord_vehicleType === VehicleTypes.HGV - || newState.editingTechRecord?.techRecord_vehicleType === VehicleTypes.TRL - ) { - newState.editingTechRecord.techRecord_dimensions_axleSpacing = new AxlesService().generateAxleSpacing( - newState.editingTechRecord.techRecord_axles.length, - ); - } - - return newState; + const newState = cloneDeep(state); + if ( + !newState.editingTechRecord || + newState.editingTechRecord.techRecord_vehicleType === 'car' || + newState.editingTechRecord.techRecord_vehicleType === 'lgv' || + newState.editingTechRecord.techRecord_vehicleType === 'motorcycle' || + !newState.editingTechRecord.techRecord_axles || + !newState.editingTechRecord.techRecord_axles.length + ) { + return newState; + } + + newState.editingTechRecord.techRecord_axles.splice(action.index, 1); + + // eslint-disable-next-line no-return-assign + newState.editingTechRecord.techRecord_axles.forEach((axle, i) => (axle.axleNumber = i + 1)); + + newState.editingTechRecord.techRecord_noOfAxles = newState.editingTechRecord.techRecord_axles.length; + + if ( + newState.editingTechRecord?.techRecord_vehicleType === VehicleTypes.HGV || + newState.editingTechRecord?.techRecord_vehicleType === VehicleTypes.TRL + ) { + newState.editingTechRecord.techRecord_dimensions_axleSpacing = new AxlesService().generateAxleSpacing( + newState.editingTechRecord.techRecord_axles.length + ); + } + + return newState; } function handleAddSection(state: TechnicalRecordServiceState, action: { section: string | number }) { - const newState = cloneDeep(state); - if (newState.sectionState?.includes(action.section)) return newState; - return { ...newState, sectionState: newState.sectionState?.concat(action.section) }; + const newState = cloneDeep(state); + if (newState.sectionState?.includes(action.section)) return newState; + return { ...newState, sectionState: newState.sectionState?.concat(action.section) }; } function handleRemoveSection(state: TechnicalRecordServiceState, action: { section: string | number }) { - const newState = cloneDeep(state); - if (!newState.sectionState?.includes(action.section)) return newState; - return { ...newState, sectionState: newState.sectionState?.filter((section) => section !== action.section) }; + const newState = cloneDeep(state); + if (!newState.sectionState?.includes(action.section)) return newState; + return { ...newState, sectionState: newState.sectionState?.filter((section) => section !== action.section) }; } -function updateEditingTechRec(state: TechnicalRecordServiceState, action: { vehicleTechRecord: TechRecordType<'put'> }) { - const newState = { ...state }; - const { editingTechRecord } = state; - const { vehicleTechRecord } = action; +function updateEditingTechRec( + state: TechnicalRecordServiceState, + action: { vehicleTechRecord: TechRecordType<'put'> } +) { + const newState = { ...state }; + const { editingTechRecord } = state; + const { vehicleTechRecord } = action; - newState.editingTechRecord = { ...editingTechRecord, ...vehicleTechRecord } as TechRecordType<'put'>; + newState.editingTechRecord = { ...editingTechRecord, ...vehicleTechRecord } as TechRecordType<'put'>; - return newState; + return newState; } function handleClearADRDetails(state: TechnicalRecordServiceState) { - const { editingTechRecord } = state; - - if (editingTechRecord) { - const { techRecord_vehicleType: type } = editingTechRecord; - if (type === VehicleTypes.HGV || type === VehicleTypes.TRL || type === VehicleTypes.LGV) { - const nulledCompatibilityGroupJ = { - techRecord_adrDetails_compatibilityGroupJ: null, - }; - - const nulledTankDetails = { - techRecord_adrDetails_tank_tankDetails_tankManufacturer: null, - techRecord_adrDetails_tank_tankDetails_yearOfManufacture: null, - techRecord_adrDetails_tank_tankDetails_tankManufacturerSerialNo: null, - techRecord_adrDetails_tank_tankDetails_tankTypeAppNo: null, - techRecord_adrDetails_tank_tankDetails_tankCode: null, - techRecord_adrDetails_tank_tankDetails_specialProvisions: null, - techRecord_adrDetails_tank_tankDetails_tc2Details_tc2Type: null, - techRecord_adrDetails_tank_tankDetails_tc2Details_tc2IntermediateApprovalNo: null, - techRecord_adrDetails_tank_tankDetails_tc2Details_tc2IntermediateExpiryDate: null, - techRecord_adrDetails_tank_tankDetails_tc3Details: null, - techRecord_adrDetails_tank_tankDetails_tankStatement_substancesPermitted: null, - techRecord_adrDetails_tank_tankDetails_tankStatement_statement: null, - techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo: null, - techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: null, - techRecord_adrDetails_tank_tankDetails_tankStatement_productList: null, - }; - - const nulledTankStatementStatement = { - techRecord_adrDetails_tank_tankDetails_tankStatement_statement: null, - }; - - const nulledTankStatementProductList = { - techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo: null, - techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: null, - techRecord_adrDetails_tank_tankDetails_tankStatement_productList: null, - }; - - const nulledSubstancesPermittedUNNumber = { - techRecord_adrDetails_tank_tankDetails_tankStatement_select: null, - ...nulledTankStatementStatement, - ...nulledTankStatementProductList, - }; - - const nulledBatteryListNumber = { - techRecord_adrDetails_batteryListNumber: null, - }; - - const nulledWeight = { - techRecord_adrDetails_weight: null, - }; - - const nulledBrakeDeclaration = { - techRecord_adrDetails_brakeDeclarationIssuer: null, - techRecord_adrDetails_brakeEndurance: null, - ...nulledWeight, - }; - - if (!editingTechRecord.techRecord_adrDetails_dangerousGoods) { - // vehicle doesn't carry dangerous goods so null this information - return { - ...state, - editingTechRecord: { - ...editingTechRecord, - techRecord_adrDetails_vehicleDetails_type: null, - techRecord_adrDetails_vehicleDetails_usedOnInternationalJourneys: null, - techRecord_adrDetails_vehicleDetails_approvalDate: null, - techRecord_adrDetails_permittedDangerousGoods: null, - ...nulledCompatibilityGroupJ, - techRecord_adrDetails_additionalExaminerNotes: null, - techRecord_adrDetails_applicantDetails_name: null, - techRecord_adrDetails_applicantDetails_street: null, - techRecord_adrDetails_applicantDetails_town: null, - techRecord_adrDetails_applicantDetails_city: null, - techRecord_adrDetails_applicantDetails_postcode: null, - techRecord_adrDetails_memosApply: null, - techRecord_adrDetails_m145Statement: null, - techRecord_adrDetails_documents: null, - techRecord_adrDetails_listStatementApplicable: null, - techRecord_adrDetails_batteryListNumber: null, - techRecord_adrDetails_brakeDeclarationsSeen: null, - techRecord_adrDetails_brakeDeclarationIssuer: null, - techRecord_adrDetails_brakeEndurance: null, - techRecord_adrDetails_weight: null, - techRecord_adrDetails_declarationsSeen: null, - techRecord_adrDetails_additionalNotes_guidanceNotes: null, - techRecord_adrDetails_additionalNotes_number: null, - techRecord_adrDetails_adrTypeApprovalNo: null, - techRecord_adrDetails_adrCertificateNotes: null, - techRecord_adrDetails_newCertificateRequested: null, - ...nulledTankDetails, - }, - }; - } - - let sanitisedEditingTechRecord = { - ...editingTechRecord, - }; - - // Null compatibility group J when permitted dangerous goods is NOT explosives type 2/3 - const explosivesGroups: string[] = [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3]; - if (!editingTechRecord.techRecord_adrDetails_permittedDangerousGoods?.some((value) => explosivesGroups.includes(value))) { - sanitisedEditingTechRecord = { ...sanitisedEditingTechRecord, ...nulledCompatibilityGroupJ }; - } - - // Null all tank details fields when ADR vehicle type does not include the words 'tank' or 'battery' - const adrVehicleTypes: string[] = Object.values(ADRBodyType).filter((value) => value.includes('battery') || value.includes('tank')); - if (!adrVehicleTypes.includes(editingTechRecord.techRecord_adrDetails_vehicleDetails_type as string)) { - sanitisedEditingTechRecord = { ...sanitisedEditingTechRecord, ...nulledTankDetails }; - } - - // Strip all unfilled UN numbers - const { techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: unNumbers } = sanitisedEditingTechRecord; - if (unNumbers) { - sanitisedEditingTechRecord = { - ...sanitisedEditingTechRecord, - techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: unNumbers.filter(Boolean), - }; - } - - // If tank details 'statement' selected, null UN numbers, product list referene no., product list - const { techRecord_adrDetails_tank_tankDetails_tankStatement_select: select } = sanitisedEditingTechRecord; - if (select === ADRTankDetailsTankStatementSelect.STATEMENT) { - sanitisedEditingTechRecord = { ...sanitisedEditingTechRecord, ...nulledTankStatementProductList }; - } - - // If tank details 'product list' selected, null statement reference no. - if (select === ADRTankDetailsTankStatementSelect.PRODUCT_LIST) { - sanitisedEditingTechRecord = { ...sanitisedEditingTechRecord, ...nulledTankStatementStatement }; - } - - // If tank details 'substances permitted' has 'tank code' option selected, null UN and product list reference no. - const { techRecord_adrDetails_tank_tankDetails_tankStatement_substancesPermitted: substancesPermitted } = sanitisedEditingTechRecord; - if (substancesPermitted === ADRTankStatementSubstancePermitted.UNDER_TANK_CODE) { - sanitisedEditingTechRecord = { ...sanitisedEditingTechRecord, ...nulledSubstancesPermittedUNNumber }; - } - - // If battery list applicable is no, null the battery list number - const { techRecord_adrDetails_listStatementApplicable: listStatementApplicable } = sanitisedEditingTechRecord; - if (!listStatementApplicable) { - sanitisedEditingTechRecord = { ...sanitisedEditingTechRecord, ...nulledBatteryListNumber }; - } - // If the ADR body type not includes 'battery', null all fields related battery list applicable - const { techRecord_adrDetails_vehicleDetails_type: vehicleDetailsType } = sanitisedEditingTechRecord; - if (!vehicleDetailsType?.includes('battery')) { - sanitisedEditingTechRecord = { - ...sanitisedEditingTechRecord, ...nulledBatteryListNumber, techRecord_adrDetails_listStatementApplicable: null, - }; - } - // If manufacturer brake declaration is no, null dependent sections - const { techRecord_adrDetails_brakeDeclarationsSeen: brakeDeclarationSeen } = sanitisedEditingTechRecord; - if (!brakeDeclarationSeen) { - sanitisedEditingTechRecord = { ...sanitisedEditingTechRecord, ...nulledBrakeDeclaration }; - } - - // If brake endurance is no, null weight field - const { techRecord_adrDetails_brakeEndurance: brakeEndurance } = sanitisedEditingTechRecord; - if (!brakeEndurance) { - sanitisedEditingTechRecord = { ...sanitisedEditingTechRecord, ...nulledWeight }; - } - - return { ...state, editingTechRecord: sanitisedEditingTechRecord }; - } - - } - - return { ...state }; + const { editingTechRecord } = state; + + if (editingTechRecord) { + const { techRecord_vehicleType: type } = editingTechRecord; + if (type === VehicleTypes.HGV || type === VehicleTypes.TRL || type === VehicleTypes.LGV) { + const nulledCompatibilityGroupJ = { + techRecord_adrDetails_compatibilityGroupJ: null, + }; + + const nulledTankDetails = { + techRecord_adrDetails_tank_tankDetails_tankManufacturer: null, + techRecord_adrDetails_tank_tankDetails_yearOfManufacture: null, + techRecord_adrDetails_tank_tankDetails_tankManufacturerSerialNo: null, + techRecord_adrDetails_tank_tankDetails_tankTypeAppNo: null, + techRecord_adrDetails_tank_tankDetails_tankCode: null, + techRecord_adrDetails_tank_tankDetails_specialProvisions: null, + techRecord_adrDetails_tank_tankDetails_tc2Details_tc2Type: null, + techRecord_adrDetails_tank_tankDetails_tc2Details_tc2IntermediateApprovalNo: null, + techRecord_adrDetails_tank_tankDetails_tc2Details_tc2IntermediateExpiryDate: null, + techRecord_adrDetails_tank_tankDetails_tc3Details: null, + techRecord_adrDetails_tank_tankDetails_tankStatement_substancesPermitted: null, + techRecord_adrDetails_tank_tankDetails_tankStatement_statement: null, + techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo: null, + techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: null, + techRecord_adrDetails_tank_tankDetails_tankStatement_productList: null, + }; + + const nulledTankStatementStatement = { + techRecord_adrDetails_tank_tankDetails_tankStatement_statement: null, + }; + + const nulledTankStatementProductList = { + techRecord_adrDetails_tank_tankDetails_tankStatement_productListRefNo: null, + techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: null, + techRecord_adrDetails_tank_tankDetails_tankStatement_productList: null, + }; + + const nulledSubstancesPermittedUNNumber = { + techRecord_adrDetails_tank_tankDetails_tankStatement_select: null, + ...nulledTankStatementStatement, + ...nulledTankStatementProductList, + }; + + const nulledBatteryListNumber = { + techRecord_adrDetails_batteryListNumber: null, + }; + + const nulledWeight = { + techRecord_adrDetails_weight: null, + }; + + const nulledBrakeDeclaration = { + techRecord_adrDetails_brakeDeclarationIssuer: null, + techRecord_adrDetails_brakeEndurance: null, + ...nulledWeight, + }; + + if (!editingTechRecord.techRecord_adrDetails_dangerousGoods) { + // vehicle doesn't carry dangerous goods so null this information + return { + ...state, + editingTechRecord: { + ...editingTechRecord, + techRecord_adrDetails_vehicleDetails_type: null, + techRecord_adrDetails_vehicleDetails_usedOnInternationalJourneys: null, + techRecord_adrDetails_vehicleDetails_approvalDate: null, + techRecord_adrDetails_permittedDangerousGoods: null, + ...nulledCompatibilityGroupJ, + techRecord_adrDetails_additionalExaminerNotes: null, + techRecord_adrDetails_applicantDetails_name: null, + techRecord_adrDetails_applicantDetails_street: null, + techRecord_adrDetails_applicantDetails_town: null, + techRecord_adrDetails_applicantDetails_city: null, + techRecord_adrDetails_applicantDetails_postcode: null, + techRecord_adrDetails_memosApply: null, + techRecord_adrDetails_m145Statement: null, + techRecord_adrDetails_documents: null, + techRecord_adrDetails_listStatementApplicable: null, + techRecord_adrDetails_batteryListNumber: null, + techRecord_adrDetails_brakeDeclarationsSeen: null, + techRecord_adrDetails_brakeDeclarationIssuer: null, + techRecord_adrDetails_brakeEndurance: null, + techRecord_adrDetails_weight: null, + techRecord_adrDetails_declarationsSeen: null, + techRecord_adrDetails_additionalNotes_guidanceNotes: null, + techRecord_adrDetails_additionalNotes_number: null, + techRecord_adrDetails_adrTypeApprovalNo: null, + techRecord_adrDetails_adrCertificateNotes: null, + techRecord_adrDetails_newCertificateRequested: null, + ...nulledTankDetails, + }, + }; + } + + let sanitisedEditingTechRecord = { + ...editingTechRecord, + }; + + // Null compatibility group J when permitted dangerous goods is NOT explosives type 2/3 + const explosivesGroups: string[] = [ADRDangerousGood.EXPLOSIVES_TYPE_2, ADRDangerousGood.EXPLOSIVES_TYPE_3]; + if ( + !editingTechRecord.techRecord_adrDetails_permittedDangerousGoods?.some((value) => + explosivesGroups.includes(value) + ) + ) { + sanitisedEditingTechRecord = { ...sanitisedEditingTechRecord, ...nulledCompatibilityGroupJ }; + } + + // Null all tank details fields when ADR vehicle type does not include the words 'tank' or 'battery' + const adrVehicleTypes: string[] = Object.values(ADRBodyType).filter( + (value) => value.includes('battery') || value.includes('tank') + ); + if (!adrVehicleTypes.includes(editingTechRecord.techRecord_adrDetails_vehicleDetails_type as string)) { + sanitisedEditingTechRecord = { ...sanitisedEditingTechRecord, ...nulledTankDetails }; + } + + // Strip all unfilled UN numbers + const { techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: unNumbers } = + sanitisedEditingTechRecord; + if (unNumbers) { + sanitisedEditingTechRecord = { + ...sanitisedEditingTechRecord, + techRecord_adrDetails_tank_tankDetails_tankStatement_productListUnNo: unNumbers.filter(Boolean), + }; + } + + // If tank details 'statement' selected, null UN numbers, product list referene no., product list + const { techRecord_adrDetails_tank_tankDetails_tankStatement_select: select } = sanitisedEditingTechRecord; + if (select === ADRTankDetailsTankStatementSelect.STATEMENT) { + sanitisedEditingTechRecord = { ...sanitisedEditingTechRecord, ...nulledTankStatementProductList }; + } + + // If tank details 'product list' selected, null statement reference no. + if (select === ADRTankDetailsTankStatementSelect.PRODUCT_LIST) { + sanitisedEditingTechRecord = { ...sanitisedEditingTechRecord, ...nulledTankStatementStatement }; + } + + // If tank details 'substances permitted' has 'tank code' option selected, null UN and product list reference no. + const { techRecord_adrDetails_tank_tankDetails_tankStatement_substancesPermitted: substancesPermitted } = + sanitisedEditingTechRecord; + if (substancesPermitted === ADRTankStatementSubstancePermitted.UNDER_TANK_CODE) { + sanitisedEditingTechRecord = { ...sanitisedEditingTechRecord, ...nulledSubstancesPermittedUNNumber }; + } + + // If battery list applicable is no, null the battery list number + const { techRecord_adrDetails_listStatementApplicable: listStatementApplicable } = sanitisedEditingTechRecord; + if (!listStatementApplicable) { + sanitisedEditingTechRecord = { ...sanitisedEditingTechRecord, ...nulledBatteryListNumber }; + } + // If the ADR body type not includes 'battery', null all fields related battery list applicable + const { techRecord_adrDetails_vehicleDetails_type: vehicleDetailsType } = sanitisedEditingTechRecord; + if (!vehicleDetailsType?.includes('battery')) { + sanitisedEditingTechRecord = { + ...sanitisedEditingTechRecord, + ...nulledBatteryListNumber, + techRecord_adrDetails_listStatementApplicable: null, + }; + } + // If manufacturer brake declaration is no, null dependent sections + const { techRecord_adrDetails_brakeDeclarationsSeen: brakeDeclarationSeen } = sanitisedEditingTechRecord; + if (!brakeDeclarationSeen) { + sanitisedEditingTechRecord = { ...sanitisedEditingTechRecord, ...nulledBrakeDeclaration }; + } + + // If brake endurance is no, null weight field + const { techRecord_adrDetails_brakeEndurance: brakeEndurance } = sanitisedEditingTechRecord; + if (!brakeEndurance) { + sanitisedEditingTechRecord = { ...sanitisedEditingTechRecord, ...nulledWeight }; + } + + return { ...state, editingTechRecord: sanitisedEditingTechRecord }; + } + } + + return { ...state }; } function handleADRExaminerNoteChanges(state: TechnicalRecordServiceState, username: string) { - const { editingTechRecord } = state; - const additionalNoteTechRecord = editingTechRecord as unknown as - (NonVerbTechRecordType<'hgv' | 'lgv' | 'trl'>) & { techRecord_adrDetails_additionalExaminerNotes_note: string }; - if (editingTechRecord) { - if (additionalNoteTechRecord.techRecord_adrDetails_additionalExaminerNotes_note) { - const additionalExaminerNotes = { - note: additionalNoteTechRecord.techRecord_adrDetails_additionalExaminerNotes_note, - lastUpdatedBy: username, - createdAtDate: new Date().toISOString(), - }; - if (additionalNoteTechRecord.techRecord_adrDetails_additionalExaminerNotes === null - || additionalNoteTechRecord.techRecord_adrDetails_additionalExaminerNotes === undefined) { - additionalNoteTechRecord.techRecord_adrDetails_additionalExaminerNotes = []; - } - additionalNoteTechRecord.techRecord_adrDetails_additionalExaminerNotes?.unshift(additionalExaminerNotes); - } - } - return { ...state, editingTechRecord: additionalNoteTechRecord as unknown as (TechRecordType<'put'>) }; + const { editingTechRecord } = state; + const additionalNoteTechRecord = editingTechRecord as unknown as NonVerbTechRecordType<'hgv' | 'lgv' | 'trl'> & { + techRecord_adrDetails_additionalExaminerNotes_note: string; + }; + if (editingTechRecord) { + if (additionalNoteTechRecord.techRecord_adrDetails_additionalExaminerNotes_note) { + const additionalExaminerNotes = { + note: additionalNoteTechRecord.techRecord_adrDetails_additionalExaminerNotes_note, + lastUpdatedBy: username, + createdAtDate: new Date().toISOString(), + }; + if ( + additionalNoteTechRecord.techRecord_adrDetails_additionalExaminerNotes === null || + additionalNoteTechRecord.techRecord_adrDetails_additionalExaminerNotes === undefined + ) { + additionalNoteTechRecord.techRecord_adrDetails_additionalExaminerNotes = []; + } + additionalNoteTechRecord.techRecord_adrDetails_additionalExaminerNotes?.unshift(additionalExaminerNotes); + } + } + return { ...state, editingTechRecord: additionalNoteTechRecord as unknown as TechRecordType<'put'> }; } function handleUpdateExistingADRExaminerNote( - state: TechnicalRecordServiceState, - action: { additionalExaminerNote: string, examinerNoteIndex: number }, + state: TechnicalRecordServiceState, + action: { additionalExaminerNote: string; examinerNoteIndex: number } ) { - const { editingTechRecord } = state; - const editedTechRecord = editingTechRecord as unknown as - (NonVerbTechRecordType<'hgv' | 'lgv' | 'trl'>); - if (editedTechRecord) { - const examinerNotes = editedTechRecord.techRecord_adrDetails_additionalExaminerNotes; - examinerNotes![action.examinerNoteIndex].note = action.additionalExaminerNote; - } - return { ...state, editingTechRecord: editingTechRecord as unknown as (TechRecordType<'put'>) }; + const { editingTechRecord } = state; + const editedTechRecord = editingTechRecord as unknown as NonVerbTechRecordType<'hgv' | 'lgv' | 'trl'>; + if (editedTechRecord) { + const examinerNotes = editedTechRecord.techRecord_adrDetails_additionalExaminerNotes; + examinerNotes![action.examinerNoteIndex].note = action.additionalExaminerNote; + } + return { ...state, editingTechRecord: editingTechRecord as unknown as TechRecordType<'put'> }; } diff --git a/src/app/store/technical-records/selectors/batch-create.selectors.ts b/src/app/store/technical-records/selectors/batch-create.selectors.ts index d248484adb..28248f2776 100644 --- a/src/app/store/technical-records/selectors/batch-create.selectors.ts +++ b/src/app/store/technical-records/selectors/batch-create.selectors.ts @@ -16,7 +16,9 @@ export const selectVehicleType = createSelector(selectBatchState, (state) => sta export const selectBatchSuccess = createSelector(selectAllBatch, (state) => state.filter((v) => v.created)); export const selectBatchSuccessCount = createSelector(selectBatchSuccess, (state) => state.length); -export const selectBatchCreated = createSelector(selectAllBatch, (state) => state.filter((v) => v.amendedRecord === false)); +export const selectBatchCreated = createSelector(selectAllBatch, (state) => + state.filter((v) => v.amendedRecord === false) +); export const selectBatchCreatedCount = createSelector(selectBatchCreated, (state) => state.length); export const selectBatchCreatedSuccess = createSelector(selectBatchCreated, (state) => state.filter((v) => v.created)); export const selectBatchCreatedSuccessCount = createSelector(selectBatchCreatedSuccess, (state) => state.length); diff --git a/src/app/store/technical-records/selectors/technical-record-service.selectors.spec.ts b/src/app/store/technical-records/selectors/technical-record-service.selectors.spec.ts index 89b2129988..9f16fa144b 100644 --- a/src/app/store/technical-records/selectors/technical-record-service.selectors.spec.ts +++ b/src/app/store/technical-records/selectors/technical-record-service.selectors.spec.ts @@ -2,226 +2,253 @@ import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; import { TechnicalRecordServiceState, initialState } from '../reducers/technical-record-service.reducer'; import { - editingTechRecord, - getSingleVehicleType, - selectSectionState, - selectTechRecord, - selectTechRecordChanges, - selectTechRecordDeletions, - selectTechRecordHistory, - techRecord, - technicalRecordsLoadingState, + editingTechRecord, + getSingleVehicleType, + selectSectionState, + selectTechRecord, + selectTechRecordChanges, + selectTechRecordDeletions, + selectTechRecordHistory, + techRecord, + technicalRecordsLoadingState, } from './technical-record-service.selectors'; describe('Tech Record Selectors', () => { - describe('selectedTestResultState', () => { - it('should return vehicleTechRecords state', () => { - const state: TechnicalRecordServiceState = { - ...initialState, - vehicleTechRecord: { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as unknown as TechRecordType<'get'>, - }; - const selectedState = techRecord.projector(state); - expect(selectedState).toEqual(state.vehicleTechRecord); - }); - }); - - describe('technicalRecordsLoadingState', () => { - it('should return loading state', () => { - const state: TechnicalRecordServiceState = { ...initialState, loading: true }; - const selectedState = technicalRecordsLoadingState.projector(state); - expect(selectedState).toBeTruthy(); - }); - }); - describe('editingTechRecord', () => { - it('should return editingTechRecords state', () => { - const state: TechnicalRecordServiceState = { - ...initialState, - vehicleTechRecord: { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>, - editingTechRecord: { systemNumber: 'bar', createdTimestamp: 'foo', vin: 'testVin2' } as unknown as TechRecordType<'put'>, - }; - const selectedState = editingTechRecord.projector(state); - expect(selectedState).toEqual(state.editingTechRecord); - }); - }); - - describe('selectTechRecord', () => { - const routes = [ - { - statusExpected: 'provisional', - techRecord_createdAt: undefined, - isEditing: false, - vehicle: { - systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin', techRecord_statusCode: 'provisional', - }, - }, - { - statusExpected: 'provisional', - techRecord_createdAt: undefined, - isEditing: false, - vehicle: { - systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin', techRecord_statusCode: 'provisional', - }, - }, - { - statusExpected: 'archived', - techRecord_createdAt: new Date('2022-02-14').toISOString(), - isEditing: false, - vehicle: { - systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin', techRecord_statusCode: 'archived', - }, - }, - { - statusExpected: 'current', - techRecord_createdAt: undefined, - isEditing: true, - vehicle: { - systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin', techRecord_statusCode: 'provisional', - }, - }, - ]; - it.each(routes)('should return the $statusExpected record', ({ - statusExpected, techRecord_createdAt, isEditing, vehicle, - }) => { - const mockTechRecord = selectTechRecord.projector({ ...vehicle, techRecord_createdAt } as unknown as TechRecordType<'get'>, isEditing, { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_statusCode: 'current', - } as unknown as TechRecordType<'put'>); - expect(mockTechRecord).toBeDefined(); - expect(mockTechRecord?.techRecord_statusCode).toBe(statusExpected); - expect((mockTechRecord as TechRecordType<'get'>).techRecord_createdAt).toEqual(techRecord_createdAt); - }); - }); - - describe('getSingleVehicleType', () => { - it('should return the correct vehicle type', () => { - const vehicleTechRecord = { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_vehicleType: 'foobar', - } as unknown as TechRecordType<'get'>; - const state: TechnicalRecordServiceState = { ...initialState, vehicleTechRecord }; - const selectedVehicleType = getSingleVehicleType.projector(state); - expect(selectedVehicleType).toBe(vehicleTechRecord.techRecord_vehicleType); - }); - }); - - describe('techRecordHistory', () => { - it('should return the vehicles tech record history', () => { - const vehicleTechRecords = [ - { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' }, - { systemNumber: 'bar', createdTimestamp: 'foo', vin: 'testVin2' }, - ] as TechRecordSearchSchema[]; - const state: TechnicalRecordServiceState = { ...initialState, techRecordHistory: vehicleTechRecords }; - const selectedVehicleHistory = selectTechRecordHistory.projector(state); - expect(selectedVehicleHistory).toBe(vehicleTechRecords); - }); - }); - - describe('selectSectionState', () => { - it('should return the sectionState in the technical record state', () => { - const state: TechnicalRecordServiceState = { ...initialState, sectionState: ['TestSection1', 'TestSection2'] }; - const selectedState = selectSectionState.projector(state); - expect(selectedState?.length).toBe(2); - }); - }); - - describe('selectTechRecordDeletions', () => { - it('should return an object with only the deleted fields from the editing tech record', () => { - - const vehicleTechRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>; - const editedTechRecord = { systemNumber: 'foo', createdTimestamp: 'bar' } as unknown as TechRecordType<'put'>; - - const selectedDeletions = selectTechRecordDeletions.projector(vehicleTechRecord, editedTechRecord); - expect(selectedDeletions).toEqual({ vin: 'testVin' }); - }); - it('should detect deeply nested deletions', () => { - - const vehicleTechRecord = { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_axles: [{ axleNumber: 1 }, { axleNumber: 2 }], - } as unknown as TechRecordType<'get'>; - const editedTechRecord = { - systemNumber: 'foo', - createdTimestamp: 'bar', - techRecord_axles: [{ axleNumber: 1 }], - } as unknown as TechRecordType<'put'>; - - const selectedDeletions = selectTechRecordDeletions.projector(vehicleTechRecord, editedTechRecord); - expect(selectedDeletions).toEqual({ vin: 'testVin', techRecord_axles: { 1: { axleNumber: 2 } } }); - }); - it('should return an empty object if current vehicle is null', () => { - - const vehicleTechRecord = null as unknown as TechRecordType<'get'>; - const editedTechRecord = { - systemNumber: 'foo', - createdTimestamp: 'bar', - techRecord_axles: [{ axleNumber: 1 }], - } as unknown as TechRecordType<'put'>; - - const selectedDeletions = selectTechRecordDeletions.projector(vehicleTechRecord, editedTechRecord); - expect(selectedDeletions).toEqual({}); - }); - it('should return an empty object if edited vehicle is null', () => { - - const vehicleTechRecord = { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_axles: [{ axleNumber: 1 }, { axleNumber: 2 }], - } as unknown as TechRecordType<'get'>; - const editedTechRecord = null as unknown as TechRecordType<'put'>; - - const selectedDeletions = selectTechRecordDeletions.projector(vehicleTechRecord, editedTechRecord); - expect(selectedDeletions).toEqual({}); - }); - }); - - describe('selectTechRecordChanges', () => { - it('should detect any changes on the flat tech record', () => { - const vehicleTechRecord = { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_axles: [{ axleNumber: 1 }, { axleNumber: 2 }], - } as unknown as TechRecordType<'get'>; - const editedTechRecord = { - systemNumber: 'foo', - createdTimestamp: 'bar', - techRecord_vehicleType: 'psv', - techRecord_axles: [{ axleNumber: 1 }], - } as unknown as TechRecordType<'put'>; - const selectedChanges = selectTechRecordChanges.projector(vehicleTechRecord, editedTechRecord); - expect(selectedChanges).toEqual({ vin: undefined, techRecord_axles: { 1: undefined }, techRecord_vehicleType: 'psv' }); - }); - it('should return an empty object if current vehicle is null', () => { - - const vehicleTechRecord = null as unknown as TechRecordType<'get'>; - const editedTechRecord = { - systemNumber: 'foo', - createdTimestamp: 'bar', - techRecord_axles: [{ axleNumber: 1 }], - } as unknown as TechRecordType<'put'>; - - const selectedDeletions = selectTechRecordChanges.projector(vehicleTechRecord, editedTechRecord); - expect(selectedDeletions).toEqual({}); - }); - it('should return an empty object if edited vehicle is null', () => { - - const vehicleTechRecord = { - systemNumber: 'foo', - createdTimestamp: 'bar', - vin: 'testVin', - techRecord_axles: [{ axleNumber: 1 }, { axleNumber: 2 }], - } as unknown as TechRecordType<'get'>; - const editedTechRecord = null as unknown as TechRecordType<'put'>; - - const selectedDeletions = selectTechRecordChanges.projector(vehicleTechRecord, editedTechRecord); - expect(selectedDeletions).toEqual({}); - }); - }); + describe('selectedTestResultState', () => { + it('should return vehicleTechRecords state', () => { + const state: TechnicalRecordServiceState = { + ...initialState, + vehicleTechRecord: { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + } as unknown as TechRecordType<'get'>, + }; + const selectedState = techRecord.projector(state); + expect(selectedState).toEqual(state.vehicleTechRecord); + }); + }); + + describe('technicalRecordsLoadingState', () => { + it('should return loading state', () => { + const state: TechnicalRecordServiceState = { ...initialState, loading: true }; + const selectedState = technicalRecordsLoadingState.projector(state); + expect(selectedState).toBeTruthy(); + }); + }); + describe('editingTechRecord', () => { + it('should return editingTechRecords state', () => { + const state: TechnicalRecordServiceState = { + ...initialState, + vehicleTechRecord: { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as TechRecordType<'get'>, + editingTechRecord: { + systemNumber: 'bar', + createdTimestamp: 'foo', + vin: 'testVin2', + } as unknown as TechRecordType<'put'>, + }; + const selectedState = editingTechRecord.projector(state); + expect(selectedState).toEqual(state.editingTechRecord); + }); + }); + + describe('selectTechRecord', () => { + const routes = [ + { + statusExpected: 'provisional', + techRecord_createdAt: undefined, + isEditing: false, + vehicle: { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_statusCode: 'provisional', + }, + }, + { + statusExpected: 'provisional', + techRecord_createdAt: undefined, + isEditing: false, + vehicle: { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_statusCode: 'provisional', + }, + }, + { + statusExpected: 'archived', + techRecord_createdAt: new Date('2022-02-14').toISOString(), + isEditing: false, + vehicle: { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_statusCode: 'archived', + }, + }, + { + statusExpected: 'current', + techRecord_createdAt: undefined, + isEditing: true, + vehicle: { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_statusCode: 'provisional', + }, + }, + ]; + it.each(routes)( + 'should return the $statusExpected record', + ({ statusExpected, techRecord_createdAt, isEditing, vehicle }) => { + const mockTechRecord = selectTechRecord.projector( + { ...vehicle, techRecord_createdAt } as unknown as TechRecordType<'get'>, + isEditing, + { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_statusCode: 'current', + } as unknown as TechRecordType<'put'> + ); + expect(mockTechRecord).toBeDefined(); + expect(mockTechRecord?.techRecord_statusCode).toBe(statusExpected); + expect((mockTechRecord as TechRecordType<'get'>).techRecord_createdAt).toEqual(techRecord_createdAt); + } + ); + }); + + describe('getSingleVehicleType', () => { + it('should return the correct vehicle type', () => { + const vehicleTechRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_vehicleType: 'foobar', + } as unknown as TechRecordType<'get'>; + const state: TechnicalRecordServiceState = { ...initialState, vehicleTechRecord }; + const selectedVehicleType = getSingleVehicleType.projector(state); + expect(selectedVehicleType).toBe(vehicleTechRecord.techRecord_vehicleType); + }); + }); + + describe('techRecordHistory', () => { + it('should return the vehicles tech record history', () => { + const vehicleTechRecords = [ + { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' }, + { systemNumber: 'bar', createdTimestamp: 'foo', vin: 'testVin2' }, + ] as TechRecordSearchSchema[]; + const state: TechnicalRecordServiceState = { ...initialState, techRecordHistory: vehicleTechRecords }; + const selectedVehicleHistory = selectTechRecordHistory.projector(state); + expect(selectedVehicleHistory).toBe(vehicleTechRecords); + }); + }); + + describe('selectSectionState', () => { + it('should return the sectionState in the technical record state', () => { + const state: TechnicalRecordServiceState = { ...initialState, sectionState: ['TestSection1', 'TestSection2'] }; + const selectedState = selectSectionState.projector(state); + expect(selectedState?.length).toBe(2); + }); + }); + + describe('selectTechRecordDeletions', () => { + it('should return an object with only the deleted fields from the editing tech record', () => { + const vehicleTechRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + } as TechRecordType<'get'>; + const editedTechRecord = { systemNumber: 'foo', createdTimestamp: 'bar' } as unknown as TechRecordType<'put'>; + + const selectedDeletions = selectTechRecordDeletions.projector(vehicleTechRecord, editedTechRecord); + expect(selectedDeletions).toEqual({ vin: 'testVin' }); + }); + it('should detect deeply nested deletions', () => { + const vehicleTechRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_axles: [{ axleNumber: 1 }, { axleNumber: 2 }], + } as unknown as TechRecordType<'get'>; + const editedTechRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + techRecord_axles: [{ axleNumber: 1 }], + } as unknown as TechRecordType<'put'>; + + const selectedDeletions = selectTechRecordDeletions.projector(vehicleTechRecord, editedTechRecord); + expect(selectedDeletions).toEqual({ vin: 'testVin', techRecord_axles: { 1: { axleNumber: 2 } } }); + }); + it('should return an empty object if current vehicle is null', () => { + const vehicleTechRecord = null as unknown as TechRecordType<'get'>; + const editedTechRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + techRecord_axles: [{ axleNumber: 1 }], + } as unknown as TechRecordType<'put'>; + + const selectedDeletions = selectTechRecordDeletions.projector(vehicleTechRecord, editedTechRecord); + expect(selectedDeletions).toEqual({}); + }); + it('should return an empty object if edited vehicle is null', () => { + const vehicleTechRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_axles: [{ axleNumber: 1 }, { axleNumber: 2 }], + } as unknown as TechRecordType<'get'>; + const editedTechRecord = null as unknown as TechRecordType<'put'>; + + const selectedDeletions = selectTechRecordDeletions.projector(vehicleTechRecord, editedTechRecord); + expect(selectedDeletions).toEqual({}); + }); + }); + + describe('selectTechRecordChanges', () => { + it('should detect any changes on the flat tech record', () => { + const vehicleTechRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_axles: [{ axleNumber: 1 }, { axleNumber: 2 }], + } as unknown as TechRecordType<'get'>; + const editedTechRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + techRecord_vehicleType: 'psv', + techRecord_axles: [{ axleNumber: 1 }], + } as unknown as TechRecordType<'put'>; + const selectedChanges = selectTechRecordChanges.projector(vehicleTechRecord, editedTechRecord); + expect(selectedChanges).toEqual({ + vin: undefined, + techRecord_axles: { 1: undefined }, + techRecord_vehicleType: 'psv', + }); + }); + it('should return an empty object if current vehicle is null', () => { + const vehicleTechRecord = null as unknown as TechRecordType<'get'>; + const editedTechRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + techRecord_axles: [{ axleNumber: 1 }], + } as unknown as TechRecordType<'put'>; + + const selectedDeletions = selectTechRecordChanges.projector(vehicleTechRecord, editedTechRecord); + expect(selectedDeletions).toEqual({}); + }); + it('should return an empty object if edited vehicle is null', () => { + const vehicleTechRecord = { + systemNumber: 'foo', + createdTimestamp: 'bar', + vin: 'testVin', + techRecord_axles: [{ axleNumber: 1 }, { axleNumber: 2 }], + } as unknown as TechRecordType<'get'>; + const editedTechRecord = null as unknown as TechRecordType<'put'>; + + const selectedDeletions = selectTechRecordChanges.projector(vehicleTechRecord, editedTechRecord); + expect(selectedDeletions).toEqual({}); + }); + }); }); diff --git a/src/app/store/technical-records/selectors/technical-record-service.selectors.ts b/src/app/store/technical-records/selectors/technical-record-service.selectors.ts index ad1b3688e2..d01b8801ae 100644 --- a/src/app/store/technical-records/selectors/technical-record-service.selectors.ts +++ b/src/app/store/technical-records/selectors/technical-record-service.selectors.ts @@ -7,7 +7,10 @@ import { getTechRecordState } from '../reducers/technical-record-service.reducer export const techRecord = createSelector(getTechRecordState, (state) => state.vehicleTechRecord); -export const getSingleVehicleType = createSelector(getTechRecordState, (state) => state.vehicleTechRecord?.techRecord_vehicleType); +export const getSingleVehicleType = createSelector( + getTechRecordState, + (state) => state.vehicleTechRecord?.techRecord_vehicleType +); export const editingTechRecord = createSelector(getTechRecordState, (state) => state.editingTechRecord); @@ -16,26 +19,27 @@ export const technicalRecordsLoadingState = createSelector(getTechRecordState, ( export const getCanGeneratePlate = createSelector(getTechRecordState, (state) => state.canGeneratePlate); export const selectTechRecordHistory = createSelector(getTechRecordState, (state) => - state.techRecordHistory?.sort((a, b) => { - const aTimeCode = new Date(a.createdTimestamp).getTime(); - const bTimeCode = new Date(b.createdTimestamp).getTime(); - // return aTimeCode < bTimeCode ? 1 : aTimeCode > bTimeCode ? -1 : 0; - if (aTimeCode < bTimeCode) { - return 1; - } - if (aTimeCode > bTimeCode) { - return -1; - } - return 0; - })); + state.techRecordHistory?.sort((a, b) => { + const aTimeCode = new Date(a.createdTimestamp).getTime(); + const bTimeCode = new Date(b.createdTimestamp).getTime(); + // return aTimeCode < bTimeCode ? 1 : aTimeCode > bTimeCode ? -1 : 0; + if (aTimeCode < bTimeCode) { + return 1; + } + if (aTimeCode > bTimeCode) { + return -1; + } + return 0; + }) +); export const selectTechRecord = createSelector( - techRecord, - selectRouteDataProperty('isEditing'), - editingTechRecord, - (viewableTechRecord, isEditing, editableTechRecord): V3TechRecordModel | undefined => { - return isEditing ? editableTechRecord : viewableTechRecord; - }, + techRecord, + selectRouteDataProperty('isEditing'), + editingTechRecord, + (viewableTechRecord, isEditing, editableTechRecord): V3TechRecordModel | undefined => { + return isEditing ? editableTechRecord : viewableTechRecord; + } ); export const selectSectionState = createSelector(getTechRecordState, (state) => state.sectionState); @@ -43,16 +47,16 @@ export const selectSectionState = createSelector(getTechRecordState, (state) => export const selectScrollPosition = createSelector(getTechRecordState, (state) => state.scrollPosition); export const selectTechRecordDeletions = createSelector(techRecord, editingTechRecord, (current, amended) => { - if (current == null || amended == null) return {}; + if (current == null || amended == null) return {}; - // Note: we use added changes from the comparison of amended to current, as deletions are not working as expected - return detailedDiff(amended, current).added as Partial>; + // Note: we use added changes from the comparison of amended to current, as deletions are not working as expected + return detailedDiff(amended, current).added as Partial>; }); export const selectTechRecordChanges = createSelector(techRecord, editingTechRecord, (current, amended) => { - if (current == null || amended == null) return {}; + if (current == null || amended == null) return {}; - const changes = detailedDiff(current, amended); + const changes = detailedDiff(current, amended); - return { ...changes.added, ...changes.updated, ...changes.deleted } as Partial>; + return { ...changes.added, ...changes.updated, ...changes.deleted } as Partial>; }); diff --git a/src/app/store/technical-records/technical-records-state.module.ts b/src/app/store/technical-records/technical-records-state.module.ts index 1d4ba44be5..bc2d804240 100644 --- a/src/app/store/technical-records/technical-records-state.module.ts +++ b/src/app/store/technical-records/technical-records-state.module.ts @@ -3,14 +3,17 @@ import { NgModule } from '@angular/core'; import { EffectsModule } from '@ngrx/effects'; import { StoreModule } from '@ngrx/store'; import { TechnicalRecordServiceEffects } from './effects/technical-record-service.effects'; -import { STORE_FEATURE_TECHNICAL_RECORDS_KEY, vehicleTechRecordReducer } from './reducers/technical-record-service.reducer'; +import { + STORE_FEATURE_TECHNICAL_RECORDS_KEY, + vehicleTechRecordReducer, +} from './reducers/technical-record-service.reducer'; @NgModule({ - declarations: [], - imports: [ - CommonModule, - StoreModule.forFeature(STORE_FEATURE_TECHNICAL_RECORDS_KEY, vehicleTechRecordReducer), - EffectsModule.forFeature([TechnicalRecordServiceEffects]), - ], + declarations: [], + imports: [ + CommonModule, + StoreModule.forFeature(STORE_FEATURE_TECHNICAL_RECORDS_KEY, vehicleTechRecordReducer), + EffectsModule.forFeature([TechnicalRecordServiceEffects]), + ], }) export class TechnicalRecordsStateModule {} diff --git a/src/app/store/test-records/actions/test-records.actions.spec.ts b/src/app/store/test-records/actions/test-records.actions.spec.ts index 3739bc19de..9e45466537 100644 --- a/src/app/store/test-records/actions/test-records.actions.spec.ts +++ b/src/app/store/test-records/actions/test-records.actions.spec.ts @@ -1,33 +1,33 @@ import { - createRequiredStandard, - fetchSelectedTestResult, - fetchSelectedTestResultFailed, - fetchSelectedTestResultSuccess, - fetchTestResults, - fetchTestResultsBySystemNumber, - fetchTestResultsBySystemNumberFailed, - fetchTestResultsBySystemNumberSuccess, - fetchTestResultsFailed, - fetchTestResultsSuccess, - removeRequiredStandard, - updateRequiredStandard, - updateResultOfTestRequiredStandards, + createRequiredStandard, + fetchSelectedTestResult, + fetchSelectedTestResultFailed, + fetchSelectedTestResultSuccess, + fetchTestResults, + fetchTestResultsBySystemNumber, + fetchTestResultsBySystemNumberFailed, + fetchTestResultsBySystemNumberSuccess, + fetchTestResultsFailed, + fetchTestResultsSuccess, + removeRequiredStandard, + updateRequiredStandard, + updateResultOfTestRequiredStandards, } from './test-records.actions'; describe('Test Result Actions', () => { - it('should return correct types', () => { - expect(fetchTestResults.type).toBe('[API/test-results] Fetch All'); - expect(fetchTestResultsSuccess.type).toBe('[API/test-results] Fetch All Success'); - expect(fetchTestResultsFailed.type).toBe('[API/test-results] Fetch All Failed'); - expect(fetchTestResultsBySystemNumber.type).toBe('[API/test-results] Fetch All By systemNumber'); - expect(fetchTestResultsBySystemNumberSuccess.type).toBe('[API/test-results] Fetch All By systemNumber Success'); - expect(fetchTestResultsBySystemNumberFailed.type).toBe('[API/test-results] Fetch All By systemNumber Failed'); - expect(fetchSelectedTestResult.type).toBe('[API/test-results], Fetch by ID'); - expect(fetchSelectedTestResultSuccess.type).toBe('[API/test-results], Fetch by ID Success'); - expect(fetchSelectedTestResultFailed.type).toBe('[API/test-results], Fetch by ID Failed'); - expect(createRequiredStandard.type).toBe('[test-results] create required standard'); - expect(updateRequiredStandard.type).toBe('[test-results] update required standard'); - expect(removeRequiredStandard.type).toBe('[test-results] remove required standard'); - expect(updateResultOfTestRequiredStandards.type).toBe('[test-results] update test result required standards'); - }); + it('should return correct types', () => { + expect(fetchTestResults.type).toBe('[API/test-results] Fetch All'); + expect(fetchTestResultsSuccess.type).toBe('[API/test-results] Fetch All Success'); + expect(fetchTestResultsFailed.type).toBe('[API/test-results] Fetch All Failed'); + expect(fetchTestResultsBySystemNumber.type).toBe('[API/test-results] Fetch All By systemNumber'); + expect(fetchTestResultsBySystemNumberSuccess.type).toBe('[API/test-results] Fetch All By systemNumber Success'); + expect(fetchTestResultsBySystemNumberFailed.type).toBe('[API/test-results] Fetch All By systemNumber Failed'); + expect(fetchSelectedTestResult.type).toBe('[API/test-results], Fetch by ID'); + expect(fetchSelectedTestResultSuccess.type).toBe('[API/test-results], Fetch by ID Success'); + expect(fetchSelectedTestResultFailed.type).toBe('[API/test-results], Fetch by ID Failed'); + expect(createRequiredStandard.type).toBe('[test-results] create required standard'); + expect(updateRequiredStandard.type).toBe('[test-results] update required standard'); + expect(removeRequiredStandard.type).toBe('[test-results] remove required standard'); + expect(updateResultOfTestRequiredStandards.type).toBe('[test-results] update test result required standards'); + }); }); diff --git a/src/app/store/test-records/actions/test-records.actions.ts b/src/app/store/test-records/actions/test-records.actions.ts index 6c3c685350..72efdfc1ad 100644 --- a/src/app/store/test-records/actions/test-records.actions.ts +++ b/src/app/store/test-records/actions/test-records.actions.ts @@ -9,62 +9,107 @@ import { Update } from '@ngrx/entity'; import { createAction, props } from '@ngrx/store'; export const fetchTestResults = createAction('[API/test-results] Fetch All'); -export const fetchTestResultsSuccess = createAction('[API/test-results] Fetch All Success', props<{ payload: Array }>()); +export const fetchTestResultsSuccess = createAction( + '[API/test-results] Fetch All Success', + props<{ payload: Array }>() +); export const fetchTestResultsFailed = createAction('[API/test-results] Fetch All Failed', props()); -export const fetchTestResultsBySystemNumber = createAction('[API/test-results] Fetch All By systemNumber', props<{ systemNumber: string }>()); +export const fetchTestResultsBySystemNumber = createAction( + '[API/test-results] Fetch All By systemNumber', + props<{ systemNumber: string }>() +); export const fetchTestResultsBySystemNumberSuccess = createAction( - '[API/test-results] Fetch All By systemNumber Success', - props<{ payload: Array }>(), + '[API/test-results] Fetch All By systemNumber Success', + props<{ payload: Array }>() +); +export const fetchTestResultsBySystemNumberFailed = createAction( + '[API/test-results] Fetch All By systemNumber Failed', + props() ); -export const fetchTestResultsBySystemNumberFailed = createAction('[API/test-results] Fetch All By systemNumber Failed', props()); export const fetchSelectedTestResult = createAction('[API/test-results], Fetch by ID'); -export const fetchSelectedTestResultSuccess = createAction('[API/test-results], Fetch by ID Success', props<{ payload: TestResultModel }>()); -export const fetchSelectedTestResultFailed = createAction('[API/test-results], Fetch by ID Failed', props()); +export const fetchSelectedTestResultSuccess = createAction( + '[API/test-results], Fetch by ID Success', + props<{ payload: TestResultModel }>() +); +export const fetchSelectedTestResultFailed = createAction( + '[API/test-results], Fetch by ID Failed', + props() +); export const createTestResult = createAction('[test-results] Create test result', props<{ value: TestResultModel }>()); -export const createTestResultSuccess = createAction('[API/test-results] Create test result Success', props<{ payload: Update }>()); -export const createTestResultFailed = createAction('[API/test-results] Create test result Failed', props<{ errors: GlobalError[] }>()); +export const createTestResultSuccess = createAction( + '[API/test-results] Create test result Success', + props<{ payload: Update }>() +); +export const createTestResultFailed = createAction( + '[API/test-results] Create test result Failed', + props<{ errors: GlobalError[] }>() +); export const updateTestResult = createAction('[test-results] Update test result', props<{ value: TestResultModel }>()); -export const updateTestResultSuccess = createAction('[API/test-results] Update test result Success', props<{ payload: Update }>()); -export const updateTestResultFailed = createAction('[API/test-results] Update test result Failed', props<{ errors: GlobalError[] }>()); +export const updateTestResultSuccess = createAction( + '[API/test-results] Update test result Success', + props<{ payload: Update }>() +); +export const updateTestResultFailed = createAction( + '[API/test-results] Update test result Failed', + props<{ errors: GlobalError[] }>() +); export const cleanTestResult = createAction('[test-results] Clean test result for submission'); export const editingTestResult = createAction('[test-results] Editing', props<{ testTypeId: string }>()); -export const updateEditingTestResult = createAction('[test-results] Update editing', props<{ testResult: TestResultModel }>()); +export const updateEditingTestResult = createAction( + '[test-results] Update editing', + props<{ testResult: TestResultModel }>() +); export const cancelEditingTestResult = createAction('[test-results] Cancel editing'); -export const setResultOfTest = createAction('[test-results] set the result of the test', props<{ result: resultOfTestEnum }>()); +export const setResultOfTest = createAction( + '[test-results] set the result of the test', + props<{ result: resultOfTestEnum }>() +); export const updateResultOfTest = createAction('[test-results] update the result of the test'); -export const initialContingencyTest = createAction('[Contingency test] Create', props<{ testResult: Partial }>()); +export const initialContingencyTest = createAction( + '[Contingency test] Create', + props<{ testResult: Partial }>() +); -export const contingencyTestTypeSelected = createAction('[Test Results] contingency test type selected', props<{ testType: string }>()); +export const contingencyTestTypeSelected = createAction( + '[Test Results] contingency test type selected', + props<{ testType: string }>() +); export const testTypeIdChanged = createAction('[test-results] test type id changed', props<{ testTypeId: string }>()); export const templateSectionsChanged = createAction( - '[test-results] Template sections changed', - props<{ sectionTemplates: FormNode[]; sectionsValue: TestResultModel | undefined }>(), + '[test-results] Template sections changed', + props<{ sectionTemplates: FormNode[]; sectionsValue: TestResultModel | undefined }>() ); export const createDefect = createAction('[test-results] create defect', props<{ defect: TestResultDefect }>()); -export const updateDefect = createAction('[test-results] save defect', props<{ defect: TestResultDefect; index: number }>()); +export const updateDefect = createAction( + '[test-results] save defect', + props<{ defect: TestResultDefect; index: number }>() +); export const removeDefect = createAction('[test-results] remove defect', props<{ index: number }>()); export const createRequiredStandard = createAction( - '[test-results] create required standard', - props<{ requiredStandard: TestResultRequiredStandard }>(), + '[test-results] create required standard', + props<{ requiredStandard: TestResultRequiredStandard }>() ); export const updateRequiredStandard = createAction( - '[test-results] update required standard', - props<{ requiredStandard: TestResultRequiredStandard, index: number }>(), + '[test-results] update required standard', + props<{ requiredStandard: TestResultRequiredStandard; index: number }>() ); -export const removeRequiredStandard = createAction('[test-results] remove required standard', props<{ index: number }>()); +export const removeRequiredStandard = createAction( + '[test-results] remove required standard', + props<{ index: number }>() +); export const updateResultOfTestRequiredStandards = createAction('[test-results] update test result required standards'); diff --git a/src/app/store/test-records/effects/test-records.effects.spec.ts b/src/app/store/test-records/effects/test-records.effects.spec.ts index 701441dbe9..01c5e2543f 100644 --- a/src/app/store/test-records/effects/test-records.effects.spec.ts +++ b/src/app/store/test-records/effects/test-records.effects.spec.ts @@ -18,6 +18,7 @@ import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { provideMockActions } from '@ngrx/effects/testing'; import { Action } from '@ngrx/store'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; +import { FeatureToggleService } from '@services/feature-toggle-service/feature-toggle-service'; import { RouterService } from '@services/router/router.service'; import { TestRecordsService } from '@services/test-records/test-records.service'; import { UserService } from '@services/user-service/user-service'; @@ -25,809 +26,860 @@ import { State, initialAppState } from '@store/.'; import { selectQueryParams, selectRouteNestedParams } from '@store/router/selectors/router.selectors'; import { Observable, of } from 'rxjs'; import { TestScheduler } from 'rxjs/testing'; -import { FeatureToggleService } from '@services/feature-toggle-service/feature-toggle-service'; import { mockTestResult, mockTestResultList } from '../../../../mocks/mock-test-result'; import { masterTpl } from '../../../forms/templates/test-records/master.template'; import { - contingencyTestTypeSelected, - createTestResult, - createTestResultFailed, - createTestResultSuccess, - editingTestResult, - fetchSelectedTestResult, - fetchSelectedTestResultFailed, - fetchSelectedTestResultSuccess, - fetchTestResultsBySystemNumber, - fetchTestResultsBySystemNumberFailed, - fetchTestResultsBySystemNumberSuccess, - templateSectionsChanged, - testTypeIdChanged, - updateResultOfTest, - updateTestResult, - updateTestResultFailed, - updateTestResultSuccess, + contingencyTestTypeSelected, + createTestResult, + createTestResultFailed, + createTestResultSuccess, + editingTestResult, + fetchSelectedTestResult, + fetchSelectedTestResultFailed, + fetchSelectedTestResultSuccess, + fetchTestResultsBySystemNumber, + fetchTestResultsBySystemNumberFailed, + fetchTestResultsBySystemNumberSuccess, + templateSectionsChanged, + testTypeIdChanged, + updateResultOfTest, + updateTestResult, + updateTestResultFailed, + updateTestResultSuccess, } from '../actions/test-records.actions'; import { isTestTypeOldIvaOrMsva, selectedTestResultState, testResultInEdit } from '../selectors/test-records.selectors'; import { TestResultsEffects } from './test-records.effects'; jest.mock('../../../forms/templates/test-records/master.template', () => ({ - __esModule: true, - default: jest.fn(), - masterTpl: { - psv: { - default: { - test: { - name: 'Default', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - type: FormNodeTypes.ARRAY, - children: [{ name: '0', type: FormNodeTypes.GROUP, children: [{ name: 'testTypeId', type: FormNodeTypes.CONTROL, value: '' }] }], - }, - ], - }, - }, - testTypesGroup1: { - test: { - name: 'Test', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - type: FormNodeTypes.ARRAY, - children: [{ name: '0', type: FormNodeTypes.GROUP, children: [{ name: 'testTypeId', type: FormNodeTypes.CONTROL, value: '' }] }], - }, - ], - }, - }, - testTypesSpecialistGroup1: { - test: { - name: 'NewSpecialistTest', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - type: FormNodeTypes.ARRAY, - children: [{ name: '0', type: FormNodeTypes.GROUP, children: [{ name: 'testTypeId', type: FormNodeTypes.CONTROL, value: '' }] }], - }, - ], - }, - }, - testTypesSpecialistGroup1OldIVAorMSVA: { - test: { - name: 'OldSpecialistTest', - type: FormNodeTypes.GROUP, - children: [ - { - name: 'testTypes', - type: FormNodeTypes.ARRAY, - children: [{ name: '0', type: FormNodeTypes.GROUP, children: [{ name: 'testTypeId', type: FormNodeTypes.CONTROL, value: '' }] }], - }, - ], - }, - }, - }, - }, + __esModule: true, + default: jest.fn(), + masterTpl: { + psv: { + default: { + test: { + name: 'Default', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypes', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + type: FormNodeTypes.GROUP, + children: [{ name: 'testTypeId', type: FormNodeTypes.CONTROL, value: '' }], + }, + ], + }, + ], + }, + }, + testTypesGroup1: { + test: { + name: 'Test', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypes', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + type: FormNodeTypes.GROUP, + children: [{ name: 'testTypeId', type: FormNodeTypes.CONTROL, value: '' }], + }, + ], + }, + ], + }, + }, + testTypesSpecialistGroup1: { + test: { + name: 'NewSpecialistTest', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypes', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + type: FormNodeTypes.GROUP, + children: [{ name: 'testTypeId', type: FormNodeTypes.CONTROL, value: '' }], + }, + ], + }, + ], + }, + }, + testTypesSpecialistGroup1OldIVAorMSVA: { + test: { + name: 'OldSpecialistTest', + type: FormNodeTypes.GROUP, + children: [ + { + name: 'testTypes', + type: FormNodeTypes.ARRAY, + children: [ + { + name: '0', + type: FormNodeTypes.GROUP, + children: [{ name: 'testTypeId', type: FormNodeTypes.CONTROL, value: '' }], + }, + ], + }, + ], + }, + }, + }, + }, })); describe('TestResultsEffects', () => { - let effects: TestResultsEffects; - let actions$ = new Observable(); - let testScheduler: TestScheduler; - let testResultsService: TestRecordsService; - let store: MockStore; - let featureToggleService: FeatureToggleService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, TestResultsApiModule, RouterTestingModule], - providers: [ - TestResultsEffects, - provideMockActions(() => actions$), - TestRecordsService, - provideMockStore({ - initialState: initialAppState, - selectors: [ - { - selector: selectRouteNestedParams, - value: [ - { - systemNumber: 'systemNumber01', - testResultId: 'testResult01', - }, - ], - }, - ], - }), - { - provide: UserService, - useValue: { - user$: of({ name: 'testername', userEmail: 'test@test.com', oid: '123zxc' }), - name$: of('name'), - userEmail$: of('userEmail'), - id$: of('iod'), - }, - }, - RouterService, - DynamicFormService, - FeatureToggleService, - ], - }); - - store = TestBed.inject(MockStore); - effects = TestBed.inject(TestResultsEffects); - testResultsService = TestBed.inject(TestRecordsService); - featureToggleService = TestBed.inject(FeatureToggleService); - }); - - beforeEach(() => { - testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - }); - - describe('fetchTestResultsBySystemNumber$', () => { - it('should return fetchTestResultBySystemNumberSuccess action on successfull API call', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const testResults = mockTestResultList(); - - // mock action to trigger effect - actions$ = hot('-a--', { a: fetchTestResultsBySystemNumber }); - - // mock service call - jest.spyOn(testResultsService, 'fetchTestResultbySystemNumber').mockReturnValue(cold('--a|', { a: testResults })); - - // expect effect to return success action - expectObservable(effects.fetchTestResultsBySystemNumber$).toBe('---b', { - b: fetchTestResultsBySystemNumberSuccess({ payload: testResults }), - }); - }); - }); - - it('should return fetchTestResultsBySystemNumberFailed action on API error', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - actions$ = hot('-a--', { a: fetchTestResultsBySystemNumber }); - - const expectedError = new HttpErrorResponse({ - status: 500, - statusText: 'Internal server error', - }); - jest.spyOn(testResultsService, 'fetchTestResultbySystemNumber').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.fetchTestResultsBySystemNumber$).toBe('---b', { - b: fetchTestResultsBySystemNumberFailed({ error: 'Http failure response for (unknown url): 500 Internal server error' }), - }); - }); - }); - - it('should return fetchTestResultsBySystemNumberSuccess on a 404', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - actions$ = hot('-a--', { a: fetchTestResultsBySystemNumber }); - - const expectedError = new HttpErrorResponse({ - status: 404, - statusText: 'Not found', - }); - jest.spyOn(testResultsService, 'fetchTestResultbySystemNumber').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.fetchTestResultsBySystemNumber$).toBe('---b', { - b: fetchTestResultsBySystemNumberSuccess({ payload: [] as TestResultModel[] }), - }); - }); - }); - }); - - describe('fetchSelectedTestResult$', () => { - it('should return fetchSelectedTestResultSuccess', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const testResult = mockTestResult(); - - actions$ = hot('-a-', { a: fetchSelectedTestResult() }); - - jest.spyOn(testResultsService, 'fetchTestResultbySystemNumber').mockReturnValue(cold('--a|', { a: [testResult] })); - - expectObservable(effects.fetchSelectedTestResult$).toBe('---b', { - b: fetchSelectedTestResultSuccess({ payload: testResult }), - }); - }); - }); - - it('should return fetchSelectedTestResultFailed if API returns empty array', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - actions$ = hot('-a-', { a: fetchSelectedTestResult() }); - - jest.spyOn(testResultsService, 'fetchTestResultbySystemNumber').mockReturnValue(cold('--a|', { a: [] })); - - expectObservable(effects.fetchSelectedTestResult$).toBe('---b', { - b: fetchSelectedTestResultFailed({ error: 'Test result not found' }), - }); - }); - }); - - it('should return fetchSelectedTestResultFailed if API returns an error', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - actions$ = hot('-a-', { a: fetchSelectedTestResult() }); - - // mock service call - const expectedError = new HttpErrorResponse({ - status: 400, - statusText: 'Bad Request', - }); - jest.spyOn(testResultsService, 'fetchTestResultbySystemNumber').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.fetchSelectedTestResult$).toBe('---b', { - b: fetchSelectedTestResultFailed({ error: 'Http failure response for (unknown url): 400 Bad Request' }), - }); - }); - }); - }); - - describe('updateTestResult$', () => { - const newTestResult = { testResultId: '1' } as TestResultModel; - - it('should dispatch updateTestResultSuccess with return payload', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - actions$ = hot('-a-', { a: updateTestResult({ value: newTestResult }) }); - - jest.spyOn(testResultsService, 'saveTestResult').mockReturnValue(cold('---b', { b: newTestResult })); - - expectObservable(effects.updateTestResult$).toBe('----b', { - b: updateTestResultSuccess({ payload: { id: '1', changes: newTestResult } }), - }); - }); - }); - - it('should dispatch updateTestResultFailed action with empty errors array', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - actions$ = hot('-a-', { a: updateTestResult({ value: newTestResult }) }); - - jest - .spyOn(testResultsService, 'saveTestResult') - .mockReturnValue(cold('---#|', {}, new HttpErrorResponse({ status: 500, error: 'some error' }))); - - expectObservable(effects.updateTestResult$).toBe('----b', { - b: updateTestResultFailed({ errors: [] }), - }); - }); - }); - - it('should dispatch updateTestResultFailed action with validation errors', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - actions$ = hot('-a-', { a: updateTestResult({ value: newTestResult }) }); - - jest - .spyOn(testResultsService, 'saveTestResult') - .mockReturnValue( - cold('---#|', {}, new HttpErrorResponse({ status: 400, error: { errors: ['"name" is missing', '"age" is missing', 'random error'] } })), - ); - - const expectedErrors: GlobalError[] = [ - { error: '"name" is missing', anchorLink: 'name' }, - { error: '"age" is missing', anchorLink: 'age' }, - { error: 'random error', anchorLink: '' }, - ]; - expectObservable(effects.updateTestResult$).toBe('----b', { - b: updateTestResultFailed({ errors: expectedErrors }), - }); - }); - }); - }); - - describe('generateSectionTemplatesAndtestResultToUpdate$', () => { - beforeEach(() => { - store.resetSelectors(); - jest.resetModules(); - }); - - it('should dispatch templateSectionsChanged with new sections and test result', () => { - const testResult = createMockTestResult({ - vehicleType: VehicleTypes.PSV, - testTypes: [createMockTestType({ testTypeId: '1' })], - }); - - testScheduler.run(({ hot, expectObservable }) => { - store.overrideSelector(selectedTestResultState, testResult); - - actions$ = hot('-a', { - a: editingTestResult({ - testTypeId: '1', - }), - }); - - expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-(bc)', { - b: templateSectionsChanged({ - sectionTemplates: Object.values(masterTpl.psv['testTypesGroup1'] as Record), - sectionsValue: { testTypes: [{ testTypeId: '1' }] } as unknown as TestResultModel, - }), - c: updateResultOfTest(), - }); - }); - }); - it('should dispatch templateSectionsChanged with new sections when custom defects is not present', () => { - const testResult = createMockTestResult({ - vehicleType: VehicleTypes.PSV, - testTypes: [createMockTestType({ testTypeId: '126' })], - }); - jest.spyOn(featureToggleService, 'isFeatureEnabled').mockReturnValue(true); - testScheduler.run(({ hot, expectObservable }) => { - store.overrideSelector(selectQueryParams, { edit: 'true' }); - store.overrideSelector(selectedTestResultState, testResult); - store.overrideSelector(isTestTypeOldIvaOrMsva, false); - - actions$ = hot('-a', { - a: editingTestResult({ - testTypeId: '126', - }), - }); - - expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-(bc)', { - b: templateSectionsChanged({ - sectionTemplates: Object.values(masterTpl.psv['testTypesSpecialistGroup1'] as Record), - sectionsValue: { testTypes: [{ testTypeId: '126' }] } as unknown as TestResultModel, - }), - c: updateResultOfTest(), - }); - }); - }); - it('should dispatch templateSectionsChanged with old sections when custom defects is present', () => { - const testResult = createMockTestResult({ - vehicleType: VehicleTypes.PSV, - testTypes: [createMockTestType({ testTypeId: '126' })], - }); - jest.spyOn(featureToggleService, 'isFeatureEnabled').mockReturnValue(true); - testScheduler.run(({ hot, expectObservable }) => { - store.overrideSelector(selectQueryParams, { edit: 'true' }); - store.overrideSelector(selectedTestResultState, testResult); - store.overrideSelector(isTestTypeOldIvaOrMsva, true); - - actions$ = hot('-a', { - a: editingTestResult({ - testTypeId: '126', - }), - }); - - expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-(bc)', { - b: templateSectionsChanged({ - sectionTemplates: Object.values(masterTpl.psv['testTypesSpecialistGroup1OldIVAorMSVA'] as Record), - sectionsValue: { testTypes: [{ testTypeId: '126' }] } as unknown as TestResultModel, - }), - c: updateResultOfTest(), - }); - }); - }); - - it('should dispatch templateSectionsChanged with old sections when feature flag is off', () => { - const testResult = createMockTestResult({ - vehicleType: VehicleTypes.PSV, - testTypes: [createMockTestType({ testTypeId: '126' })], - }); - jest.spyOn(featureToggleService, 'isFeatureEnabled').mockReturnValue(false); - testScheduler.run(({ hot, expectObservable }) => { - store.overrideSelector(selectQueryParams, { edit: 'true' }); - store.overrideSelector(selectedTestResultState, testResult); - store.overrideSelector(isTestTypeOldIvaOrMsva, false); - - actions$ = hot('-a', { - a: editingTestResult({ - testTypeId: '126', - }), - }); - - expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-(bc)', { - b: templateSectionsChanged({ - sectionTemplates: Object.values(masterTpl.psv['testTypesSpecialistGroup1OldIVAorMSVA'] as Record), - sectionsValue: { testTypes: [{ testTypeId: '126' }] } as unknown as TestResultModel, - }), - c: updateResultOfTest(), - }); - }); - }); - it('should return empty section templates if action testResult.vehicleType === undefined', () => { - const testResult = createMockTestResult({ - vehicleType: undefined, - testTypes: [createMockTestType({ testTypeId: '1' })], - }); - - testScheduler.run(({ hot, expectObservable }) => { - store.overrideSelector(selectedTestResultState, testResult); - actions$ = hot('-a', { - a: testTypeIdChanged({ - testTypeId: '1', - }), - }); - - expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-b', { - b: templateSectionsChanged({ - sectionTemplates: [], - sectionsValue: undefined, - }), - }); - }); - }); - - it('should return empty section templates if action testResult.vehicleType is not known by masterTpl', () => { - const testResult = createMockTestResult({ - vehicleType: 'car' as VehicleTypes, - testTypes: [createMockTestType({ testTypeId: '1' })], - }); - - testScheduler.run(({ hot, expectObservable }) => { - store.overrideSelector(selectedTestResultState, testResult); - - actions$ = hot('-a', { - a: testTypeIdChanged({ - testTypeId: '1', - }), - }); - - expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-b', { - b: templateSectionsChanged({ - sectionTemplates: [], - sectionsValue: undefined, - }), - }); - }); - }); - - it('should return empty section templates if testTypeId doesnt apply to vehicleType', () => { - const testResult = createMockTestResult({ - vehicleType: VehicleTypes.PSV, - testTypes: [createMockTestType({ testTypeId: '190' })], - }); - - testScheduler.run(({ hot, expectObservable }) => { - store.overrideSelector(selectQueryParams, { edit: 'true' }); - store.overrideSelector(selectedTestResultState, testResult); - - actions$ = hot('-a', { - a: testTypeIdChanged({ - testTypeId: '190', - }), - }); - - expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-b', { - b: templateSectionsChanged({ - sectionTemplates: [], - sectionsValue: undefined, - }), - }); - }); - }); - - it('should return empty section templates if testTypeId is known but not in master template and edit is true', () => { - const testResult = createMockTestResult({ - vehicleType: VehicleTypes.PSV, - testTypes: [createMockTestType(({ testTypeId: '39' }))], - }); - - testScheduler.run(({ hot, expectObservable }) => { - store.overrideSelector(selectQueryParams, { edit: 'true' }); - store.overrideSelector(selectedTestResultState, testResult); - - actions$ = hot('-a', { - a: testTypeIdChanged({ - testTypeId: '39', - }), - }); - - expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-b', { - b: templateSectionsChanged({ - sectionTemplates: [], - sectionsValue: undefined, - }), - }); - }); - }); - - it('should return default section templates if testTypeId is known but not in master template and edit is false', () => { - const testResult = createMockTestResult({ - vehicleType: VehicleTypes.PSV, - testTypes: [createMockTestType({ testTypeId: '39' })], - }); - testScheduler.run(({ hot, expectObservable }) => { - store.overrideSelector(selectQueryParams, { edit: 'false' }); - store.overrideSelector(selectedTestResultState, testResult); - - actions$ = hot('-a', { - a: testTypeIdChanged({ - testTypeId: '39', - }), - }); - - expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-(bc)', { - b: templateSectionsChanged({ - sectionTemplates: Object.values(masterTpl.psv['default'] as Record), - sectionsValue: { testTypes: [{ testTypeId: '39' }] } as unknown as TestResultModel, - }), - c: updateResultOfTest(), - }); - }); - }); - }); - - describe('generateContingencyTestTemplatesAndtestResultToUpdate$', () => { - beforeEach(() => { - store.resetSelectors(); - jest.resetModules(); - }); - - it('should dispatch templateSectionsChanged with new sections and test result', () => { - const testResult = createMockTestResult({ - vehicleType: VehicleTypes.PSV, - testTypes: [createMockTestType({ testTypeId: '1' })], - }); - - store.overrideSelector(testResultInEdit, testResult); - - testScheduler.run(({ hot, expectObservable }) => { - actions$ = hot('-a', { - a: contingencyTestTypeSelected({ - testType: '1', - }), - }); - - expectObservable(effects.generateContingencyTestTemplatesAndtestResultToUpdate$).toBe('-b', { - b: templateSectionsChanged({ - sectionTemplates: Object.values(contingencyTestTemplates.psv['testTypesGroup1'] as Record), - sectionsValue: { - contingencyTestNumber: undefined, - countryOfRegistration: '', - createdById: undefined, - createdByName: undefined, - euVehicleCategory: EUVehicleCategory.M1, - firstUseDate: null, - lastUpdatedAt: undefined, - lastUpdatedById: undefined, - lastUpdatedByName: undefined, - noOfAxles: undefined, - numberOfSeats: undefined, - numberOfWheelsDriven: undefined, - odometerReading: 0, - odometerReadingUnits: OdometerReadingUnits.KILOMETRES, - preparerId: '', - preparerName: '', - reasonForCancellation: undefined, - reasonForCreation: undefined, - regnDate: undefined, - source: undefined, - shouldEmailCertificate: undefined, - systemNumber: '', - testEndTimestamp: '', - testResultId: '', - testStartTimestamp: '', - testStationName: '', - testStationPNumber: '', - testStationType: 'atf', - testStatus: undefined, - testTypes: [ - { - additionalCommentsForAbandon: null, - additionalNotesRecorded: '', - certificateLink: undefined, - certificateNumber: '', - customDefects: [], - defects: [], - deletionFlag: undefined, - lastSeatbeltInstallationCheckDate: '', - name: '', - numberOfSeatbeltsFitted: 0, - prohibitionIssued: false, - reasonForAbandoning: '', - seatbeltInstallationCheckDate: false, - secondaryCertificateNumber: null, - testExpiryDate: '', - testResult: resultOfTestEnum.fail, - testTypeEndTimestamp: '', - testTypeId: '1', - testTypeName: '', - testTypeStartTimestamp: '', - }, - ], - testerEmailAddress: '', - testerName: '', - testerStaffId: '', - typeOfTest: TypeOfTest.CONTINGENCY, - vehicleClass: null, - vehicleConfiguration: undefined, - vehicleSize: undefined, - vehicleType: 'psv', - vin: '', - vrm: '', - } as unknown as TestResultModel, - }), - }); - }); - }); - - it('should dispatch templateSectionsChanged with old sections for IVA when flag is false', () => { - const testResult = createMockTestResult({ - vehicleType: VehicleTypes.PSV, - testTypes: [createMockTestType({ testTypeId: '126' })], - }); - jest.spyOn(featureToggleService, 'isFeatureEnabled').mockReturnValue(false); - store.overrideSelector(testResultInEdit, testResult); - - testScheduler.run(({ hot, expectObservable }) => { - actions$ = hot('-a', { - a: contingencyTestTypeSelected({ - testType: '126', - }), - }); - - expectObservable(effects.generateContingencyTestTemplatesAndtestResultToUpdate$).toBe('-b', { - b: templateSectionsChanged({ - sectionTemplates: Object.values(contingencyTestTemplates.psv['testTypesSpecialistGroup1OldIVAorMSVA'] as Record), - sectionsValue: { - contingencyTestNumber: undefined, - countryOfRegistration: '', - createdById: undefined, - createdByName: undefined, - euVehicleCategory: EUVehicleCategory.M1, - firstUseDate: null, - lastUpdatedAt: undefined, - lastUpdatedById: undefined, - lastUpdatedByName: undefined, - noOfAxles: undefined, - numberOfSeats: undefined, - numberOfWheelsDriven: undefined, - odometerReading: 0, - odometerReadingUnits: OdometerReadingUnits.KILOMETRES, - preparerId: '', - preparerName: '', - reasonForCancellation: undefined, - reasonForCreation: undefined, - regnDate: undefined, - source: undefined, - shouldEmailCertificate: undefined, - systemNumber: '', - testEndTimestamp: '', - testResultId: '', - testStartTimestamp: '', - testStationName: '', - testStationPNumber: '', - testStationType: 'atf', - testStatus: undefined, - testTypes: [ - { - additionalCommentsForAbandon: null, - additionalNotesRecorded: '', - certificateLink: undefined, - certificateNumber: '', - customDefects: [], - defects: [], - deletionFlag: undefined, - lastSeatbeltInstallationCheckDate: '', - name: '', - numberOfSeatbeltsFitted: 0, - prohibitionIssued: false, - reasonForAbandoning: '', - seatbeltInstallationCheckDate: false, - secondaryCertificateNumber: null, - testResult: resultOfTestEnum.fail, - testTypeEndTimestamp: '', - testTypeId: '126', - testTypeName: '', - testTypeStartTimestamp: '', - }, - ], - testerEmailAddress: '', - testerName: '', - testerStaffId: '', - typeOfTest: TypeOfTest.CONTINGENCY, - vehicleClass: null, - vehicleConfiguration: undefined, - vehicleSize: undefined, - vehicleType: 'psv', - vin: '', - vrm: '', - } as unknown as TestResultModel, - }), - }); - }); - }); - - it('should return empty section templates if action testResult.vehicleType === undefined', () => { - const testResult = createMockTestResult({ - vehicleType: undefined, - testTypes: [createMockTestType({ testTypeId: '1' })], - }); - - testScheduler.run(({ hot, expectObservable }) => { - store.overrideSelector(testResultInEdit, testResult); - actions$ = hot('-a', { - a: contingencyTestTypeSelected({ - testType: '1', - }), - }); - - expectObservable(effects.generateContingencyTestTemplatesAndtestResultToUpdate$).toBe('-b', { - b: templateSectionsChanged({ - sectionTemplates: [], - sectionsValue: undefined, - }), - }); - }); - }); - }); - - describe('createTestResult$$', () => { - it('should return createTestResultSuccess action on successfull API call', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const testResult: TestResultModel = mockTestResult(); - // mock action to trigger effect - actions$ = hot('-a--', { a: createTestResult({ value: testResult }) }); - // mock service call - jest.spyOn(testResultsService, 'postTestResult') - .mockReturnValue(cold('---b|', { b: testResult }) as unknown as Observable>); - - // expect effect to return success action - expectObservable(effects.createTestResult$).toBe('----b', { - b: createTestResultSuccess({ payload: { id: testResult.testResultId, changes: testResult } }), - }); - }); - }); - - it('should return createTestResultFailed', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const testResult: TestResultModel = mockTestResult(); - actions$ = hot('-a--', { a: createTestResult({ value: testResult }) }); - - const expectedError = new HttpErrorResponse({ - status: 500, - statusText: 'Internal server error', - }); - - jest.spyOn(testResultsService, 'postTestResult').mockReturnValue(cold('---#|', {}, expectedError)); - - expectObservable(effects.createTestResult$).toBe('----b', { - b: createTestResultFailed({ errors: [] }), - }); - }); - }); - - it('should return createTestResultFailed and add validation errors', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const testResult: TestResultModel = mockTestResult(); - actions$ = hot('-a--', { a: createTestResult({ value: testResult }) }); - - const expectedError = new HttpErrorResponse({ - status: 400, - error: { errors: ['"name" is missing', '"age" is missing', 'random error'] }, - }); - - jest.spyOn(testResultsService, 'postTestResult').mockReturnValue(cold('---#|', {}, expectedError)); - - const expectedErrors: GlobalError[] = [ - { error: '"name" is missing', anchorLink: 'name' }, - { error: '"age" is missing', anchorLink: 'age' }, - { error: 'random error', anchorLink: '' }, - ]; - - expectObservable(effects.createTestResult$).toBe('----b', { - b: createTestResultFailed({ errors: expectedErrors }), - }); - }); - }); - - it('should return createTestResultFailed and add a validation error', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const testResult: TestResultModel = mockTestResult(); - actions$ = hot('-a--', { a: createTestResult({ value: testResult }) }); - - const expectedError = new HttpErrorResponse({ - status: 400, - error: 'Certificate number not present on TIR test type', - }); - - jest.spyOn(testResultsService, 'postTestResult').mockReturnValue(cold('---#|', {}, expectedError)); - - const expectedErrors: GlobalError[] = [{ error: 'Certificate number not present on TIR test type' }]; - - expectObservable(effects.createTestResult$).toBe('----b', { - b: createTestResultFailed({ errors: expectedErrors }), - }); - }); - }); - }); + let effects: TestResultsEffects; + let actions$ = new Observable(); + let testScheduler: TestScheduler; + let testResultsService: TestRecordsService; + let store: MockStore; + let featureToggleService: FeatureToggleService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule, TestResultsApiModule, RouterTestingModule], + providers: [ + TestResultsEffects, + provideMockActions(() => actions$), + TestRecordsService, + provideMockStore({ + initialState: initialAppState, + selectors: [ + { + selector: selectRouteNestedParams, + value: [ + { + systemNumber: 'systemNumber01', + testResultId: 'testResult01', + }, + ], + }, + ], + }), + { + provide: UserService, + useValue: { + user$: of({ name: 'testername', userEmail: 'test@test.com', oid: '123zxc' }), + name$: of('name'), + userEmail$: of('userEmail'), + id$: of('iod'), + }, + }, + RouterService, + DynamicFormService, + FeatureToggleService, + ], + }); + + store = TestBed.inject(MockStore); + effects = TestBed.inject(TestResultsEffects); + testResultsService = TestBed.inject(TestRecordsService); + featureToggleService = TestBed.inject(FeatureToggleService); + }); + + beforeEach(() => { + testScheduler = new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); + }); + }); + + describe('fetchTestResultsBySystemNumber$', () => { + it('should return fetchTestResultBySystemNumberSuccess action on successfull API call', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const testResults = mockTestResultList(); + + // mock action to trigger effect + actions$ = hot('-a--', { a: fetchTestResultsBySystemNumber }); + + // mock service call + jest + .spyOn(testResultsService, 'fetchTestResultbySystemNumber') + .mockReturnValue(cold('--a|', { a: testResults })); + + // expect effect to return success action + expectObservable(effects.fetchTestResultsBySystemNumber$).toBe('---b', { + b: fetchTestResultsBySystemNumberSuccess({ payload: testResults }), + }); + }); + }); + + it('should return fetchTestResultsBySystemNumberFailed action on API error', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + actions$ = hot('-a--', { a: fetchTestResultsBySystemNumber }); + + const expectedError = new HttpErrorResponse({ + status: 500, + statusText: 'Internal server error', + }); + jest + .spyOn(testResultsService, 'fetchTestResultbySystemNumber') + .mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.fetchTestResultsBySystemNumber$).toBe('---b', { + b: fetchTestResultsBySystemNumberFailed({ + error: 'Http failure response for (unknown url): 500 Internal server error', + }), + }); + }); + }); + + it('should return fetchTestResultsBySystemNumberSuccess on a 404', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + actions$ = hot('-a--', { a: fetchTestResultsBySystemNumber }); + + const expectedError = new HttpErrorResponse({ + status: 404, + statusText: 'Not found', + }); + jest + .spyOn(testResultsService, 'fetchTestResultbySystemNumber') + .mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.fetchTestResultsBySystemNumber$).toBe('---b', { + b: fetchTestResultsBySystemNumberSuccess({ payload: [] as TestResultModel[] }), + }); + }); + }); + }); + + describe('fetchSelectedTestResult$', () => { + it('should return fetchSelectedTestResultSuccess', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const testResult = mockTestResult(); + + actions$ = hot('-a-', { a: fetchSelectedTestResult() }); + + jest + .spyOn(testResultsService, 'fetchTestResultbySystemNumber') + .mockReturnValue(cold('--a|', { a: [testResult] })); + + expectObservable(effects.fetchSelectedTestResult$).toBe('---b', { + b: fetchSelectedTestResultSuccess({ payload: testResult }), + }); + }); + }); + + it('should return fetchSelectedTestResultFailed if API returns empty array', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + actions$ = hot('-a-', { a: fetchSelectedTestResult() }); + + jest.spyOn(testResultsService, 'fetchTestResultbySystemNumber').mockReturnValue(cold('--a|', { a: [] })); + + expectObservable(effects.fetchSelectedTestResult$).toBe('---b', { + b: fetchSelectedTestResultFailed({ error: 'Test result not found' }), + }); + }); + }); + + it('should return fetchSelectedTestResultFailed if API returns an error', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + actions$ = hot('-a-', { a: fetchSelectedTestResult() }); + + // mock service call + const expectedError = new HttpErrorResponse({ + status: 400, + statusText: 'Bad Request', + }); + jest + .spyOn(testResultsService, 'fetchTestResultbySystemNumber') + .mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.fetchSelectedTestResult$).toBe('---b', { + b: fetchSelectedTestResultFailed({ error: 'Http failure response for (unknown url): 400 Bad Request' }), + }); + }); + }); + }); + + describe('updateTestResult$', () => { + const newTestResult = { testResultId: '1' } as TestResultModel; + + it('should dispatch updateTestResultSuccess with return payload', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + actions$ = hot('-a-', { a: updateTestResult({ value: newTestResult }) }); + + jest.spyOn(testResultsService, 'saveTestResult').mockReturnValue(cold('---b', { b: newTestResult })); + + expectObservable(effects.updateTestResult$).toBe('----b', { + b: updateTestResultSuccess({ payload: { id: '1', changes: newTestResult } }), + }); + }); + }); + + it('should dispatch updateTestResultFailed action with empty errors array', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + actions$ = hot('-a-', { a: updateTestResult({ value: newTestResult }) }); + + jest + .spyOn(testResultsService, 'saveTestResult') + .mockReturnValue(cold('---#|', {}, new HttpErrorResponse({ status: 500, error: 'some error' }))); + + expectObservable(effects.updateTestResult$).toBe('----b', { + b: updateTestResultFailed({ errors: [] }), + }); + }); + }); + + it('should dispatch updateTestResultFailed action with validation errors', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + actions$ = hot('-a-', { a: updateTestResult({ value: newTestResult }) }); + + jest + .spyOn(testResultsService, 'saveTestResult') + .mockReturnValue( + cold( + '---#|', + {}, + new HttpErrorResponse({ + status: 400, + error: { errors: ['"name" is missing', '"age" is missing', 'random error'] }, + }) + ) + ); + + const expectedErrors: GlobalError[] = [ + { error: '"name" is missing', anchorLink: 'name' }, + { error: '"age" is missing', anchorLink: 'age' }, + { error: 'random error', anchorLink: '' }, + ]; + expectObservable(effects.updateTestResult$).toBe('----b', { + b: updateTestResultFailed({ errors: expectedErrors }), + }); + }); + }); + }); + + describe('generateSectionTemplatesAndtestResultToUpdate$', () => { + beforeEach(() => { + store.resetSelectors(); + jest.resetModules(); + }); + + it('should dispatch templateSectionsChanged with new sections and test result', () => { + const testResult = createMockTestResult({ + vehicleType: VehicleTypes.PSV, + testTypes: [createMockTestType({ testTypeId: '1' })], + }); + + testScheduler.run(({ hot, expectObservable }) => { + store.overrideSelector(selectedTestResultState, testResult); + + actions$ = hot('-a', { + a: editingTestResult({ + testTypeId: '1', + }), + }); + + expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-(bc)', { + b: templateSectionsChanged({ + sectionTemplates: Object.values(masterTpl.psv['testTypesGroup1'] as Record), + sectionsValue: { testTypes: [{ testTypeId: '1' }] } as unknown as TestResultModel, + }), + c: updateResultOfTest(), + }); + }); + }); + it('should dispatch templateSectionsChanged with new sections when custom defects is not present', () => { + const testResult = createMockTestResult({ + vehicleType: VehicleTypes.PSV, + testTypes: [createMockTestType({ testTypeId: '126' })], + }); + jest.spyOn(featureToggleService, 'isFeatureEnabled').mockReturnValue(true); + testScheduler.run(({ hot, expectObservable }) => { + store.overrideSelector(selectQueryParams, { edit: 'true' }); + store.overrideSelector(selectedTestResultState, testResult); + store.overrideSelector(isTestTypeOldIvaOrMsva, false); + + actions$ = hot('-a', { + a: editingTestResult({ + testTypeId: '126', + }), + }); + + expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-(bc)', { + b: templateSectionsChanged({ + sectionTemplates: Object.values(masterTpl.psv['testTypesSpecialistGroup1'] as Record), + sectionsValue: { testTypes: [{ testTypeId: '126' }] } as unknown as TestResultModel, + }), + c: updateResultOfTest(), + }); + }); + }); + it('should dispatch templateSectionsChanged with old sections when custom defects is present', () => { + const testResult = createMockTestResult({ + vehicleType: VehicleTypes.PSV, + testTypes: [createMockTestType({ testTypeId: '126' })], + }); + jest.spyOn(featureToggleService, 'isFeatureEnabled').mockReturnValue(true); + testScheduler.run(({ hot, expectObservable }) => { + store.overrideSelector(selectQueryParams, { edit: 'true' }); + store.overrideSelector(selectedTestResultState, testResult); + store.overrideSelector(isTestTypeOldIvaOrMsva, true); + + actions$ = hot('-a', { + a: editingTestResult({ + testTypeId: '126', + }), + }); + + expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-(bc)', { + b: templateSectionsChanged({ + sectionTemplates: Object.values( + masterTpl.psv['testTypesSpecialistGroup1OldIVAorMSVA'] as Record + ), + sectionsValue: { testTypes: [{ testTypeId: '126' }] } as unknown as TestResultModel, + }), + c: updateResultOfTest(), + }); + }); + }); + + it('should dispatch templateSectionsChanged with old sections when feature flag is off', () => { + const testResult = createMockTestResult({ + vehicleType: VehicleTypes.PSV, + testTypes: [createMockTestType({ testTypeId: '126' })], + }); + jest.spyOn(featureToggleService, 'isFeatureEnabled').mockReturnValue(false); + testScheduler.run(({ hot, expectObservable }) => { + store.overrideSelector(selectQueryParams, { edit: 'true' }); + store.overrideSelector(selectedTestResultState, testResult); + store.overrideSelector(isTestTypeOldIvaOrMsva, false); + + actions$ = hot('-a', { + a: editingTestResult({ + testTypeId: '126', + }), + }); + + expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-(bc)', { + b: templateSectionsChanged({ + sectionTemplates: Object.values( + masterTpl.psv['testTypesSpecialistGroup1OldIVAorMSVA'] as Record + ), + sectionsValue: { testTypes: [{ testTypeId: '126' }] } as unknown as TestResultModel, + }), + c: updateResultOfTest(), + }); + }); + }); + it('should return empty section templates if action testResult.vehicleType === undefined', () => { + const testResult = createMockTestResult({ + vehicleType: undefined, + testTypes: [createMockTestType({ testTypeId: '1' })], + }); + + testScheduler.run(({ hot, expectObservable }) => { + store.overrideSelector(selectedTestResultState, testResult); + actions$ = hot('-a', { + a: testTypeIdChanged({ + testTypeId: '1', + }), + }); + + expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-b', { + b: templateSectionsChanged({ + sectionTemplates: [], + sectionsValue: undefined, + }), + }); + }); + }); + + it('should return empty section templates if action testResult.vehicleType is not known by masterTpl', () => { + const testResult = createMockTestResult({ + vehicleType: 'car' as VehicleTypes, + testTypes: [createMockTestType({ testTypeId: '1' })], + }); + + testScheduler.run(({ hot, expectObservable }) => { + store.overrideSelector(selectedTestResultState, testResult); + + actions$ = hot('-a', { + a: testTypeIdChanged({ + testTypeId: '1', + }), + }); + + expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-b', { + b: templateSectionsChanged({ + sectionTemplates: [], + sectionsValue: undefined, + }), + }); + }); + }); + + it('should return empty section templates if testTypeId doesnt apply to vehicleType', () => { + const testResult = createMockTestResult({ + vehicleType: VehicleTypes.PSV, + testTypes: [createMockTestType({ testTypeId: '190' })], + }); + + testScheduler.run(({ hot, expectObservable }) => { + store.overrideSelector(selectQueryParams, { edit: 'true' }); + store.overrideSelector(selectedTestResultState, testResult); + + actions$ = hot('-a', { + a: testTypeIdChanged({ + testTypeId: '190', + }), + }); + + expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-b', { + b: templateSectionsChanged({ + sectionTemplates: [], + sectionsValue: undefined, + }), + }); + }); + }); + + it('should return empty section templates if testTypeId is known but not in master template and edit is true', () => { + const testResult = createMockTestResult({ + vehicleType: VehicleTypes.PSV, + testTypes: [createMockTestType({ testTypeId: '39' })], + }); + + testScheduler.run(({ hot, expectObservable }) => { + store.overrideSelector(selectQueryParams, { edit: 'true' }); + store.overrideSelector(selectedTestResultState, testResult); + + actions$ = hot('-a', { + a: testTypeIdChanged({ + testTypeId: '39', + }), + }); + + expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-b', { + b: templateSectionsChanged({ + sectionTemplates: [], + sectionsValue: undefined, + }), + }); + }); + }); + + it('should return default section templates if testTypeId is known but not in master template and edit is false', () => { + const testResult = createMockTestResult({ + vehicleType: VehicleTypes.PSV, + testTypes: [createMockTestType({ testTypeId: '39' })], + }); + testScheduler.run(({ hot, expectObservable }) => { + store.overrideSelector(selectQueryParams, { edit: 'false' }); + store.overrideSelector(selectedTestResultState, testResult); + + actions$ = hot('-a', { + a: testTypeIdChanged({ + testTypeId: '39', + }), + }); + + expectObservable(effects.generateSectionTemplatesAndtestResultToUpdate$).toBe('-(bc)', { + b: templateSectionsChanged({ + sectionTemplates: Object.values(masterTpl.psv['default'] as Record), + sectionsValue: { testTypes: [{ testTypeId: '39' }] } as unknown as TestResultModel, + }), + c: updateResultOfTest(), + }); + }); + }); + }); + + describe('generateContingencyTestTemplatesAndtestResultToUpdate$', () => { + beforeEach(() => { + store.resetSelectors(); + jest.resetModules(); + }); + + it('should dispatch templateSectionsChanged with new sections and test result', () => { + const testResult = createMockTestResult({ + vehicleType: VehicleTypes.PSV, + testTypes: [createMockTestType({ testTypeId: '1' })], + }); + + store.overrideSelector(testResultInEdit, testResult); + + testScheduler.run(({ hot, expectObservable }) => { + actions$ = hot('-a', { + a: contingencyTestTypeSelected({ + testType: '1', + }), + }); + + expectObservable(effects.generateContingencyTestTemplatesAndtestResultToUpdate$).toBe('-b', { + b: templateSectionsChanged({ + sectionTemplates: Object.values( + contingencyTestTemplates.psv['testTypesGroup1'] as Record + ), + sectionsValue: { + contingencyTestNumber: undefined, + countryOfRegistration: '', + createdById: undefined, + createdByName: undefined, + euVehicleCategory: EUVehicleCategory.M1, + firstUseDate: null, + lastUpdatedAt: undefined, + lastUpdatedById: undefined, + lastUpdatedByName: undefined, + noOfAxles: undefined, + numberOfSeats: undefined, + numberOfWheelsDriven: undefined, + odometerReading: 0, + odometerReadingUnits: OdometerReadingUnits.KILOMETRES, + preparerId: '', + preparerName: '', + reasonForCancellation: undefined, + reasonForCreation: undefined, + regnDate: undefined, + source: undefined, + shouldEmailCertificate: undefined, + systemNumber: '', + testEndTimestamp: '', + testResultId: '', + testStartTimestamp: '', + testStationName: '', + testStationPNumber: '', + testStationType: 'atf', + testStatus: undefined, + testTypes: [ + { + additionalCommentsForAbandon: null, + additionalNotesRecorded: '', + certificateLink: undefined, + certificateNumber: '', + customDefects: [], + defects: [], + deletionFlag: undefined, + lastSeatbeltInstallationCheckDate: '', + name: '', + numberOfSeatbeltsFitted: 0, + prohibitionIssued: false, + reasonForAbandoning: '', + seatbeltInstallationCheckDate: false, + secondaryCertificateNumber: null, + testExpiryDate: '', + testResult: resultOfTestEnum.fail, + testTypeEndTimestamp: '', + testTypeId: '1', + testTypeName: '', + testTypeStartTimestamp: '', + }, + ], + testerEmailAddress: '', + testerName: '', + testerStaffId: '', + typeOfTest: TypeOfTest.CONTINGENCY, + vehicleClass: null, + vehicleConfiguration: undefined, + vehicleSize: undefined, + vehicleType: 'psv', + vin: '', + vrm: '', + } as unknown as TestResultModel, + }), + }); + }); + }); + + it('should dispatch templateSectionsChanged with old sections for IVA when flag is false', () => { + const testResult = createMockTestResult({ + vehicleType: VehicleTypes.PSV, + testTypes: [createMockTestType({ testTypeId: '126' })], + }); + jest.spyOn(featureToggleService, 'isFeatureEnabled').mockReturnValue(false); + store.overrideSelector(testResultInEdit, testResult); + + testScheduler.run(({ hot, expectObservable }) => { + actions$ = hot('-a', { + a: contingencyTestTypeSelected({ + testType: '126', + }), + }); + + expectObservable(effects.generateContingencyTestTemplatesAndtestResultToUpdate$).toBe('-b', { + b: templateSectionsChanged({ + sectionTemplates: Object.values( + contingencyTestTemplates.psv['testTypesSpecialistGroup1OldIVAorMSVA'] as Record + ), + sectionsValue: { + contingencyTestNumber: undefined, + countryOfRegistration: '', + createdById: undefined, + createdByName: undefined, + euVehicleCategory: EUVehicleCategory.M1, + firstUseDate: null, + lastUpdatedAt: undefined, + lastUpdatedById: undefined, + lastUpdatedByName: undefined, + noOfAxles: undefined, + numberOfSeats: undefined, + numberOfWheelsDriven: undefined, + odometerReading: 0, + odometerReadingUnits: OdometerReadingUnits.KILOMETRES, + preparerId: '', + preparerName: '', + reasonForCancellation: undefined, + reasonForCreation: undefined, + regnDate: undefined, + source: undefined, + shouldEmailCertificate: undefined, + systemNumber: '', + testEndTimestamp: '', + testResultId: '', + testStartTimestamp: '', + testStationName: '', + testStationPNumber: '', + testStationType: 'atf', + testStatus: undefined, + testTypes: [ + { + additionalCommentsForAbandon: null, + additionalNotesRecorded: '', + certificateLink: undefined, + certificateNumber: '', + customDefects: [], + defects: [], + deletionFlag: undefined, + lastSeatbeltInstallationCheckDate: '', + name: '', + numberOfSeatbeltsFitted: 0, + prohibitionIssued: false, + reasonForAbandoning: '', + seatbeltInstallationCheckDate: false, + secondaryCertificateNumber: null, + testResult: resultOfTestEnum.fail, + testTypeEndTimestamp: '', + testTypeId: '126', + testTypeName: '', + testTypeStartTimestamp: '', + }, + ], + testerEmailAddress: '', + testerName: '', + testerStaffId: '', + typeOfTest: TypeOfTest.CONTINGENCY, + vehicleClass: null, + vehicleConfiguration: undefined, + vehicleSize: undefined, + vehicleType: 'psv', + vin: '', + vrm: '', + } as unknown as TestResultModel, + }), + }); + }); + }); + + it('should return empty section templates if action testResult.vehicleType === undefined', () => { + const testResult = createMockTestResult({ + vehicleType: undefined, + testTypes: [createMockTestType({ testTypeId: '1' })], + }); + + testScheduler.run(({ hot, expectObservable }) => { + store.overrideSelector(testResultInEdit, testResult); + actions$ = hot('-a', { + a: contingencyTestTypeSelected({ + testType: '1', + }), + }); + + expectObservable(effects.generateContingencyTestTemplatesAndtestResultToUpdate$).toBe('-b', { + b: templateSectionsChanged({ + sectionTemplates: [], + sectionsValue: undefined, + }), + }); + }); + }); + }); + + describe('createTestResult$$', () => { + it('should return createTestResultSuccess action on successfull API call', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const testResult: TestResultModel = mockTestResult(); + // mock action to trigger effect + actions$ = hot('-a--', { a: createTestResult({ value: testResult }) }); + // mock service call + jest + .spyOn(testResultsService, 'postTestResult') + .mockReturnValue(cold('---b|', { b: testResult }) as unknown as Observable>); + + // expect effect to return success action + expectObservable(effects.createTestResult$).toBe('----b', { + b: createTestResultSuccess({ payload: { id: testResult.testResultId, changes: testResult } }), + }); + }); + }); + + it('should return createTestResultFailed', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const testResult: TestResultModel = mockTestResult(); + actions$ = hot('-a--', { a: createTestResult({ value: testResult }) }); + + const expectedError = new HttpErrorResponse({ + status: 500, + statusText: 'Internal server error', + }); + + jest.spyOn(testResultsService, 'postTestResult').mockReturnValue(cold('---#|', {}, expectedError)); + + expectObservable(effects.createTestResult$).toBe('----b', { + b: createTestResultFailed({ errors: [] }), + }); + }); + }); + + it('should return createTestResultFailed and add validation errors', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const testResult: TestResultModel = mockTestResult(); + actions$ = hot('-a--', { a: createTestResult({ value: testResult }) }); + + const expectedError = new HttpErrorResponse({ + status: 400, + error: { errors: ['"name" is missing', '"age" is missing', 'random error'] }, + }); + + jest.spyOn(testResultsService, 'postTestResult').mockReturnValue(cold('---#|', {}, expectedError)); + + const expectedErrors: GlobalError[] = [ + { error: '"name" is missing', anchorLink: 'name' }, + { error: '"age" is missing', anchorLink: 'age' }, + { error: 'random error', anchorLink: '' }, + ]; + + expectObservable(effects.createTestResult$).toBe('----b', { + b: createTestResultFailed({ errors: expectedErrors }), + }); + }); + }); + + it('should return createTestResultFailed and add a validation error', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const testResult: TestResultModel = mockTestResult(); + actions$ = hot('-a--', { a: createTestResult({ value: testResult }) }); + + const expectedError = new HttpErrorResponse({ + status: 400, + error: 'Certificate number not present on TIR test type', + }); + + jest.spyOn(testResultsService, 'postTestResult').mockReturnValue(cold('---#|', {}, expectedError)); + + const expectedErrors: GlobalError[] = [{ error: 'Certificate number not present on TIR test type' }]; + + expectObservable(effects.createTestResult$).toBe('----b', { + b: createTestResultFailed({ errors: expectedErrors }), + }); + }); + }); + }); }); diff --git a/src/app/store/test-records/effects/test-records.effects.ts b/src/app/store/test-records/effects/test-records.effects.ts index e067016758..1fd6ebe83f 100644 --- a/src/app/store/test-records/effects/test-records.effects.ts +++ b/src/app/store/test-records/effects/test-records.effects.ts @@ -21,293 +21,334 @@ import { updateResultOfTest } from '@store/test-records'; import { getTestStationFromProperty } from '@store/test-stations'; import { selectTestType } from '@store/test-types/selectors/test-types.selectors'; import merge from 'lodash.merge'; +import { catchError, concatMap, delay, filter, map, mergeMap, of, switchMap, take, withLatestFrom } from 'rxjs'; import { - catchError, concatMap, delay, filter, map, mergeMap, of, switchMap, take, - withLatestFrom, -} from 'rxjs'; -import { - contingencyTestTypeSelected, - createTestResult, - createTestResultFailed, - createTestResultSuccess, - editingTestResult, - fetchSelectedTestResult, - fetchSelectedTestResultFailed, - fetchSelectedTestResultSuccess, - fetchTestResultsBySystemNumber, - fetchTestResultsBySystemNumberFailed, - fetchTestResultsBySystemNumberSuccess, - templateSectionsChanged, - testTypeIdChanged, - updateTestResult, - updateTestResultFailed, - updateTestResultSuccess, + contingencyTestTypeSelected, + createTestResult, + createTestResultFailed, + createTestResultSuccess, + editingTestResult, + fetchSelectedTestResult, + fetchSelectedTestResultFailed, + fetchSelectedTestResultSuccess, + fetchTestResultsBySystemNumber, + fetchTestResultsBySystemNumberFailed, + fetchTestResultsBySystemNumberSuccess, + templateSectionsChanged, + testTypeIdChanged, + updateTestResult, + updateTestResultFailed, + updateTestResultSuccess, } from '../actions/test-records.actions'; import { - isTestTypeOldIvaOrMsva, - selectAllTestResultsInDateOrder, - selectedTestResultState, - testResultInEdit, + isTestTypeOldIvaOrMsva, + selectAllTestResultsInDateOrder, + selectedTestResultState, + testResultInEdit, } from '../selectors/test-records.selectors'; @Injectable() export class TestResultsEffects { - fetchTestResultsBySystemNumber$ = createEffect(() => - this.actions$.pipe( - ofType(fetchTestResultsBySystemNumber), - mergeMap(({ systemNumber }) => - this.testRecordsService.fetchTestResultbySystemNumber(systemNumber, { fromDateTime: new Date(1970) }).pipe( - map((testResults) => fetchTestResultsBySystemNumberSuccess({ payload: testResults })), - catchError((e) => { - switch (e.status) { - case 404: - return of(fetchTestResultsBySystemNumberSuccess({ payload: [] as TestResultModel[] })); - default: return of(fetchTestResultsBySystemNumberFailed({ error: e.message })); - } - }), - )), - )); - - fetchSelectedTestResult$ = createEffect(() => - this.actions$.pipe( - ofType(fetchSelectedTestResult), - mergeMap(() => this.store.pipe(select(selectRouteNestedParams), take(1))), - mergeMap((params) => { - const { systemNumber, testResultId } = params; - return this.testRecordsService - .fetchTestResultbySystemNumber(systemNumber, { fromDateTime: new Date(1970), testResultId, version: 'all' }) - .pipe( - map((vehicleTestRecords) => { - if (vehicleTestRecords && vehicleTestRecords.length === 1) { - return fetchSelectedTestResultSuccess({ payload: vehicleTestRecords[0] }); - } - return fetchSelectedTestResultFailed({ error: 'Test result not found' }); + fetchTestResultsBySystemNumber$ = createEffect(() => + this.actions$.pipe( + ofType(fetchTestResultsBySystemNumber), + mergeMap(({ systemNumber }) => + this.testRecordsService.fetchTestResultbySystemNumber(systemNumber, { fromDateTime: new Date(1970) }).pipe( + map((testResults) => fetchTestResultsBySystemNumberSuccess({ payload: testResults })), + catchError((e) => { + switch (e.status) { + case 404: + return of(fetchTestResultsBySystemNumberSuccess({ payload: [] as TestResultModel[] })); + default: + return of(fetchTestResultsBySystemNumberFailed({ error: e.message })); + } + }) + ) + ) + ) + ); - }), - catchError((e) => { - return of(fetchSelectedTestResultFailed({ error: e.message })); - }), - ); - }), - )); + fetchSelectedTestResult$ = createEffect(() => + this.actions$.pipe( + ofType(fetchSelectedTestResult), + mergeMap(() => this.store.pipe(select(selectRouteNestedParams), take(1))), + mergeMap((params) => { + const { systemNumber, testResultId } = params; + return this.testRecordsService + .fetchTestResultbySystemNumber(systemNumber, { fromDateTime: new Date(1970), testResultId, version: 'all' }) + .pipe( + map((vehicleTestRecords) => { + if (vehicleTestRecords && vehicleTestRecords.length === 1) { + return fetchSelectedTestResultSuccess({ payload: vehicleTestRecords[0] }); + } + return fetchSelectedTestResultFailed({ error: 'Test result not found' }); + }), + catchError((e) => { + return of(fetchSelectedTestResultFailed({ error: e.message })); + }) + ); + }) + ) + ); - /** - * Call POST Test Results API to update test result - */ - createTestResult$ = createEffect(() => - this.actions$.pipe( - ofType(createTestResult), - switchMap((action) => { - const testResult = action.value; - return this.testRecordsService.postTestResult(testResult).pipe( - take(1), - map(() => createTestResultSuccess({ payload: { id: testResult.testResultId, changes: testResult } })), - catchError((e) => { - const validationsErrors: GlobalError[] = []; - if (e.status === 400) { - const { - error: { errors }, - } = e; - // eslint-disable-next-line @typescript-eslint/no-unused-expressions, no-unused-expressions - Array.isArray(errors) - ? errors.forEach((error: string) => { - const field = error.match(/"([^"]+)"/); - validationsErrors.push({ error, anchorLink: field && field.length > 1 ? field[1].replace('"', '') : '' }); - }) - : validationsErrors.push({ error: e.error }); - } else if (e.status === 502) { - validationsErrors.push({ error: 'Internal Server Error, please contact technical support', anchorLink: '' }); - } - return of(createTestResultFailed({ errors: validationsErrors })); - }), - ); - }), - )); + /** + * Call POST Test Results API to update test result + */ + createTestResult$ = createEffect(() => + this.actions$.pipe( + ofType(createTestResult), + switchMap((action) => { + const testResult = action.value; + return this.testRecordsService.postTestResult(testResult).pipe( + take(1), + map(() => createTestResultSuccess({ payload: { id: testResult.testResultId, changes: testResult } })), + catchError((e) => { + const validationsErrors: GlobalError[] = []; + if (e.status === 400) { + const { + error: { errors }, + } = e; + // eslint-disable-next-line @typescript-eslint/no-unused-expressions, no-unused-expressions + Array.isArray(errors) + ? errors.forEach((error: string) => { + const field = error.match(/"([^"]+)"/); + validationsErrors.push({ + error, + anchorLink: field && field.length > 1 ? field[1].replace('"', '') : '', + }); + }) + : validationsErrors.push({ error: e.error }); + } else if (e.status === 502) { + validationsErrors.push({ + error: 'Internal Server Error, please contact technical support', + anchorLink: '', + }); + } + return of(createTestResultFailed({ errors: validationsErrors })); + }) + ); + }) + ) + ); - /** - * Call PUT Test Results API to update test result - */ - updateTestResult$ = createEffect(() => - this.actions$.pipe( - ofType(updateTestResult), - mergeMap((action) => - of(action.value).pipe( - withLatestFrom( - this.userService.name$, - this.userService.id$, - this.userService.userEmail$, - this.store.select(selectRouteNestedParams), - this.store.select(selectAllTestResultsInDateOrder), - ), - take(1), - )), - mergeMap(([testResult, name, id, userEmail, { systemNumber }, testResults]) => { - return this.testRecordsService.saveTestResult( - systemNumber, - { name, id, userEmail }, - this.testRecordsService.prepareTestResultForAmendment(testResults, testResult), - ).pipe( - take(1), - map((responseBody) => updateTestResultSuccess({ payload: { id: responseBody.testResultId, changes: responseBody } })), - catchError((e) => { - const validationsErrors: GlobalError[] = []; - if (e.status === 400) { - const { - error: { errors }, - } = e; - errors.forEach((error: string) => { - const field = error.match(/"([^"]+)"/); - validationsErrors.push({ error, anchorLink: field && field.length > 1 ? field[1].replace('"', '') : '' }); - }); - } else if (e.status === 502) { - validationsErrors.push({ error: 'Internal Server Error, please contact technical support', anchorLink: '' }); - } - return of(updateTestResultFailed({ errors: validationsErrors })); - }), - ); - }), - )); + /** + * Call PUT Test Results API to update test result + */ + updateTestResult$ = createEffect(() => + this.actions$.pipe( + ofType(updateTestResult), + mergeMap((action) => + of(action.value).pipe( + withLatestFrom( + this.userService.name$, + this.userService.id$, + this.userService.userEmail$, + this.store.select(selectRouteNestedParams), + this.store.select(selectAllTestResultsInDateOrder) + ), + take(1) + ) + ), + mergeMap(([testResult, name, id, userEmail, { systemNumber }, testResults]) => { + return this.testRecordsService + .saveTestResult( + systemNumber, + { name, id, userEmail }, + this.testRecordsService.prepareTestResultForAmendment(testResults, testResult) + ) + .pipe( + take(1), + map((responseBody) => + updateTestResultSuccess({ payload: { id: responseBody.testResultId, changes: responseBody } }) + ), + catchError((e) => { + const validationsErrors: GlobalError[] = []; + if (e.status === 400) { + const { + error: { errors }, + } = e; + errors.forEach((error: string) => { + const field = error.match(/"([^"]+)"/); + validationsErrors.push({ + error, + anchorLink: field && field.length > 1 ? field[1].replace('"', '') : '', + }); + }); + } else if (e.status === 502) { + validationsErrors.push({ + error: 'Internal Server Error, please contact technical support', + anchorLink: '', + }); + } + return of(updateTestResultFailed({ errors: validationsErrors })); + }) + ); + }) + ) + ); - generateSectionTemplatesAndtestResultToUpdate$ = createEffect(() => - this.actions$.pipe( - ofType(editingTestResult, testTypeIdChanged), - mergeMap((action) => - of(action).pipe(withLatestFrom( - this.store.pipe(select(selectedTestResultState)), - this.store.pipe(select(selectQueryParam('edit'))), - this.store.pipe(select(isTestTypeOldIvaOrMsva)), - ), take(1))), - concatMap(([action, selectedTestResult, isEditing, isOldIVAorMSVAtest]) => { - const { testTypeId } = action; + generateSectionTemplatesAndtestResultToUpdate$ = createEffect(() => + this.actions$.pipe( + ofType(editingTestResult, testTypeIdChanged), + mergeMap((action) => + of(action).pipe( + withLatestFrom( + this.store.pipe(select(selectedTestResultState)), + this.store.pipe(select(selectQueryParam('edit'))), + this.store.pipe(select(isTestTypeOldIvaOrMsva)) + ), + take(1) + ) + ), + concatMap(([action, selectedTestResult, isEditing, isOldIVAorMSVAtest]) => { + const { testTypeId } = action; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const { vehicleType } = selectedTestResult!; - if (!vehicleType || !Object.prototype.hasOwnProperty.call(masterTpl, vehicleType)) { - return of(templateSectionsChanged({ sectionTemplates: [], sectionsValue: undefined })); - } - const testTypeGroup = TestRecordsService.getTestTypeGroup(testTypeId); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const { vehicleType } = selectedTestResult!; + if (!vehicleType || !Object.prototype.hasOwnProperty.call(masterTpl, vehicleType)) { + return of(templateSectionsChanged({ sectionTemplates: [], sectionsValue: undefined })); + } + const testTypeGroup = TestRecordsService.getTestTypeGroup(testTypeId); - // tech-debt: feature flag check to be removed when required standard is enabled - const isRequiredStandardsEnabled = this.featureToggleService.isFeatureEnabled('requiredStandards'); - const isIVAorMSVATest = testTypeGroup === 'testTypesSpecialistGroup1' || testTypeGroup === 'testTypesSpecialistGroup5'; + // tech-debt: feature flag check to be removed when required standard is enabled + const isRequiredStandardsEnabled = this.featureToggleService.isFeatureEnabled('requiredStandards'); + const isIVAorMSVATest = + testTypeGroup === 'testTypesSpecialistGroup1' || testTypeGroup === 'testTypesSpecialistGroup5'; - const vehicleTpl = masterTpl[`${vehicleType}`]; - const testTypeGroupString = (!isRequiredStandardsEnabled || isOldIVAorMSVAtest) - && isIVAorMSVATest ? `${testTypeGroup}OldIVAorMSVA` : testTypeGroup; + const vehicleTpl = masterTpl[`${vehicleType}`]; + const testTypeGroupString = + (!isRequiredStandardsEnabled || isOldIVAorMSVAtest) && isIVAorMSVATest + ? `${testTypeGroup}OldIVAorMSVA` + : testTypeGroup; - let tpl; - if (testTypeGroupString && Object.prototype.hasOwnProperty.call(vehicleTpl, testTypeGroupString)) { - tpl = vehicleTpl[testTypeGroupString as keyof typeof TEST_TYPES]; - } else if (isEditing === 'true') { - tpl = undefined; - } else { - tpl = vehicleTpl['default']; - } + let tpl; + if (testTypeGroupString && Object.prototype.hasOwnProperty.call(vehicleTpl, testTypeGroupString)) { + tpl = vehicleTpl[testTypeGroupString as keyof typeof TEST_TYPES]; + } else if (isEditing === 'true') { + tpl = undefined; + } else { + tpl = vehicleTpl['default']; + } - if (!tpl) { - return of(templateSectionsChanged({ sectionTemplates: [], sectionsValue: undefined })); - } + if (!tpl) { + return of(templateSectionsChanged({ sectionTemplates: [], sectionsValue: undefined })); + } - const mergedForms = {}; - Object.values(tpl).forEach((node) => { - const form = this.dfs.createForm(node, selectedTestResult); - merge(mergedForms, form.getCleanValue(form)); - }); + const mergedForms = {}; + Object.values(tpl).forEach((node) => { + const form = this.dfs.createForm(node, selectedTestResult); + merge(mergedForms, form.getCleanValue(form)); + }); - if (testTypeId) { - (mergedForms as TestResultModel).testTypes[0].testTypeId = testTypeId; - } + if (testTypeId) { + (mergedForms as TestResultModel).testTypes[0].testTypeId = testTypeId; + } - return of( - templateSectionsChanged({ sectionTemplates: Object.values(tpl), sectionsValue: mergedForms as TestResultModel }), - updateResultOfTest(), - ); - }), - )); + return of( + templateSectionsChanged({ + sectionTemplates: Object.values(tpl), + sectionsValue: mergedForms as TestResultModel, + }), + updateResultOfTest() + ); + }) + ) + ); - generateContingencyTestTemplatesAndtestResultToUpdate$ = createEffect(() => - this.actions$.pipe( - ofType(contingencyTestTypeSelected), - mergeMap((action) => - of(action).pipe( - withLatestFrom( - this.store.select(testResultInEdit), - this.store.select(selectTestType(action.testType)), - this.store.select(getTestStationFromProperty('testStationType', TestStationType.HQ)), - this.userService.user$, - ), - take(1), - )), - concatMap(([action, editedTestResult, testTypeTaxonomy, testStation, user]) => { - const id = action.testType; + generateContingencyTestTemplatesAndtestResultToUpdate$ = createEffect(() => + this.actions$.pipe( + ofType(contingencyTestTypeSelected), + mergeMap((action) => + of(action).pipe( + withLatestFrom( + this.store.select(testResultInEdit), + this.store.select(selectTestType(action.testType)), + this.store.select(getTestStationFromProperty('testStationType', TestStationType.HQ)), + this.userService.user$ + ), + take(1) + ) + ), + concatMap(([action, editedTestResult, testTypeTaxonomy, testStation, user]) => { + const id = action.testType; - const vehicleType = editedTestResult?.vehicleType; - if (!vehicleType || !Object.prototype.hasOwnProperty.call(contingencyTestTemplates, vehicleType)) { - return of(templateSectionsChanged({ sectionTemplates: [], sectionsValue: undefined })); - } + const vehicleType = editedTestResult?.vehicleType; + if (!vehicleType || !Object.prototype.hasOwnProperty.call(contingencyTestTemplates, vehicleType)) { + return of(templateSectionsChanged({ sectionTemplates: [], sectionsValue: undefined })); + } - const testTypeGroup = TestRecordsService.getTestTypeGroup(id); - // tech-debt: feature flag check to be removed when required standard is enabled - const isRequiredStandardsEnabled = this.featureToggleService.isFeatureEnabled('requiredStandards'); - const isIVAorMSVATest = testTypeGroup === 'testTypesSpecialistGroup1' || testTypeGroup === 'testTypesSpecialistGroup5'; + const testTypeGroup = TestRecordsService.getTestTypeGroup(id); + // tech-debt: feature flag check to be removed when required standard is enabled + const isRequiredStandardsEnabled = this.featureToggleService.isFeatureEnabled('requiredStandards'); + const isIVAorMSVATest = + testTypeGroup === 'testTypesSpecialistGroup1' || testTypeGroup === 'testTypesSpecialistGroup5'; - const vehicleTpl = contingencyTestTemplates[`${vehicleType}`]; - const testTypeGroupString = !isRequiredStandardsEnabled && isIVAorMSVATest ? `${testTypeGroup}OldIVAorMSVA` : testTypeGroup; + const vehicleTpl = contingencyTestTemplates[`${vehicleType}`]; + const testTypeGroupString = + !isRequiredStandardsEnabled && isIVAorMSVATest ? `${testTypeGroup}OldIVAorMSVA` : testTypeGroup; - const tpl = testTypeGroupString && Object.prototype.hasOwnProperty.call(vehicleTpl, testTypeGroupString) - ? vehicleTpl[testTypeGroupString as keyof typeof TEST_TYPES] - : vehicleTpl['default']; + const tpl = + testTypeGroupString && Object.prototype.hasOwnProperty.call(vehicleTpl, testTypeGroupString) + ? vehicleTpl[testTypeGroupString as keyof typeof TEST_TYPES] + : vehicleTpl['default']; - const mergedForms = {} as TestResultModel; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - Object.values(tpl!).forEach((node) => { - const form = this.dfs.createForm(node, editedTestResult); - merge(mergedForms, form.getCleanValue(form)); - }); + const mergedForms = {} as TestResultModel; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + Object.values(tpl!).forEach((node) => { + const form = this.dfs.createForm(node, editedTestResult); + merge(mergedForms, form.getCleanValue(form)); + }); - mergedForms.testTypes[0].testTypeId = id; - mergedForms.testTypes[0].name = testTypeTaxonomy?.name ?? ''; - mergedForms.testTypes[0].testTypeName = testTypeTaxonomy?.testTypeName ?? ''; - mergedForms.typeOfTest = (testTypeTaxonomy?.typeOfTest as TypeOfTest) ?? TypeOfTest.CONTINGENCY; + mergedForms.testTypes[0].testTypeId = id; + mergedForms.testTypes[0].name = testTypeTaxonomy?.name ?? ''; + mergedForms.testTypes[0].testTypeName = testTypeTaxonomy?.testTypeName ?? ''; + mergedForms.typeOfTest = (testTypeTaxonomy?.typeOfTest as TypeOfTest) ?? TypeOfTest.CONTINGENCY; - const now = new Date().toISOString(); + const now = new Date().toISOString(); - if (mergedForms.typeOfTest !== TypeOfTest.CONTINGENCY) { - mergedForms.testerName = user.name; - mergedForms.testerEmailAddress = user.userEmail; - mergedForms.testerStaffId = user.oid; - mergedForms.testStartTimestamp = now; - mergedForms.testEndTimestamp = now; - mergedForms.testTypes[0].testTypeStartTimestamp = now; - mergedForms.testTypes[0].testTypeEndTimestamp = now; - mergedForms.testStationName = testStation?.testStationName ?? '[INVALID_OPTION]'; - mergedForms.testStationPNumber = testStation?.testStationPNumber ?? '[INVALID_OPTION]'; - mergedForms.testStationType = TestStationType.ATF; - } + if (mergedForms.typeOfTest !== TypeOfTest.CONTINGENCY) { + mergedForms.testerName = user.name; + mergedForms.testerEmailAddress = user.userEmail; + mergedForms.testerStaffId = user.oid; + mergedForms.testStartTimestamp = now; + mergedForms.testEndTimestamp = now; + mergedForms.testTypes[0].testTypeStartTimestamp = now; + mergedForms.testTypes[0].testTypeEndTimestamp = now; + mergedForms.testStationName = testStation?.testStationName ?? '[INVALID_OPTION]'; + mergedForms.testStationPNumber = testStation?.testStationPNumber ?? '[INVALID_OPTION]'; + mergedForms.testStationType = TestStationType.ATF; + } - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - return of(templateSectionsChanged({ sectionTemplates: Object.values(tpl!), sectionsValue: mergedForms })); - }), - )); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return of(templateSectionsChanged({ sectionTemplates: Object.values(tpl!), sectionsValue: mergedForms })); + }) + ) + ); - createTestResultSuccess$ = createEffect(() => this.actions$.pipe( - ofType(createTestResultSuccess), - delay(3000), - map((action) => action.payload.changes.systemNumber as string), - switchMap((systemNumber) => this.techRecordHttpService.getBySystemNumber$(systemNumber)), - map((results) => results.find((result) => result.techRecord_statusCode === StatusCodes.CURRENT)), - filter(Boolean), - switchMap((techRecord) => this.router.navigate(['tech-records', techRecord.systemNumber, techRecord.createdTimestamp])), - ), { dispatch: false }); + createTestResultSuccess$ = createEffect( + () => + this.actions$.pipe( + ofType(createTestResultSuccess), + delay(3000), + map((action) => action.payload.changes.systemNumber as string), + switchMap((systemNumber) => this.techRecordHttpService.getBySystemNumber$(systemNumber)), + map((results) => results.find((result) => result.techRecord_statusCode === StatusCodes.CURRENT)), + filter(Boolean), + switchMap((techRecord) => + this.router.navigate(['tech-records', techRecord.systemNumber, techRecord.createdTimestamp]) + ) + ), + { dispatch: false } + ); - constructor( - private actions$: Actions, - private testRecordsService: TestRecordsService, - private techRecordHttpService: TechnicalRecordHttpService, - private store: Store, - private router: Router, - private userService: UserService, - private dfs: DynamicFormService, - private featureToggleService: FeatureToggleService, - ) { } + constructor( + private actions$: Actions, + private testRecordsService: TestRecordsService, + private techRecordHttpService: TechnicalRecordHttpService, + private store: Store, + private router: Router, + private userService: UserService, + private dfs: DynamicFormService, + private featureToggleService: FeatureToggleService + ) {} } diff --git a/src/app/store/test-records/reducers/test-records.reducer.spec.ts b/src/app/store/test-records/reducers/test-records.reducer.spec.ts index 7fa7042e6d..bc3eead17a 100644 --- a/src/app/store/test-records/reducers/test-records.reducer.spec.ts +++ b/src/app/store/test-records/reducers/test-records.reducer.spec.ts @@ -4,546 +4,543 @@ import { TestResultModel } from '@models/test-results/test-result.model'; import { Action } from '@ngrx/store'; import { mockTestResultList } from '../../../../mocks/mock-test-result'; import { - cleanTestResult, - createDefect, - createRequiredStandard, - fetchSelectedTestResult, - fetchSelectedTestResultFailed, - fetchSelectedTestResultSuccess, - fetchTestResults, - fetchTestResultsBySystemNumber, - fetchTestResultsBySystemNumberFailed, - fetchTestResultsBySystemNumberSuccess, - fetchTestResultsSuccess, - removeDefect, - removeRequiredStandard, - updateDefect, - updateRequiredStandard, - updateResultOfTest, - updateTestResult, - updateTestResultFailed, - updateTestResultSuccess, + cleanTestResult, + createDefect, + createRequiredStandard, + fetchSelectedTestResult, + fetchSelectedTestResultFailed, + fetchSelectedTestResultSuccess, + fetchTestResults, + fetchTestResultsBySystemNumber, + fetchTestResultsBySystemNumberFailed, + fetchTestResultsBySystemNumberSuccess, + fetchTestResultsSuccess, + removeDefect, + removeRequiredStandard, + updateDefect, + updateRequiredStandard, + updateResultOfTest, + updateTestResult, + updateTestResultFailed, + updateTestResultSuccess, } from '../actions/test-records.actions'; import { TestResultsState, initialTestResultsState, testResultsReducer } from './test-records.reducer'; describe('Test Results Reducer', () => { - describe('unknown action', () => { - it('should return the default state', () => { - const action = { - type: 'Unknown', - }; - const state = testResultsReducer(initialTestResultsState, action); - - expect(state).toBe(initialTestResultsState); - }); - }); - - describe('fetchTestResults', () => { - it('should set loading to true', () => { - const oldState: TestResultsState = { ...initialTestResultsState, loading: false }; - const action = fetchTestResults(); - const state = testResultsReducer(oldState, action); - - expect(state.loading).toBe(true); - expect(state).not.toBe(oldState); - }); - }); - - describe('fetchTestResultsSuccess', () => { - it('should set all test result records', () => { - const testResults = mockTestResultList(3); - const newState: TestResultsState = { - ...initialTestResultsState, - ids: ['TestResultId0001', 'TestResultId0002', 'TestResultId0003'], - entities: { TestResultId0001: testResults[0], TestResultId0002: testResults[1], TestResultId0003: testResults[2] }, - }; - const action = fetchTestResultsSuccess({ payload: testResults }); - const state = testResultsReducer(initialTestResultsState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('fetchTestResultsBySystemNumber actions', () => { - it('should set loading to true', () => { - const newState: TestResultsState = { ...initialTestResultsState, loading: true }; - const action = fetchTestResultsBySystemNumber({ systemNumber: 'TestResultId0001' }); - const state = testResultsReducer(initialTestResultsState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - - describe('fetchTestResultsBySystemNumberSuccess', () => { - it('should set all test result records', () => { - const testResults = mockTestResultList(); - const newState: TestResultsState = { - ...initialTestResultsState, - ids: ['TestResultId0001'], - entities: { TestResultId0001: testResults[0] }, - }; - const action = fetchTestResultsBySystemNumberSuccess({ payload: testResults }); - const state = testResultsReducer(initialTestResultsState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('fetchTestResultsBySystemNumberFailed', () => { - it('should set error state', () => { - const newState = { ...initialTestResultsState, loading: false }; - const action = fetchTestResultsBySystemNumberFailed({ error: 'unit testing error message' }); - const state = testResultsReducer({ ...initialTestResultsState, loading: true }, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - }); - - describe('fetchSelectedTestResult actions', () => { - it('should set loading to true', () => { - const newState: TestResultsState = { ...initialTestResultsState, loading: true }; - const action = fetchSelectedTestResult(); - const state = testResultsReducer(initialTestResultsState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - - describe('fetchSelectedTestResultSuccess', () => { - it('should set all test result records', () => { - const testResults = mockTestResultList(); - const updatedTestResult = { ...testResults[0], odometerReading: 99999 }; - - const newState: TestResultsState = { - ...initialTestResultsState, - ids: [updatedTestResult.testResultId], - entities: { [updatedTestResult.testResultId]: updatedTestResult }, - }; - const action = fetchSelectedTestResultSuccess({ payload: updatedTestResult }); - const state = testResultsReducer(initialTestResultsState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('fetchSelectedTestResultFailed', () => { - it('should set error state', () => { - const newState = { ...initialTestResultsState, loading: false }; - const action = fetchSelectedTestResultFailed({ error: 'unit testing error message' }); - const state = testResultsReducer({ ...initialTestResultsState, loading: true }, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - }); - - describe('updateTestResult actions', () => { - it('should set loading to true', () => { - const state: TestResultsState = { ...initialTestResultsState, loading: true }; - const action = updateTestResult({ value: {} as TestResultModel }); - const newState = testResultsReducer(initialTestResultsState, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - - describe('updateTestResultSuccess', () => { - it('should set loading to false', () => { - const state: TestResultsState = { ...initialTestResultsState, loading: false }; - const action = updateTestResultSuccess({ payload: { id: '', changes: {} as TestResultModel } }); - const newState = testResultsReducer({ ...initialTestResultsState, loading: true }, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - - describe('updateTestResultFailed', () => { - it('should set loading to false', () => { - const state: TestResultsState = { ...initialTestResultsState, loading: false }; - const action = updateTestResultFailed({ errors: [] }); - const newState = testResultsReducer({ ...initialTestResultsState, loading: true }, action); - - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - }); - - describe('calculateTestResult', () => { - let action: Action; - beforeEach(() => { - action = updateResultOfTest(); - }); - - it('should return a testType with a testResult of pass if empty defects', () => { - const testResult = { - testTypes: [ - { - testResult: 'fail', - defects: [], - }, - ], - } as unknown as TestResultModel; - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - expect(newState.editingTestResult?.testTypes[0].testResult).toBe('pass'); - }); - - it('should not change the test result of defects key is not present', () => { - const testResult = { - testTypes: [ - { - testResult: 'fail', - }, - ], - } as TestResultModel; - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - expect(newState.editingTestResult?.testTypes[0].testResult).toEqual(testResult.testTypes[0].testResult); - }); - it('should return a testType with a testResult of pass if advisory defect', () => { - const testResult = { - testTypes: [ - { - testResult: 'fail', - defects: [ - { - deficiencyCategory: 'advisory', - }, - ], - }, - ], - } as TestResultModel; - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - expect(newState.editingTestResult?.testTypes[0].testResult).toBe('pass'); - }); - it('should return a testType with a testResult of pass if minor defect', () => { - const testResult = { - testTypes: [ - { - testResult: 'fail', - defects: [ - { - deficiencyCategory: 'minor', - }, - ], - }, - ], - } as TestResultModel; - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - expect(newState.editingTestResult?.testTypes[0].testResult).toBe('pass'); - }); - it('should return a testType with a testResult of pass if minor and advisory defect', () => { - const testResult = { - testTypes: [ - { - testResult: 'fail', - defects: [ - { - deficiencyCategory: 'minor', - }, - { - deficiencyCategory: 'advisory', - }, - ], - }, - ], - } as TestResultModel; - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - expect(newState.editingTestResult?.testTypes[0].testResult).toBe('pass'); - }); - it('should return a testType with a testResult of fail if at least one major defect', () => { - const testResult = { - testTypes: [ - { - testResult: 'pass', - defects: [ - { - deficiencyCategory: 'major', - }, - { - deficiencyCategory: 'advisory', - }, - ], - }, - ], - } as TestResultModel; - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - expect(newState.editingTestResult?.testTypes[0].testResult).toBe('fail'); - }); - it('should return a testType with a testResult of fail if at least one dangerous defect', () => { - const testResult = { - testTypes: [ - { - testResult: 'pass', - defects: [ - { - deficiencyCategory: 'dangerous', - }, - { - deficiencyCategory: 'advisory', - }, - ], - }, - ], - } as TestResultModel; - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - expect(newState.editingTestResult?.testTypes[0].testResult).toBe('fail'); - }); - it('should return a testType with a testResult of prs if major defect is prs and other defects are advisory', () => { - const testResult = { - testTypes: [ - { - testResult: 'pass', - defects: [ - { - deficiencyCategory: 'major', - prs: true, - }, - { - deficiencyCategory: 'advisory', - }, - ], - }, - ], - } as TestResultModel; - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - expect(newState.editingTestResult?.testTypes[0].testResult).toBe('prs'); - }); - it('should return a testType with a testResult of fail if not all major/dangerous defects are prs', () => { - const testResult = { - testTypes: [ - { - testResult: 'pass', - defects: [ - { - deficiencyCategory: 'major', - }, - { - deficiencyCategory: 'dangerous', - prs: true, - }, - ], - }, - ], - } as TestResultModel; - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - expect(newState.editingTestResult?.testTypes[0].testResult).toBe('fail'); - }); - it('should handle multiple testTypes', () => { - const testResult = { - testTypes: [ - { - testResult: 'pass', - defects: [ - { - deficiencyCategory: 'major', - }, - { - deficiencyCategory: 'dangerous', - prs: true, - }, - ], - }, - { - testResult: 'pass', - defects: [ - { - deficiencyCategory: 'dangerous', - prs: true, - }, - ], - }, - { - testResult: 'fail', - defects: [ - { - deficiencyCategory: 'advisory', - prs: true, - }, - ], - }, - ], - } as TestResultModel; - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - expect(newState.editingTestResult?.testTypes[0].testResult).toBe('fail'); - expect(newState.editingTestResult?.testTypes[1].testResult).toBe('prs'); - expect(newState.editingTestResult?.testTypes[2].testResult).toBe('pass'); - }); - }); - - describe('createDefect', () => { - it('should create defect', () => { - const defect = { imNumber: 2 } as TestResultDefect; - const testResult = { - testTypes: [ - { - defects: [defect], - }, - ], - } as unknown as TestResultModel; - const action = createDefect({ defect }); - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - - expect(newState.editingTestResult?.testTypes[0].defects?.length).toBe(2); - }); - }); - - describe('updateDefect', () => { - it('should update defect', () => { - const defect = { imNumber: 2 } as TestResultDefect; - const newDefect = { imNumber: 1 } as TestResultDefect; - const testResult = { - testTypes: [ - { - defects: [defect], - }, - ], - } as unknown as TestResultModel; - const action = updateDefect({ defect: newDefect, index: 0 }); - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - - const path = newState.editingTestResult?.testTypes[0] - && newState.editingTestResult?.testTypes[0].defects - && newState.editingTestResult?.testTypes[0].defects[0].imNumber; - - expect(path).toBe(1); - }); - }); - - describe('removeDefect', () => { - it('should remove defect', () => { - const defect = { imNumber: 2 } as TestResultDefect; - const testResult = { - testTypes: [ - { - defects: [defect], - }, - ], - } as unknown as TestResultModel; - const action = removeDefect({ index: 0 }); - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - - expect(newState.editingTestResult?.testTypes[0].defects?.length).toBe(0); - }); - }); - - describe('createRequiredStandard', () => { - it('should create required standard', () => { - const requiredStandard = { sectionNumber: 2 } as unknown as TestResultRequiredStandard; - const testResult = { - testTypes: [ - { - requiredStandards: [requiredStandard], - }, - ], - } as unknown as TestResultModel; - const action = createRequiredStandard({ requiredStandard }); - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - - expect(newState.editingTestResult?.testTypes[0].requiredStandards?.length).toBe(2); - }); - }); - - describe('updateRequiredStandard', () => { - it('should update required standard', () => { - const requiredStandard = { sectionNumber: 2 } as unknown as TestResultRequiredStandard; - const newRequiredStandard = { sectionNumber: 1 } as unknown as TestResultRequiredStandard; - const testResult = { - testTypes: [ - { - requiredStandards: [requiredStandard], - }, - ], - } as unknown as TestResultModel; - const action = updateRequiredStandard({ requiredStandard: newRequiredStandard, index: 0 }); - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - - expect(newState.editingTestResult?.testTypes[0].requiredStandards?.length).toBe(1); - expect(newState.editingTestResult?.testTypes?.at(0)?.requiredStandards?.at(0)?.sectionNumber).toBe(1); - }); - }); - - describe('removeRequiredStandard', () => { - it('should remove required standard', () => { - const requiredStandard = { sectionNumber: 2 } as unknown as TestResultRequiredStandard; - const testResult = { - testTypes: [ - { - requiredStandards: [requiredStandard], - }, - ], - } as unknown as TestResultModel; - const action = removeRequiredStandard({ index: 0 }); - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - - expect(newState.editingTestResult?.testTypes[0].requiredStandards?.length).toBe(0); - }); - }); - - describe('cleanTestResultPayload', () => { - it('should return the state unaltered if no editing test result', () => { - const action = cleanTestResult(); - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: undefined }, action); - - expect(newState).toStrictEqual({ ...initialTestResultsState, editingTestResult: undefined }); - - }); - - it('should return the state unaltered if no test type', () => { - const editingTestResult = { - foo: 'bar', - } as unknown as TestResultModel; - - const action = cleanTestResult(); - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult }, action); - - expect(newState).toStrictEqual({ ...initialTestResultsState, editingTestResult }); - }); - - it('should return the state unaltered if required standards are populated', () => { - const editingTestResult = { - testTypes: [ - { requiredStandards: ['I am a RS'], testTypeId: '125' }, - ], - } as unknown as TestResultModel; - - const action = cleanTestResult(); - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult }, action); - - expect(newState).toStrictEqual({ ...initialTestResultsState, editingTestResult }); - }); - - it('should return the state unaltered if test type is not spec 1 or spec 5', () => { - const editingTestResult = { - testTypes: [ - { requiredStandards: ['I am a RS'], testTypeId: 'xyz' }, - ], - } as unknown as TestResultModel; - - const action = cleanTestResult(); - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult }, action); - - expect(newState).toStrictEqual({ ...initialTestResultsState, editingTestResult }); - - }); - - it('should delete RS if empty from state', () => { - const editingTestResult = { - testTypes: [ - { requiredStandards: [], testTypeId: '125' }, - ], - } as unknown as TestResultModel; - - const action = cleanTestResult(); - const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult }, action); - - expect(newState.editingTestResult?.testTypes[0].requiredStandards).toBeUndefined(); - }); - }); + describe('unknown action', () => { + it('should return the default state', () => { + const action = { + type: 'Unknown', + }; + const state = testResultsReducer(initialTestResultsState, action); + + expect(state).toBe(initialTestResultsState); + }); + }); + + describe('fetchTestResults', () => { + it('should set loading to true', () => { + const oldState: TestResultsState = { ...initialTestResultsState, loading: false }; + const action = fetchTestResults(); + const state = testResultsReducer(oldState, action); + + expect(state.loading).toBe(true); + expect(state).not.toBe(oldState); + }); + }); + + describe('fetchTestResultsSuccess', () => { + it('should set all test result records', () => { + const testResults = mockTestResultList(3); + const newState: TestResultsState = { + ...initialTestResultsState, + ids: ['TestResultId0001', 'TestResultId0002', 'TestResultId0003'], + entities: { + TestResultId0001: testResults[0], + TestResultId0002: testResults[1], + TestResultId0003: testResults[2], + }, + }; + const action = fetchTestResultsSuccess({ payload: testResults }); + const state = testResultsReducer(initialTestResultsState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('fetchTestResultsBySystemNumber actions', () => { + it('should set loading to true', () => { + const newState: TestResultsState = { ...initialTestResultsState, loading: true }; + const action = fetchTestResultsBySystemNumber({ systemNumber: 'TestResultId0001' }); + const state = testResultsReducer(initialTestResultsState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + + describe('fetchTestResultsBySystemNumberSuccess', () => { + it('should set all test result records', () => { + const testResults = mockTestResultList(); + const newState: TestResultsState = { + ...initialTestResultsState, + ids: ['TestResultId0001'], + entities: { TestResultId0001: testResults[0] }, + }; + const action = fetchTestResultsBySystemNumberSuccess({ payload: testResults }); + const state = testResultsReducer(initialTestResultsState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('fetchTestResultsBySystemNumberFailed', () => { + it('should set error state', () => { + const newState = { ...initialTestResultsState, loading: false }; + const action = fetchTestResultsBySystemNumberFailed({ error: 'unit testing error message' }); + const state = testResultsReducer({ ...initialTestResultsState, loading: true }, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + }); + + describe('fetchSelectedTestResult actions', () => { + it('should set loading to true', () => { + const newState: TestResultsState = { ...initialTestResultsState, loading: true }; + const action = fetchSelectedTestResult(); + const state = testResultsReducer(initialTestResultsState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + + describe('fetchSelectedTestResultSuccess', () => { + it('should set all test result records', () => { + const testResults = mockTestResultList(); + const updatedTestResult = { ...testResults[0], odometerReading: 99999 }; + + const newState: TestResultsState = { + ...initialTestResultsState, + ids: [updatedTestResult.testResultId], + entities: { [updatedTestResult.testResultId]: updatedTestResult }, + }; + const action = fetchSelectedTestResultSuccess({ payload: updatedTestResult }); + const state = testResultsReducer(initialTestResultsState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('fetchSelectedTestResultFailed', () => { + it('should set error state', () => { + const newState = { ...initialTestResultsState, loading: false }; + const action = fetchSelectedTestResultFailed({ error: 'unit testing error message' }); + const state = testResultsReducer({ ...initialTestResultsState, loading: true }, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + }); + + describe('updateTestResult actions', () => { + it('should set loading to true', () => { + const state: TestResultsState = { ...initialTestResultsState, loading: true }; + const action = updateTestResult({ value: {} as TestResultModel }); + const newState = testResultsReducer(initialTestResultsState, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + + describe('updateTestResultSuccess', () => { + it('should set loading to false', () => { + const state: TestResultsState = { ...initialTestResultsState, loading: false }; + const action = updateTestResultSuccess({ payload: { id: '', changes: {} as TestResultModel } }); + const newState = testResultsReducer({ ...initialTestResultsState, loading: true }, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + + describe('updateTestResultFailed', () => { + it('should set loading to false', () => { + const state: TestResultsState = { ...initialTestResultsState, loading: false }; + const action = updateTestResultFailed({ errors: [] }); + const newState = testResultsReducer({ ...initialTestResultsState, loading: true }, action); + + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + }); + + describe('calculateTestResult', () => { + let action: Action; + beforeEach(() => { + action = updateResultOfTest(); + }); + + it('should return a testType with a testResult of pass if empty defects', () => { + const testResult = { + testTypes: [ + { + testResult: 'fail', + defects: [], + }, + ], + } as unknown as TestResultModel; + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); + expect(newState.editingTestResult?.testTypes[0].testResult).toBe('pass'); + }); + + it('should not change the test result of defects key is not present', () => { + const testResult = { + testTypes: [ + { + testResult: 'fail', + }, + ], + } as TestResultModel; + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); + expect(newState.editingTestResult?.testTypes[0].testResult).toEqual(testResult.testTypes[0].testResult); + }); + it('should return a testType with a testResult of pass if advisory defect', () => { + const testResult = { + testTypes: [ + { + testResult: 'fail', + defects: [ + { + deficiencyCategory: 'advisory', + }, + ], + }, + ], + } as TestResultModel; + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); + expect(newState.editingTestResult?.testTypes[0].testResult).toBe('pass'); + }); + it('should return a testType with a testResult of pass if minor defect', () => { + const testResult = { + testTypes: [ + { + testResult: 'fail', + defects: [ + { + deficiencyCategory: 'minor', + }, + ], + }, + ], + } as TestResultModel; + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); + expect(newState.editingTestResult?.testTypes[0].testResult).toBe('pass'); + }); + it('should return a testType with a testResult of pass if minor and advisory defect', () => { + const testResult = { + testTypes: [ + { + testResult: 'fail', + defects: [ + { + deficiencyCategory: 'minor', + }, + { + deficiencyCategory: 'advisory', + }, + ], + }, + ], + } as TestResultModel; + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); + expect(newState.editingTestResult?.testTypes[0].testResult).toBe('pass'); + }); + it('should return a testType with a testResult of fail if at least one major defect', () => { + const testResult = { + testTypes: [ + { + testResult: 'pass', + defects: [ + { + deficiencyCategory: 'major', + }, + { + deficiencyCategory: 'advisory', + }, + ], + }, + ], + } as TestResultModel; + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); + expect(newState.editingTestResult?.testTypes[0].testResult).toBe('fail'); + }); + it('should return a testType with a testResult of fail if at least one dangerous defect', () => { + const testResult = { + testTypes: [ + { + testResult: 'pass', + defects: [ + { + deficiencyCategory: 'dangerous', + }, + { + deficiencyCategory: 'advisory', + }, + ], + }, + ], + } as TestResultModel; + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); + expect(newState.editingTestResult?.testTypes[0].testResult).toBe('fail'); + }); + it('should return a testType with a testResult of prs if major defect is prs and other defects are advisory', () => { + const testResult = { + testTypes: [ + { + testResult: 'pass', + defects: [ + { + deficiencyCategory: 'major', + prs: true, + }, + { + deficiencyCategory: 'advisory', + }, + ], + }, + ], + } as TestResultModel; + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); + expect(newState.editingTestResult?.testTypes[0].testResult).toBe('prs'); + }); + it('should return a testType with a testResult of fail if not all major/dangerous defects are prs', () => { + const testResult = { + testTypes: [ + { + testResult: 'pass', + defects: [ + { + deficiencyCategory: 'major', + }, + { + deficiencyCategory: 'dangerous', + prs: true, + }, + ], + }, + ], + } as TestResultModel; + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); + expect(newState.editingTestResult?.testTypes[0].testResult).toBe('fail'); + }); + it('should handle multiple testTypes', () => { + const testResult = { + testTypes: [ + { + testResult: 'pass', + defects: [ + { + deficiencyCategory: 'major', + }, + { + deficiencyCategory: 'dangerous', + prs: true, + }, + ], + }, + { + testResult: 'pass', + defects: [ + { + deficiencyCategory: 'dangerous', + prs: true, + }, + ], + }, + { + testResult: 'fail', + defects: [ + { + deficiencyCategory: 'advisory', + prs: true, + }, + ], + }, + ], + } as TestResultModel; + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); + expect(newState.editingTestResult?.testTypes[0].testResult).toBe('fail'); + expect(newState.editingTestResult?.testTypes[1].testResult).toBe('prs'); + expect(newState.editingTestResult?.testTypes[2].testResult).toBe('pass'); + }); + }); + + describe('createDefect', () => { + it('should create defect', () => { + const defect = { imNumber: 2 } as TestResultDefect; + const testResult = { + testTypes: [ + { + defects: [defect], + }, + ], + } as unknown as TestResultModel; + const action = createDefect({ defect }); + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); + + expect(newState.editingTestResult?.testTypes[0].defects?.length).toBe(2); + }); + }); + + describe('updateDefect', () => { + it('should update defect', () => { + const defect = { imNumber: 2 } as TestResultDefect; + const newDefect = { imNumber: 1 } as TestResultDefect; + const testResult = { + testTypes: [ + { + defects: [defect], + }, + ], + } as unknown as TestResultModel; + const action = updateDefect({ defect: newDefect, index: 0 }); + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); + + const path = + newState.editingTestResult?.testTypes[0] && + newState.editingTestResult?.testTypes[0].defects && + newState.editingTestResult?.testTypes[0].defects[0].imNumber; + + expect(path).toBe(1); + }); + }); + + describe('removeDefect', () => { + it('should remove defect', () => { + const defect = { imNumber: 2 } as TestResultDefect; + const testResult = { + testTypes: [ + { + defects: [defect], + }, + ], + } as unknown as TestResultModel; + const action = removeDefect({ index: 0 }); + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); + + expect(newState.editingTestResult?.testTypes[0].defects?.length).toBe(0); + }); + }); + + describe('createRequiredStandard', () => { + it('should create required standard', () => { + const requiredStandard = { sectionNumber: 2 } as unknown as TestResultRequiredStandard; + const testResult = { + testTypes: [ + { + requiredStandards: [requiredStandard], + }, + ], + } as unknown as TestResultModel; + const action = createRequiredStandard({ requiredStandard }); + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); + + expect(newState.editingTestResult?.testTypes[0].requiredStandards?.length).toBe(2); + }); + }); + + describe('updateRequiredStandard', () => { + it('should update required standard', () => { + const requiredStandard = { sectionNumber: 2 } as unknown as TestResultRequiredStandard; + const newRequiredStandard = { sectionNumber: 1 } as unknown as TestResultRequiredStandard; + const testResult = { + testTypes: [ + { + requiredStandards: [requiredStandard], + }, + ], + } as unknown as TestResultModel; + const action = updateRequiredStandard({ requiredStandard: newRequiredStandard, index: 0 }); + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); + + expect(newState.editingTestResult?.testTypes[0].requiredStandards?.length).toBe(1); + expect(newState.editingTestResult?.testTypes?.at(0)?.requiredStandards?.at(0)?.sectionNumber).toBe(1); + }); + }); + + describe('removeRequiredStandard', () => { + it('should remove required standard', () => { + const requiredStandard = { sectionNumber: 2 } as unknown as TestResultRequiredStandard; + const testResult = { + testTypes: [ + { + requiredStandards: [requiredStandard], + }, + ], + } as unknown as TestResultModel; + const action = removeRequiredStandard({ index: 0 }); + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); + + expect(newState.editingTestResult?.testTypes[0].requiredStandards?.length).toBe(0); + }); + }); + + describe('cleanTestResultPayload', () => { + it('should return the state unaltered if no editing test result', () => { + const action = cleanTestResult(); + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: undefined }, action); + + expect(newState).toStrictEqual({ ...initialTestResultsState, editingTestResult: undefined }); + }); + + it('should return the state unaltered if no test type', () => { + const editingTestResult = { + foo: 'bar', + } as unknown as TestResultModel; + + const action = cleanTestResult(); + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult }, action); + + expect(newState).toStrictEqual({ ...initialTestResultsState, editingTestResult }); + }); + + it('should return the state unaltered if required standards are populated', () => { + const editingTestResult = { + testTypes: [{ requiredStandards: ['I am a RS'], testTypeId: '125' }], + } as unknown as TestResultModel; + + const action = cleanTestResult(); + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult }, action); + + expect(newState).toStrictEqual({ ...initialTestResultsState, editingTestResult }); + }); + + it('should return the state unaltered if test type is not spec 1 or spec 5', () => { + const editingTestResult = { + testTypes: [{ requiredStandards: ['I am a RS'], testTypeId: 'xyz' }], + } as unknown as TestResultModel; + + const action = cleanTestResult(); + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult }, action); + + expect(newState).toStrictEqual({ ...initialTestResultsState, editingTestResult }); + }); + + it('should delete RS if empty from state', () => { + const editingTestResult = { + testTypes: [{ requiredStandards: [], testTypeId: '125' }], + } as unknown as TestResultModel; + + const action = cleanTestResult(); + const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult }, action); + + expect(newState.editingTestResult?.testTypes[0].requiredStandards).toBeUndefined(); + }); + }); }); 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..6294c47b1c 100644 --- a/src/app/store/test-records/reducers/test-records.reducer.ts +++ b/src/app/store/test-records/reducers/test-records.reducer.ts @@ -11,302 +11,360 @@ import { createFeatureSelector, createReducer, on } from '@ngrx/store'; import cloneDeep from 'lodash.clonedeep'; import merge from 'lodash.merge'; import { - cancelEditingTestResult, - cleanTestResult, - createDefect, - createRequiredStandard, - createTestResult, - createTestResultFailed, - createTestResultSuccess, - fetchSelectedTestResult, - fetchSelectedTestResultFailed, - fetchSelectedTestResultSuccess, - fetchTestResults, - fetchTestResultsBySystemNumber, - fetchTestResultsBySystemNumberFailed, - fetchTestResultsBySystemNumberSuccess, - fetchTestResultsSuccess, - initialContingencyTest, - removeDefect, - removeRequiredStandard, - setResultOfTest, - templateSectionsChanged, - updateDefect, - updateEditingTestResult, - updateRequiredStandard, - updateResultOfTest, - updateResultOfTestRequiredStandards, - updateTestResult, - updateTestResultFailed, - updateTestResultSuccess, + cancelEditingTestResult, + cleanTestResult, + createDefect, + createRequiredStandard, + createTestResult, + createTestResultFailed, + createTestResultSuccess, + fetchSelectedTestResult, + fetchSelectedTestResultFailed, + fetchSelectedTestResultSuccess, + fetchTestResults, + fetchTestResultsBySystemNumber, + fetchTestResultsBySystemNumberFailed, + fetchTestResultsBySystemNumberSuccess, + fetchTestResultsSuccess, + initialContingencyTest, + removeDefect, + removeRequiredStandard, + setResultOfTest, + templateSectionsChanged, + updateDefect, + updateEditingTestResult, + updateRequiredStandard, + updateResultOfTest, + updateResultOfTestRequiredStandards, + updateTestResult, + updateTestResultFailed, + updateTestResultSuccess, } from '../actions/test-records.actions'; export const STORE_FEATURE_TEST_RESULTS_KEY = 'testRecords'; interface Extras { - error: string; - loading: boolean; - editingTestResult?: TestResultModel; - sectionTemplates?: FormNode[]; + error: string; + loading: boolean; + editingTestResult?: TestResultModel; + sectionTemplates?: FormNode[]; } export interface TestResultsState extends EntityState, Extras {} const selectTestResultId = (a: TestResultModel): string => { - return a.testResultId; + return a.testResultId; }; -export const testResultAdapter: EntityAdapter = createEntityAdapter({ selectId: selectTestResultId }); +export const testResultAdapter: EntityAdapter = createEntityAdapter({ + selectId: selectTestResultId, +}); export const initialTestResultsState = testResultAdapter.getInitialState({ - error: '', - loading: false, + error: '', + loading: false, }); export const testResultsReducer = createReducer( - initialTestResultsState, - on(fetchTestResults, (state) => ({ ...state, loading: true })), - on(fetchTestResultsSuccess, (state, action) => ({ ...testResultAdapter.setAll(action.payload, state), loading: false })), - - on(fetchTestResultsBySystemNumber, (state) => ({ ...state, loading: true })), - on(fetchTestResultsBySystemNumberSuccess, (state, action) => ({ ...testResultAdapter.setAll(action.payload, state), loading: false })), - on(fetchTestResultsBySystemNumberFailed, (state) => ({ ...testResultAdapter.setAll([], state), loading: false })), - - on(fetchSelectedTestResult, (state) => ({ ...state, loading: true })), - on(fetchSelectedTestResultSuccess, (state, action) => ({ ...testResultAdapter.upsertOne(action.payload, state), loading: false })), - on(fetchSelectedTestResultFailed, (state) => ({ ...state, loading: false })), - - on(createTestResult, updateTestResult, (state) => ({ ...state, loading: true })), - on(updateTestResultSuccess, (state, action) => ({ - ...testResultAdapter.updateOne(action.payload, state), - loading: false, - })), - on(createTestResultSuccess, createTestResultFailed, updateTestResultFailed, (state) => ({ ...state, loading: false })), - - on(updateResultOfTest, (state) => ({ ...state, editingTestResult: calculateTestResult(state.editingTestResult) })), - on(setResultOfTest, (state, action) => ({ ...state, editingTestResult: setTestResult(state.editingTestResult, action.result) })), - - on(updateEditingTestResult, (state, action) => ({ ...state, editingTestResult: merge({}, action.testResult) })), - on(cancelEditingTestResult, (state) => ({ ...state, editingTestResult: undefined, sectionTemplates: undefined })), - - on(initialContingencyTest, (state, action) => ({ - ...state, - editingTestResult: { ...action.testResult } as TestResultModel, - })), - - on(templateSectionsChanged, (state, action) => ({ ...state, sectionTemplates: action.sectionTemplates, editingTestResult: action.sectionsValue })), - - on(createDefect, (state, action) => ({ ...state, editingTestResult: createNewDefect(state.editingTestResult, action.defect) })), - 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(updateResultOfTestRequiredStandards, (state) => ({ - ...state, - editingTestResult: calculateTestResultRequiredStandards(state.editingTestResult), - })), - - on(cleanTestResult, (state) => ({ ...state, editingTestResult: cleanTestResultPayload(state.editingTestResult) })), + initialTestResultsState, + on(fetchTestResults, (state) => ({ ...state, loading: true })), + on(fetchTestResultsSuccess, (state, action) => ({ + ...testResultAdapter.setAll(action.payload, state), + loading: false, + })), + + on(fetchTestResultsBySystemNumber, (state) => ({ ...state, loading: true })), + on(fetchTestResultsBySystemNumberSuccess, (state, action) => ({ + ...testResultAdapter.setAll(action.payload, state), + loading: false, + })), + on(fetchTestResultsBySystemNumberFailed, (state) => ({ ...testResultAdapter.setAll([], state), loading: false })), + + on(fetchSelectedTestResult, (state) => ({ ...state, loading: true })), + on(fetchSelectedTestResultSuccess, (state, action) => ({ + ...testResultAdapter.upsertOne(action.payload, state), + loading: false, + })), + on(fetchSelectedTestResultFailed, (state) => ({ ...state, loading: false })), + + on(createTestResult, updateTestResult, (state) => ({ ...state, loading: true })), + on(updateTestResultSuccess, (state, action) => ({ + ...testResultAdapter.updateOne(action.payload, state), + loading: false, + })), + on(createTestResultSuccess, createTestResultFailed, updateTestResultFailed, (state) => ({ + ...state, + loading: false, + })), + + on(updateResultOfTest, (state) => ({ ...state, editingTestResult: calculateTestResult(state.editingTestResult) })), + on(setResultOfTest, (state, action) => ({ + ...state, + editingTestResult: setTestResult(state.editingTestResult, action.result), + })), + + on(updateEditingTestResult, (state, action) => ({ ...state, editingTestResult: merge({}, action.testResult) })), + on(cancelEditingTestResult, (state) => ({ ...state, editingTestResult: undefined, sectionTemplates: undefined })), + + on(initialContingencyTest, (state, action) => ({ + ...state, + editingTestResult: { ...action.testResult } as TestResultModel, + })), + + on(templateSectionsChanged, (state, action) => ({ + ...state, + sectionTemplates: action.sectionTemplates, + editingTestResult: action.sectionsValue, + })), + + on(createDefect, (state, action) => ({ + ...state, + editingTestResult: createNewDefect(state.editingTestResult, action.defect), + })), + 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(updateResultOfTestRequiredStandards, (state) => ({ + ...state, + editingTestResult: calculateTestResultRequiredStandards(state.editingTestResult), + })), + + on(cleanTestResult, (state) => ({ ...state, editingTestResult: cleanTestResultPayload(state.editingTestResult) })) ); export const testResultsFeatureState = createFeatureSelector(STORE_FEATURE_TEST_RESULTS_KEY); -function createNewRequiredStandard(testResultState: TestResultModel | undefined, requiredStandard: TestResultRequiredStandard) { - if (!testResultState) { - return; - } - const testResult = cloneDeep(testResultState); - - if (!testResult.testTypes[0].requiredStandards) { - return; - } - testResult.testTypes[0].requiredStandards.push(requiredStandard); - - return { ...testResult }; +function createNewRequiredStandard( + testResultState: TestResultModel | undefined, + requiredStandard: TestResultRequiredStandard +) { + if (!testResultState) { + return; + } + const testResult = cloneDeep(testResultState); + + if (!testResult.testTypes[0].requiredStandards) { + return; + } + testResult.testTypes[0].requiredStandards.push(requiredStandard); + + return { ...testResult }; } 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 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 }; + 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 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 }; } -function updateRequiredStandardAtIndex(testResultState: TestResultModel | undefined, requiredStandard: TestResultRequiredStandard, index: number) { - if (!testResultState) { - return; - } - const testResult = cloneDeep(testResultState); - if (!testResult.testTypes[0].requiredStandards) { - return; - } - testResult.testTypes[0].requiredStandards[`${index}`] = requiredStandard; - - return { ...testResult }; +function updateRequiredStandardAtIndex( + testResultState: TestResultModel | undefined, + requiredStandard: TestResultRequiredStandard, + index: number +) { + if (!testResultState) { + return; + } + const testResult = cloneDeep(testResultState); + if (!testResult.testTypes[0].requiredStandards) { + return; + } + testResult.testTypes[0].requiredStandards[`${index}`] = requiredStandard; + + return { ...testResult }; } function removeRequiredStandardAtIndex(testResultState: TestResultModel | undefined, index: number) { - if (!testResultState) { - return; - } - const testResult = cloneDeep(testResultState); - if (!testResult.testTypes[0].requiredStandards) { - return; - } - testResult.testTypes[0].requiredStandards.splice(index, 1); - - return { ...testResult }; + if (!testResultState) { + return; + } + const testResult = cloneDeep(testResultState); + if (!testResult.testTypes[0].requiredStandards) { + return; + } + testResult.testTypes[0].requiredStandards.splice(index, 1); + + return { ...testResult }; } -function createNewDefect(testResultState: TestResultModel | undefined, defect: TestResultDefect): TestResultModel | undefined { - if (!testResultState) { - return; - } - const testResult = cloneDeep(testResultState); - - if (!testResult.testTypes[0].defects) { - return; - } - testResult.testTypes[0].defects.push(defect); - - return { ...testResult }; +function createNewDefect( + testResultState: TestResultModel | undefined, + defect: TestResultDefect +): TestResultModel | undefined { + if (!testResultState) { + return; + } + const testResult = cloneDeep(testResultState); + + if (!testResult.testTypes[0].defects) { + return; + } + testResult.testTypes[0].defects.push(defect); + + return { ...testResult }; } -function updateDefectAtIndex(testResultState: TestResultModel | undefined, defect: TestResultDefect, index: number): TestResultModel | undefined { - if (!testResultState) { - return; - } - const testResult = cloneDeep(testResultState); - if (!testResult.testTypes[0].defects) { - return; - } - testResult.testTypes[0].defects[`${index}`] = defect; - - return { ...testResult }; +function updateDefectAtIndex( + testResultState: TestResultModel | undefined, + defect: TestResultDefect, + index: number +): TestResultModel | undefined { + if (!testResultState) { + return; + } + const testResult = cloneDeep(testResultState); + if (!testResult.testTypes[0].defects) { + return; + } + testResult.testTypes[0].defects[`${index}`] = defect; + + return { ...testResult }; } function removeDefectAtIndex(testResultState: TestResultModel | undefined, index: number): TestResultModel | undefined { - if (!testResultState) { - return; - } - const testResult = cloneDeep(testResultState); - if (!testResult.testTypes[0].defects) { - return; - } - testResult.testTypes[0].defects.splice(index, 1); - - return { ...testResult }; + if (!testResultState) { + return; + } + const testResult = cloneDeep(testResultState); + if (!testResult.testTypes[0].defects) { + return; + } + testResult.testTypes[0].defects.splice(index, 1); + + return { ...testResult }; } function calculateTestResult(testResultState: TestResultModel | undefined): TestResultModel | undefined { - if (!testResultState) { - return; - } - - const testResult = cloneDeep(testResultState); - - const newTestTypes = testResult.testTypes.map((testType) => { - if (testType.testResult === resultOfTestEnum.abandoned || !testType.defects || TypeOfTest.DESK_BASED === testResultState?.typeOfTest) { - return testType; - } - - if (!testType.defects.length) { - testType.testResult = resultOfTestEnum.pass; - return testType; - } - - const failOrPrs = testType.defects.some( - (defect) => defect.deficiencyCategory === DeficiencyCategoryEnum.Major || defect.deficiencyCategory === DeficiencyCategoryEnum.Dangerous, - ); - if (!failOrPrs) { - testType.testResult = resultOfTestEnum.pass; - return testType; - } - - testType.testResult = testType.defects.every( - (defect) => - defect.deficiencyCategory === DeficiencyCategoryEnum.Advisory - || defect.deficiencyCategory === DeficiencyCategoryEnum.Minor - || (defect.deficiencyCategory === DeficiencyCategoryEnum.Dangerous && defect.prs) - || (defect.deficiencyCategory === DeficiencyCategoryEnum.Major && defect.prs), - ) - ? resultOfTestEnum.prs - : resultOfTestEnum.fail; - - return testType; - }); - return { ...testResult, testTypes: [...newTestTypes] }; + if (!testResultState) { + return; + } + + const testResult = cloneDeep(testResultState); + + const newTestTypes = testResult.testTypes.map((testType) => { + if ( + testType.testResult === resultOfTestEnum.abandoned || + !testType.defects || + TypeOfTest.DESK_BASED === testResultState?.typeOfTest + ) { + return testType; + } + + if (!testType.defects.length) { + testType.testResult = resultOfTestEnum.pass; + return testType; + } + + const failOrPrs = testType.defects.some( + (defect) => + defect.deficiencyCategory === DeficiencyCategoryEnum.Major || + defect.deficiencyCategory === DeficiencyCategoryEnum.Dangerous + ); + if (!failOrPrs) { + testType.testResult = resultOfTestEnum.pass; + return testType; + } + + testType.testResult = testType.defects.every( + (defect) => + defect.deficiencyCategory === DeficiencyCategoryEnum.Advisory || + defect.deficiencyCategory === DeficiencyCategoryEnum.Minor || + (defect.deficiencyCategory === DeficiencyCategoryEnum.Dangerous && defect.prs) || + (defect.deficiencyCategory === DeficiencyCategoryEnum.Major && defect.prs) + ) + ? resultOfTestEnum.prs + : resultOfTestEnum.fail; + + return testType; + }); + return { ...testResult, testTypes: [...newTestTypes] }; } -function calculateTestResultRequiredStandards(testResultState: TestResultModel | undefined): TestResultModel | undefined { - if (!testResultState) { - return; - } - - const testResult = cloneDeep(testResultState); - - const newTestTypes = testResult.testTypes.map((testType) => { - if (testType.testResult === resultOfTestEnum.abandoned || !testType.requiredStandards || TypeOfTest.DESK_BASED === testResultState?.typeOfTest) { - return testType; - } - - if (!testType.requiredStandards.length) { - testType.testResult = resultOfTestEnum.pass; - return testType; - } - - testType.testResult = testType.requiredStandards.every((rs) => rs.prs) ? resultOfTestEnum.prs : resultOfTestEnum.fail; - - return testType; - }); - return { ...testResult, testTypes: [...newTestTypes] }; +function calculateTestResultRequiredStandards( + testResultState: TestResultModel | undefined +): TestResultModel | undefined { + if (!testResultState) { + return; + } + + const testResult = cloneDeep(testResultState); + + const newTestTypes = testResult.testTypes.map((testType) => { + if ( + testType.testResult === resultOfTestEnum.abandoned || + !testType.requiredStandards || + TypeOfTest.DESK_BASED === testResultState?.typeOfTest + ) { + return testType; + } + + if (!testType.requiredStandards.length) { + testType.testResult = resultOfTestEnum.pass; + return testType; + } + + testType.testResult = testType.requiredStandards.every((rs) => rs.prs) + ? resultOfTestEnum.prs + : resultOfTestEnum.fail; + + return testType; + }); + return { ...testResult, testTypes: [...newTestTypes] }; } function setTestResult(testResult: TestResultModel | undefined, result: resultOfTestEnum): TestResultModel | undefined { - if (!testResult) { - return; - } - const testResultCopy = cloneDeep(testResult); - testResultCopy.testTypes[0].testResult = result; - return testResultCopy; + if (!testResult) { + return; + } + const testResultCopy = cloneDeep(testResult); + testResultCopy.testTypes[0].testResult = result; + return testResultCopy; } diff --git a/src/app/store/test-records/selectors/test-records.selectors.spec.ts b/src/app/store/test-records/selectors/test-records.selectors.spec.ts index d3b1497714..1733b20444 100644 --- a/src/app/store/test-records/selectors/test-records.selectors.spec.ts +++ b/src/app/store/test-records/selectors/test-records.selectors.spec.ts @@ -1,252 +1,280 @@ import { Params } from '@angular/router'; +import { createMockAdditionalDefect, createMockCustomDefect } from '@mocks/custom-defect.mock'; import { mockDefect } from '@mocks/mock-defects'; import { createMockTestResult } from '@mocks/test-result.mock'; import { createMockTestType } from '@mocks/test-type.mock'; import { TestResultModel } from '@models/test-results/test-result.model'; -import { createMockAdditionalDefect, createMockCustomDefect } from '@mocks/custom-defect.mock'; import { mockTestResult } from '../../../../mocks/mock-test-result'; import { TestResultsState, initialTestResultsState } from '../reducers/test-records.reducer'; import { - isTestTypeKeySame, - selectAllTestResults, - selectAmendedDefectData, - selectDefectData, - selectTestResultIds, - selectTestResultsEntities, - selectTestResultsTotal, - selectedAmendedTestResultState, - selectedTestResultState, - selectedTestSortedAmendmentHistory, - testResultLoadingState, - isTestTypeOldIvaOrMsva, + isTestTypeKeySame, + isTestTypeOldIvaOrMsva, + selectAllTestResults, + selectAmendedDefectData, + selectDefectData, + selectTestResultIds, + selectTestResultsEntities, + selectTestResultsTotal, + selectedAmendedTestResultState, + selectedTestResultState, + selectedTestSortedAmendmentHistory, + testResultLoadingState, } from './test-records.selectors'; describe('Test Results Selectors', () => { - describe('adapter selectors', () => { - it('should return correct state', () => { - const state = { ...initialTestResultsState, ids: ['1'], entities: { 1: { preparerId: '2' } } } as unknown as TestResultsState; - expect(selectTestResultIds.projector(state)).toEqual(['1']); - expect(selectTestResultsEntities.projector(state)).toEqual({ 1: { preparerId: '2' } }); - expect(selectAllTestResults.projector(state)).toEqual([{ preparerId: '2' }]); - expect(selectTestResultsTotal.projector(state)).toBe(1); - }); - }); - - describe('selectedTestResultState', () => { - it('should return the correct test result', () => { - const state: TestResultsState = { - ...initialTestResultsState, - ids: ['testResult1'], - entities: { - testResult1: createMockTestResult({ - testResultId: 'testResult1', - testTypes: [createMockTestType({ testNumber: '1' })], - }), - }, - }; - - const selectedState = selectedTestResultState.projector(state.entities, { testResultId: 'testResult1', testNumber: '1' } as Params); - expect(selectedState).toEqual(state.entities['testResult1']); - }); - }); - - describe('testResultLoadingState', () => { - it('should return loading state', () => { - const state: TestResultsState = { ...initialTestResultsState, loading: true }; - const selectedState = testResultLoadingState.projector(state); - expect(selectedState).toBeTruthy(); - }); - }); - - describe('isTestTypeOldIvaOrMsva', () => { - it('should return true if all custom defects have a reference number', () => { - const state: TestResultModel = mockTestResult(); - state.testTypes[0].customDefects = [createMockCustomDefect()]; - const isOldIvaOrMsva = isTestTypeOldIvaOrMsva.projector(state); - expect(isOldIvaOrMsva).toBe(true); - }); - - it('should return false if all custom defects do not have a reference number', () => { - const state: TestResultModel = mockTestResult(); - state.testTypes[0].customDefects = [createMockAdditionalDefect()]; - const isOldIvaOrMsva = isTestTypeOldIvaOrMsva.projector(state); - expect(isOldIvaOrMsva).toBe(false); - }); - - it('should return false if no custom defects are present', () => { - const state: TestResultModel = mockTestResult(); - state.testTypes[0].customDefects = []; - const isOldIvaOrMsva = isTestTypeOldIvaOrMsva.projector(state); - expect(isOldIvaOrMsva).toBe(false); - }); - }); - - describe('selectDefectData', () => { - const state: TestResultModel = mockTestResult(); - state.testTypes[0].defects = [mockDefect()]; - - it('should return defect data for the first testType in selected test result', () => { - const defectState = selectDefectData.projector(state); - expect(defectState?.length).toBe(1); - expect(defectState).toEqual(state.testTypes[0].defects); - }); - - it('should return an empty array if there are no defects', () => { - const noDefectState = { ...state, testTypes: [{ ...state.testTypes[0], defects: undefined }] }; - const defectState = selectDefectData.projector(noDefectState); - expect(defectState?.length).toBe(0); - }); - - it('should return an empty array if there are no test types', () => { - const noTestTypeState = { ...state, testTypes: undefined } as unknown as TestResultModel; - const testTypeState = selectDefectData.projector(noTestTypeState); - expect(testTypeState?.length).toBe(0); - }); - - it('should return an empty array if there are no test results', () => { - const noTestResultState = undefined; - const testResultState = selectDefectData.projector(noTestResultState); - expect(testResultState?.length).toBe(0); - }); - }); - - describe('selectSortedTestAmendmentHistory', () => { - let mock: TestResultModel; - - beforeEach(() => { - const date = new Date('2022-01-02'); - mock = mockTestResult(); - mock.testHistory = mock.testHistory?.concat(...mock.testHistory) ?? []; - mock.testHistory[0].createdAt = undefined; - mock.testHistory[1].createdAt = date.toISOString(); - mock.testHistory[2].createdAt = date.toISOString(); - mock.testHistory[3].createdAt = undefined; - mock.testHistory[4].createdAt = new Date(date.setDate(date.getDate() - 1)).toISOString(); - mock.testHistory[5].createdAt = new Date(date.setDate(date.getDate() + 1)).toISOString(); - mock.testHistory[6].createdAt = new Date(date.setDate(date.getDate() - 1)).toISOString(); - mock.testHistory[7].createdAt = undefined; - mock.testHistory[8].createdAt = date.toISOString(); - mock.testHistory[9].createdAt = date.toISOString(); - }); - - it('should sort the test history', () => { - // Adding entries with null created at at the end if they exist - const sortedTestHistory = selectedTestSortedAmendmentHistory.projector(mock); - let previous = new Date(sortedTestHistory[0].createdAt as string).getTime(); - const notfound: TestResultModel[] = []; - sortedTestHistory?.forEach((test) => { - if (test.createdAt) { - // eslint-disable-next-line jest/no-conditional-expect - expect(new Date(test.createdAt).getTime()).toBeLessThanOrEqual(previous); - previous = new Date(test.createdAt).getTime(); - } else { - notfound.push(test); - } - }); - if (notfound.length > 0) { - // eslint-disable-next-line jest/no-conditional-expect - expect(sortedTestHistory?.slice(-notfound.length)).toEqual(notfound); - } - }); - }); - - describe('selectedAmendedTestResultState', () => { - const testResult = createMockTestResult({ - testHistory: new Array(2).fill(0).map((i) => - createMockTestResult({ - createdAt: `2020-01-01T00:0${i}:00.000Z`, - testTypes: [createMockTestType({ testTypeId: `${i}1`, testNumber: 'ABC00' })], - })), - }); - - it('should return amended record that matches "createdAt" route param value', () => { - const selectedState = selectedAmendedTestResultState.projector(testResult, { testNumber: 'ABC00', createdAt: '2020-01-01T00:00:00.000Z' }); - expect(selectedState).toBeDefined(); - expect(testResult.testHistory?.[1].testTypes).toHaveLength(1); - }); - - it('should return return undefined when "createdAt" route param value does not match any amended records', () => { - expect(selectedAmendedTestResultState.projector(testResult, { testTypeId: '00', createdAt: '2020-01-01T00:02:00.000Z' })).toBeUndefined(); - }); - - it('should return return undefined when "testTypeId" route param value does not match any in amended test record', () => { - expect(selectedAmendedTestResultState.projector(testResult, { testTypeId: '01', createdAt: '2020-01-01T00:02:00.000Z' })).toBeUndefined(); - }); - - it('should return return undefined when there is no selected testResult', () => { - expect(selectedAmendedTestResultState.projector(undefined, { createdAt: '2020-01-01T00:01:00.000Z' })).toBeUndefined(); - }); - - it('should return return undefined when testHistory is empty', () => { - expect(selectedAmendedTestResultState.projector({ ...testResult, testHistory: [] }, { createdAt: '2020-01-01T00:01:00.000Z' })).toBeUndefined(); - }); - }); - - describe('selectAmendedDefectData', () => { - const amendedTestResultState = createMockTestResult({ - testTypes: [ - createMockTestType({ - defects: [mockDefect(1)], - }), - ], - }); - - it('should return defect array from first testType in testResult', () => { - const selectedState = selectAmendedDefectData.projector(amendedTestResultState); - expect(selectedState?.length).toBe(1); - expect(selectedState).toEqual(amendedTestResultState.testTypes[0].defects); - }); - - it('should return empty array if testResult is undefined', () => { - expect(selectAmendedDefectData.projector(undefined)).toEqual([]); - }); - - it('should return empty array if testTypes is empty', () => { - expect(selectAmendedDefectData.projector({ testTypes: [] } as unknown as TestResultModel)).toEqual([]); - }); - }); - - describe('isTestTypeKeySame', () => { - it('should return false if the property is different', () => { - const amendTestResult = { - testTypes: [ - { - testNumber: 'foo', - testTypeId: '1', - }, - ], - } as TestResultModel; - const oldTestResult = { - testTypes: [ - { - testNumber: 'foo', - testTypeId: '2', - }, - ], - } as TestResultModel; - const state = isTestTypeKeySame('testTypeId').projector(amendTestResult, oldTestResult); - expect(state).toBe(false); - }); - - it('should return true if the property is the same', () => { - const amendTestResult = { - testTypes: [ - { - testNumber: 'foo', - testTypeId: '1', - }, - ], - } as TestResultModel; - const oldTestResult = { - testTypes: [ - { - testNumber: 'foo', - testTypeId: '1', - }, - ], - } as TestResultModel; - const state = isTestTypeKeySame('testTypeId').projector(amendTestResult, oldTestResult); - expect(state).toBe(true); - }); - }); + describe('adapter selectors', () => { + it('should return correct state', () => { + const state = { + ...initialTestResultsState, + ids: ['1'], + entities: { 1: { preparerId: '2' } }, + } as unknown as TestResultsState; + expect(selectTestResultIds.projector(state)).toEqual(['1']); + expect(selectTestResultsEntities.projector(state)).toEqual({ 1: { preparerId: '2' } }); + expect(selectAllTestResults.projector(state)).toEqual([{ preparerId: '2' }]); + expect(selectTestResultsTotal.projector(state)).toBe(1); + }); + }); + + describe('selectedTestResultState', () => { + it('should return the correct test result', () => { + const state: TestResultsState = { + ...initialTestResultsState, + ids: ['testResult1'], + entities: { + testResult1: createMockTestResult({ + testResultId: 'testResult1', + testTypes: [createMockTestType({ testNumber: '1' })], + }), + }, + }; + + const selectedState = selectedTestResultState.projector(state.entities, { + testResultId: 'testResult1', + testNumber: '1', + } as Params); + expect(selectedState).toEqual(state.entities['testResult1']); + }); + }); + + describe('testResultLoadingState', () => { + it('should return loading state', () => { + const state: TestResultsState = { ...initialTestResultsState, loading: true }; + const selectedState = testResultLoadingState.projector(state); + expect(selectedState).toBeTruthy(); + }); + }); + + describe('isTestTypeOldIvaOrMsva', () => { + it('should return true if all custom defects have a reference number', () => { + const state: TestResultModel = mockTestResult(); + state.testTypes[0].customDefects = [createMockCustomDefect()]; + const isOldIvaOrMsva = isTestTypeOldIvaOrMsva.projector(state); + expect(isOldIvaOrMsva).toBe(true); + }); + + it('should return false if all custom defects do not have a reference number', () => { + const state: TestResultModel = mockTestResult(); + state.testTypes[0].customDefects = [createMockAdditionalDefect()]; + const isOldIvaOrMsva = isTestTypeOldIvaOrMsva.projector(state); + expect(isOldIvaOrMsva).toBe(false); + }); + + it('should return false if no custom defects are present', () => { + const state: TestResultModel = mockTestResult(); + state.testTypes[0].customDefects = []; + const isOldIvaOrMsva = isTestTypeOldIvaOrMsva.projector(state); + expect(isOldIvaOrMsva).toBe(false); + }); + }); + + describe('selectDefectData', () => { + const state: TestResultModel = mockTestResult(); + state.testTypes[0].defects = [mockDefect()]; + + it('should return defect data for the first testType in selected test result', () => { + const defectState = selectDefectData.projector(state); + expect(defectState?.length).toBe(1); + expect(defectState).toEqual(state.testTypes[0].defects); + }); + + it('should return an empty array if there are no defects', () => { + const noDefectState = { ...state, testTypes: [{ ...state.testTypes[0], defects: undefined }] }; + const defectState = selectDefectData.projector(noDefectState); + expect(defectState?.length).toBe(0); + }); + + it('should return an empty array if there are no test types', () => { + const noTestTypeState = { ...state, testTypes: undefined } as unknown as TestResultModel; + const testTypeState = selectDefectData.projector(noTestTypeState); + expect(testTypeState?.length).toBe(0); + }); + + it('should return an empty array if there are no test results', () => { + const noTestResultState = undefined; + const testResultState = selectDefectData.projector(noTestResultState); + expect(testResultState?.length).toBe(0); + }); + }); + + describe('selectSortedTestAmendmentHistory', () => { + let mock: TestResultModel; + + beforeEach(() => { + const date = new Date('2022-01-02'); + mock = mockTestResult(); + mock.testHistory = mock.testHistory?.concat(...mock.testHistory) ?? []; + mock.testHistory[0].createdAt = undefined; + mock.testHistory[1].createdAt = date.toISOString(); + mock.testHistory[2].createdAt = date.toISOString(); + mock.testHistory[3].createdAt = undefined; + mock.testHistory[4].createdAt = new Date(date.setDate(date.getDate() - 1)).toISOString(); + mock.testHistory[5].createdAt = new Date(date.setDate(date.getDate() + 1)).toISOString(); + mock.testHistory[6].createdAt = new Date(date.setDate(date.getDate() - 1)).toISOString(); + mock.testHistory[7].createdAt = undefined; + mock.testHistory[8].createdAt = date.toISOString(); + mock.testHistory[9].createdAt = date.toISOString(); + }); + + it('should sort the test history', () => { + // Adding entries with null created at at the end if they exist + const sortedTestHistory = selectedTestSortedAmendmentHistory.projector(mock); + let previous = new Date(sortedTestHistory[0].createdAt as string).getTime(); + const notfound: TestResultModel[] = []; + sortedTestHistory?.forEach((test) => { + if (test.createdAt) { + // eslint-disable-next-line jest/no-conditional-expect + expect(new Date(test.createdAt).getTime()).toBeLessThanOrEqual(previous); + previous = new Date(test.createdAt).getTime(); + } else { + notfound.push(test); + } + }); + if (notfound.length > 0) { + // eslint-disable-next-line jest/no-conditional-expect + expect(sortedTestHistory?.slice(-notfound.length)).toEqual(notfound); + } + }); + }); + + describe('selectedAmendedTestResultState', () => { + const testResult = createMockTestResult({ + testHistory: new Array(2).fill(0).map((i) => + createMockTestResult({ + createdAt: `2020-01-01T00:0${i}:00.000Z`, + testTypes: [createMockTestType({ testTypeId: `${i}1`, testNumber: 'ABC00' })], + }) + ), + }); + + it('should return amended record that matches "createdAt" route param value', () => { + const selectedState = selectedAmendedTestResultState.projector(testResult, { + testNumber: 'ABC00', + createdAt: '2020-01-01T00:00:00.000Z', + }); + expect(selectedState).toBeDefined(); + expect(testResult.testHistory?.[1].testTypes).toHaveLength(1); + }); + + it('should return return undefined when "createdAt" route param value does not match any amended records', () => { + expect( + selectedAmendedTestResultState.projector(testResult, { + testTypeId: '00', + createdAt: '2020-01-01T00:02:00.000Z', + }) + ).toBeUndefined(); + }); + + it('should return return undefined when "testTypeId" route param value does not match any in amended test record', () => { + expect( + selectedAmendedTestResultState.projector(testResult, { + testTypeId: '01', + createdAt: '2020-01-01T00:02:00.000Z', + }) + ).toBeUndefined(); + }); + + it('should return return undefined when there is no selected testResult', () => { + expect( + selectedAmendedTestResultState.projector(undefined, { createdAt: '2020-01-01T00:01:00.000Z' }) + ).toBeUndefined(); + }); + + it('should return return undefined when testHistory is empty', () => { + expect( + selectedAmendedTestResultState.projector( + { ...testResult, testHistory: [] }, + { createdAt: '2020-01-01T00:01:00.000Z' } + ) + ).toBeUndefined(); + }); + }); + + describe('selectAmendedDefectData', () => { + const amendedTestResultState = createMockTestResult({ + testTypes: [ + createMockTestType({ + defects: [mockDefect(1)], + }), + ], + }); + + it('should return defect array from first testType in testResult', () => { + const selectedState = selectAmendedDefectData.projector(amendedTestResultState); + expect(selectedState?.length).toBe(1); + expect(selectedState).toEqual(amendedTestResultState.testTypes[0].defects); + }); + + it('should return empty array if testResult is undefined', () => { + expect(selectAmendedDefectData.projector(undefined)).toEqual([]); + }); + + it('should return empty array if testTypes is empty', () => { + expect(selectAmendedDefectData.projector({ testTypes: [] } as unknown as TestResultModel)).toEqual([]); + }); + }); + + describe('isTestTypeKeySame', () => { + it('should return false if the property is different', () => { + const amendTestResult = { + testTypes: [ + { + testNumber: 'foo', + testTypeId: '1', + }, + ], + } as TestResultModel; + const oldTestResult = { + testTypes: [ + { + testNumber: 'foo', + testTypeId: '2', + }, + ], + } as TestResultModel; + const state = isTestTypeKeySame('testTypeId').projector(amendTestResult, oldTestResult); + expect(state).toBe(false); + }); + + it('should return true if the property is the same', () => { + const amendTestResult = { + testTypes: [ + { + testNumber: 'foo', + testTypeId: '1', + }, + ], + } as TestResultModel; + const oldTestResult = { + testTypes: [ + { + testNumber: 'foo', + testTypeId: '1', + }, + ], + } as TestResultModel; + const state = isTestTypeKeySame('testTypeId').projector(amendTestResult, oldTestResult); + expect(state).toBe(true); + }); + }); }); diff --git a/src/app/store/test-records/selectors/test-records.selectors.ts b/src/app/store/test-records/selectors/test-records.selectors.ts index 11d2dd6741..c139a6c876 100644 --- a/src/app/store/test-records/selectors/test-records.selectors.ts +++ b/src/app/store/test-records/selectors/test-records.selectors.ts @@ -6,9 +6,7 @@ import { selectRouteNestedParams } from '@store/router/selectors/router.selector // eslint-disable-next-line import/no-cycle import { testResultAdapter, testResultsFeatureState } from '../reducers/test-records.reducer'; -const { - selectIds, selectEntities, selectAll, selectTotal, -} = testResultAdapter.getSelectors(); +const { selectIds, selectEntities, selectAll, selectTotal } = testResultAdapter.getSelectors(); // select the array of ids export const selectTestResultIds = createSelector(testResultsFeatureState, (state) => selectIds(state)); @@ -20,86 +18,100 @@ export const selectTestResultsEntities = createSelector(testResultsFeatureState, export const selectAllTestResults = createSelector(testResultsFeatureState, (state) => selectAll(state)); // select the array of tests results in order of createdAt (most recent to oldest) -export const selectAllTestResultsInDateOrder = createSelector(selectAllTestResults, (testResults) => testResults.sort(byDate)); +export const selectAllTestResultsInDateOrder = createSelector(selectAllTestResults, (testResults) => + testResults.sort(byDate) +); // select the total test results count export const selectTestResultsTotal = createSelector(testResultsFeatureState, (state) => selectTotal(state)); export const selectedTestResultState = createSelector( - selectTestResultsEntities, - selectRouteNestedParams, - (entities, { testResultId, testNumber }) => { - // eslint-disable-next-line security/detect-object-injection - const testResult = entities[testResultId]; - if (!testResult) { - return undefined; - } - - const testTypeFound = testResult.testTypes.find((testType) => testType.testNumber === testNumber); - - if (!testTypeFound) { - return undefined; - } - - return { ...testResult, testTypes: [testTypeFound] } as TestResultModel; - }, + selectTestResultsEntities, + selectRouteNestedParams, + (entities, { testResultId, testNumber }) => { + // eslint-disable-next-line security/detect-object-injection + const testResult = entities[testResultId]; + if (!testResult) { + return undefined; + } + + const testTypeFound = testResult.testTypes.find((testType) => testType.testNumber === testNumber); + + if (!testTypeFound) { + return undefined; + } + + return { ...testResult, testTypes: [testTypeFound] } as TestResultModel; + } ); export const testResultInEdit = createSelector(testResultsFeatureState, (state) => state.editingTestResult); -export const toEditOrNotToEdit = createSelector(testResultInEdit, selectedTestResultState, (editingTestResult, selectedTestResult) => { - return editingTestResult || selectedTestResult; -}); +export const toEditOrNotToEdit = createSelector( + testResultInEdit, + selectedTestResultState, + (editingTestResult, selectedTestResult) => { + return editingTestResult || selectedTestResult; + } +); export const testResultLoadingState = createSelector(testResultsFeatureState, (state) => state.loading); -export const selectDefectData = createSelector(selectedTestResultState, (testResult) => getDefectFromTestResult(testResult)); +export const selectDefectData = createSelector(selectedTestResultState, (testResult) => + getDefectFromTestResult(testResult) +); export const isTestTypeOldIvaOrMsva = createSelector(toEditOrNotToEdit, (testResult) => { - return !!testResult?.testTypes[0]?.customDefects?.length && !!testResult?.testTypes[0]?.customDefects?.every((defect) => !!defect.referenceNumber); + return ( + !!testResult?.testTypes[0]?.customDefects?.length && + !!testResult?.testTypes[0]?.customDefects?.every((defect) => !!defect.referenceNumber) + ); }); export const selectedTestSortedAmendmentHistory = createSelector(selectedTestResultState, (testResult) => { - if (!testResult || !testResult.testHistory) { - return []; - } + if (!testResult || !testResult.testHistory) { + return []; + } - const testHistory = [...testResult.testHistory]; - return testHistory.sort(byDate); + const testHistory = [...testResult.testHistory]; + return testHistory.sort(byDate); }); export const selectedAmendedTestResultState = createSelector( - selectedTestResultState, - selectRouteNestedParams, - (testRecord, { testNumber, createdAt }) => { - const amendedTest = testRecord?.testHistory?.find((testResult) => testResult.createdAt === createdAt); + selectedTestResultState, + selectRouteNestedParams, + (testRecord, { testNumber, createdAt }) => { + const amendedTest = testRecord?.testHistory?.find((testResult) => testResult.createdAt === createdAt); - if (!amendedTest) { - return undefined; - } + if (!amendedTest) { + return undefined; + } - const testTypeFound = amendedTest.testTypes.find((testType) => testType.testNumber === testNumber); + const testTypeFound = amendedTest.testTypes.find((testType) => testType.testNumber === testNumber); - if (!testTypeFound) { - return undefined; - } + if (!testTypeFound) { + return undefined; + } - return { ...amendedTest, testTypes: [testTypeFound] }; - }, + return { ...amendedTest, testTypes: [testTypeFound] }; + } ); export const selectAmendedDefectData = createSelector(selectedAmendedTestResultState, (amendedTestResult) => { - return getDefectFromTestResult(amendedTestResult); + return getDefectFromTestResult(amendedTestResult); }); export const sectionTemplates = createSelector(testResultsFeatureState, (state) => state.sectionTemplates); -export const resultOfTestSelector = createSelector(toEditOrNotToEdit, (testRecord) => testRecord?.testTypes[0].testResult); +export const resultOfTestSelector = createSelector( + toEditOrNotToEdit, + (testRecord) => testRecord?.testTypes[0].testResult +); export const isTestTypeKeySame = (key: keyof TestType) => - createSelector(selectedAmendedTestResultState, selectedTestResultState, (testRecord, amendedTestRecord) => { - return testRecord?.testTypes[0][`${key}`] === amendedTestRecord?.testTypes[0][`${key}`]; - }); + createSelector(selectedAmendedTestResultState, selectedTestResultState, (testRecord, amendedTestRecord) => { + return testRecord?.testTypes[0][`${key}`] === amendedTestRecord?.testTypes[0][`${key}`]; + }); // Common Functions /** @@ -107,22 +119,22 @@ export const isTestTypeKeySame = (key: keyof TestType) => * TODO: When we have better routing set up, we need to revisit this so that the testType is also selected based on route paramerets/queries. */ function getDefectFromTestResult(testResult: TestResultModel | undefined): TestResultDefects { - return (testResult?.testTypes && testResult.testTypes.length > 0 && testResult.testTypes[0].defects) || []; + return (testResult?.testTypes && testResult.testTypes.length > 0 && testResult.testTypes[0].defects) || []; } function byDate(a: TestResultModel, b: TestResultModel): -1 | 0 | 1 { - if (a === b) { - // equal items sort equally - return 0; - } - - if (!a.createdAt) { - // nulls sort after anything else - return 1; - } - if (!b.createdAt) { - return -1; - } - - return new Date(a.createdAt).getTime() > new Date(b.createdAt).getTime() ? -1 : 1; + if (a === b) { + // equal items sort equally + return 0; + } + + if (!a.createdAt) { + // nulls sort after anything else + return 1; + } + if (!b.createdAt) { + return -1; + } + + return new Date(a.createdAt).getTime() > new Date(b.createdAt).getTime() ? -1 : 1; } diff --git a/src/app/store/test-records/test-records.module.ts b/src/app/store/test-records/test-records.module.ts index 73a9cbfa51..6aacbc2f31 100644 --- a/src/app/store/test-records/test-records.module.ts +++ b/src/app/store/test-records/test-records.module.ts @@ -6,7 +6,11 @@ import { TestResultsEffects } from './effects/test-records.effects'; import { STORE_FEATURE_TEST_RESULTS_KEY, testResultsReducer } from './reducers/test-records.reducer'; @NgModule({ - declarations: [], - imports: [CommonModule, StoreModule.forFeature(STORE_FEATURE_TEST_RESULTS_KEY, testResultsReducer), EffectsModule.forFeature([TestResultsEffects])], + declarations: [], + imports: [ + CommonModule, + StoreModule.forFeature(STORE_FEATURE_TEST_RESULTS_KEY, testResultsReducer), + EffectsModule.forFeature([TestResultsEffects]), + ], }) export class TestRecordsStateModule {} diff --git a/src/app/store/test-stations/actions/test-stations.actions.spec.ts b/src/app/store/test-stations/actions/test-stations.actions.spec.ts index ab9780f7ab..a7cb4a2793 100644 --- a/src/app/store/test-stations/actions/test-stations.actions.spec.ts +++ b/src/app/store/test-stations/actions/test-stations.actions.spec.ts @@ -1,19 +1,19 @@ import { - fetchTestStation, - fetchTestStationFailed, - fetchTestStations, - fetchTestStationsFailed, - fetchTestStationsSuccess, - fetchTestStationSuccess, + fetchTestStation, + fetchTestStationFailed, + fetchTestStationSuccess, + fetchTestStations, + fetchTestStationsFailed, + fetchTestStationsSuccess, } from './test-stations.actions'; describe('Test Stations Actions', () => { - it('should return correct types', () => { - expect(fetchTestStations.type).toBe('[API/test-stations] Fetch Test Stations'); - expect(fetchTestStationsSuccess.type).toBe('[API/test-stations] Fetch Test Stations Success'); - expect(fetchTestStationsFailed.type).toBe('[API/test-stations] Fetch Test Stations Failed'); - expect(fetchTestStation.type).toBe('[API/test-stations] Fetch Test Station by ID'); - expect(fetchTestStationSuccess.type).toBe('[API/test-stations] Fetch Test Station by ID Success'); - expect(fetchTestStationFailed.type).toBe('[API/test-stations] Fetch Test Station by ID Failed'); - }); + it('should return correct types', () => { + expect(fetchTestStations.type).toBe('[API/test-stations] Fetch Test Stations'); + expect(fetchTestStationsSuccess.type).toBe('[API/test-stations] Fetch Test Stations Success'); + expect(fetchTestStationsFailed.type).toBe('[API/test-stations] Fetch Test Stations Failed'); + expect(fetchTestStation.type).toBe('[API/test-stations] Fetch Test Station by ID'); + expect(fetchTestStationSuccess.type).toBe('[API/test-stations] Fetch Test Station by ID Success'); + expect(fetchTestStationFailed.type).toBe('[API/test-stations] Fetch Test Station by ID Failed'); + }); }); diff --git a/src/app/store/test-stations/actions/test-stations.actions.ts b/src/app/store/test-stations/actions/test-stations.actions.ts index 1c0b1b5d0a..42d6128c83 100644 --- a/src/app/store/test-stations/actions/test-stations.actions.ts +++ b/src/app/store/test-stations/actions/test-stations.actions.ts @@ -7,11 +7,14 @@ export const fetchTestStationsSuccess = createAction(getTitle(true, 'Success'), export const fetchTestStationsFailed = createAction(getTitle(true, 'Failed'), props()); export const fetchTestStation = createAction(getTitle(), props<{ id: string }>()); -export const fetchTestStationSuccess = createAction(getTitle(false, 'Success'), props<{ id: string; payload: TestStation }>()); +export const fetchTestStationSuccess = createAction( + getTitle(false, 'Success'), + props<{ id: string; payload: TestStation }>() +); export const fetchTestStationFailed = createAction(getTitle(false, 'Failed'), props()); function getTitle(isPlural = false, suffix = ''): string { - const plural = isPlural ? 's' : ' by ID'; - suffix = suffix ? ` ${suffix}` : suffix; - return `[API/test-stations] Fetch Test Station${plural}${suffix}`; + const plural = isPlural ? 's' : ' by ID'; + suffix = suffix ? ` ${suffix}` : suffix; + return `[API/test-stations] Fetch Test Station${plural}${suffix}`; } diff --git a/src/app/store/test-stations/effects/test-stations.effects.spec.ts b/src/app/store/test-stations/effects/test-stations.effects.spec.ts index 4cd21ad512..70c120781c 100644 --- a/src/app/store/test-stations/effects/test-stations.effects.spec.ts +++ b/src/app/store/test-stations/effects/test-stations.effects.spec.ts @@ -9,116 +9,118 @@ import { initialAppState } from '@store/.'; import { Observable } from 'rxjs'; import { TestScheduler } from 'rxjs/testing'; import { - fetchTestStation, - fetchTestStationFailed, - fetchTestStations, - fetchTestStationsFailed, - fetchTestStationsSuccess, - fetchTestStationSuccess, + fetchTestStation, + fetchTestStationFailed, + fetchTestStationSuccess, + fetchTestStations, + fetchTestStationsFailed, + fetchTestStationsSuccess, } from '../actions/test-stations.actions'; import { TestStationsEffects } from './test-stations.effects'; describe('TestStationsEffects', () => { - let effects: TestStationsEffects; - let actions$ = new Observable(); - let testScheduler: TestScheduler; - let service: TestStationsService; - - const expectedResult = { testStationId: 'some ID' } as TestStation; - const testCases = [ - { - id: expectedResult.testStationId, - payload: [expectedResult], - }, - ]; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - TestStationsEffects, - provideMockActions(() => actions$), - TestStationsService, - provideMockStore({ - initialState: initialAppState, - }), - ], - }); - - effects = TestBed.inject(TestStationsEffects); - service = TestBed.inject(TestStationsService); - }); - - beforeEach(() => { - testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - }); - - describe('fetchTestStations$', () => { - it.each(testCases)('should return fetchTestStationsSuccess action on successfull API call', (value) => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const { payload } = value; - - // mock action to trigger effect - actions$ = hot('-a--', { a: fetchTestStations() }); - - // mock service call - jest.spyOn(service, 'fetchTestStations').mockReturnValue(cold('--a|', { a: payload })); - - // expect effect to return success action - expectObservable(effects.fetchTestStations$).toBe('---b', { - b: fetchTestStationsSuccess({ payload }), - }); - }); - }); - - it.each(testCases)('should return fetchTestStationsFailed action on API error', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - actions$ = hot('-a--', { a: fetchTestStations() }); - - const expectedError = new Error('Reference data resourceType is required'); - - jest.spyOn(service, 'fetchTestStations').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.fetchTestStations$).toBe('---b', { - b: fetchTestStationsFailed({ error: 'Reference data resourceType is required' }), - }); - }); - }); - }); - - describe('fetchTestStation$', () => { - it.each(testCases)('should return fetchTestStationSuccess action on successfull API call', (value) => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const { id, payload } = value; - - const entity = payload.find((p) => p.testStationId === id) as TestStation; - - // mock action to trigger effect - actions$ = hot('-a--', { a: fetchTestStation({ id }) }); - - // mock service call - jest.spyOn(service, 'fetchTestStation').mockReturnValue(cold('--a|', { a: entity })); - - // expect effect to return success action - expectObservable(effects.fetchTestStation$).toBe('---b', { - b: fetchTestStationSuccess({ id, payload: entity }), - }); - }); - }); - - it.each(testCases)('should return fetchTestStationFailed action on API error', (value) => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const { id } = value; - actions$ = hot('-a--', { a: fetchTestStation({ id }) }); - - const expectedError = new Error('Reference data resourceKey is required'); - - jest.spyOn(service, 'fetchTestStation').mockReturnValue(cold('--#|', {}, expectedError)); - - expectObservable(effects.fetchTestStation$).toBe('---b', { b: fetchTestStationFailed({ error: 'Reference data resourceKey is required' }) }); - }); - }); - }); + let effects: TestStationsEffects; + let actions$ = new Observable(); + let testScheduler: TestScheduler; + let service: TestStationsService; + + const expectedResult = { testStationId: 'some ID' } as TestStation; + const testCases = [ + { + id: expectedResult.testStationId, + payload: [expectedResult], + }, + ]; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule], + providers: [ + TestStationsEffects, + provideMockActions(() => actions$), + TestStationsService, + provideMockStore({ + initialState: initialAppState, + }), + ], + }); + + effects = TestBed.inject(TestStationsEffects); + service = TestBed.inject(TestStationsService); + }); + + beforeEach(() => { + testScheduler = new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); + }); + }); + + describe('fetchTestStations$', () => { + it.each(testCases)('should return fetchTestStationsSuccess action on successfull API call', (value) => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const { payload } = value; + + // mock action to trigger effect + actions$ = hot('-a--', { a: fetchTestStations() }); + + // mock service call + jest.spyOn(service, 'fetchTestStations').mockReturnValue(cold('--a|', { a: payload })); + + // expect effect to return success action + expectObservable(effects.fetchTestStations$).toBe('---b', { + b: fetchTestStationsSuccess({ payload }), + }); + }); + }); + + it.each(testCases)('should return fetchTestStationsFailed action on API error', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + actions$ = hot('-a--', { a: fetchTestStations() }); + + const expectedError = new Error('Reference data resourceType is required'); + + jest.spyOn(service, 'fetchTestStations').mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.fetchTestStations$).toBe('---b', { + b: fetchTestStationsFailed({ error: 'Reference data resourceType is required' }), + }); + }); + }); + }); + + describe('fetchTestStation$', () => { + it.each(testCases)('should return fetchTestStationSuccess action on successfull API call', (value) => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const { id, payload } = value; + + const entity = payload.find((p) => p.testStationId === id) as TestStation; + + // mock action to trigger effect + actions$ = hot('-a--', { a: fetchTestStation({ id }) }); + + // mock service call + jest.spyOn(service, 'fetchTestStation').mockReturnValue(cold('--a|', { a: entity })); + + // expect effect to return success action + expectObservable(effects.fetchTestStation$).toBe('---b', { + b: fetchTestStationSuccess({ id, payload: entity }), + }); + }); + }); + + it.each(testCases)('should return fetchTestStationFailed action on API error', (value) => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const { id } = value; + actions$ = hot('-a--', { a: fetchTestStation({ id }) }); + + const expectedError = new Error('Reference data resourceKey is required'); + + jest.spyOn(service, 'fetchTestStation').mockReturnValue(cold('--#|', {}, expectedError)); + + expectObservable(effects.fetchTestStation$).toBe('---b', { + b: fetchTestStationFailed({ error: 'Reference data resourceKey is required' }), + }); + }); + }); + }); }); diff --git a/src/app/store/test-stations/effects/test-stations.effects.ts b/src/app/store/test-stations/effects/test-stations.effects.ts index 3f52fcb049..c6aef9e6dd 100644 --- a/src/app/store/test-stations/effects/test-stations.effects.ts +++ b/src/app/store/test-stations/effects/test-stations.effects.ts @@ -1,39 +1,44 @@ import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { TestStationsService } from '@services/test-stations/test-stations.service'; +import { catchError, map, mergeMap, of } from 'rxjs'; import { - catchError, map, mergeMap, of, -} from 'rxjs'; -import { - fetchTestStation, - fetchTestStationFailed, - fetchTestStations, - fetchTestStationsFailed, - fetchTestStationsSuccess, - fetchTestStationSuccess, + fetchTestStation, + fetchTestStationFailed, + fetchTestStationSuccess, + fetchTestStations, + fetchTestStationsFailed, + fetchTestStationsSuccess, } from '../actions/test-stations.actions'; @Injectable() export class TestStationsEffects { - fetchTestStations$ = createEffect(() => - this.actions$.pipe( - ofType(fetchTestStations), - mergeMap(() => - this.testStationsService.fetchTestStations().pipe( - map((testStations) => fetchTestStationsSuccess({ payload: testStations })), - catchError((e) => of(fetchTestStationsFailed({ error: e.message }))), - )), - )); + fetchTestStations$ = createEffect(() => + this.actions$.pipe( + ofType(fetchTestStations), + mergeMap(() => + this.testStationsService.fetchTestStations().pipe( + map((testStations) => fetchTestStationsSuccess({ payload: testStations })), + catchError((e) => of(fetchTestStationsFailed({ error: e.message }))) + ) + ) + ) + ); - fetchTestStation$ = createEffect(() => - this.actions$.pipe( - ofType(fetchTestStation), - mergeMap(({ id }) => - this.testStationsService.fetchTestStation(id).pipe( - map((testStation) => fetchTestStationSuccess({ id, payload: testStation })), - catchError((e) => of(fetchTestStationFailed({ error: e.message }))), - )), - )); + fetchTestStation$ = createEffect(() => + this.actions$.pipe( + ofType(fetchTestStation), + mergeMap(({ id }) => + this.testStationsService.fetchTestStation(id).pipe( + map((testStation) => fetchTestStationSuccess({ id, payload: testStation })), + catchError((e) => of(fetchTestStationFailed({ error: e.message }))) + ) + ) + ) + ); - constructor(private actions$: Actions, private testStationsService: TestStationsService) { } + constructor( + private actions$: Actions, + private testStationsService: TestStationsService + ) {} } diff --git a/src/app/store/test-stations/reducers/test-stations.reducer.spec.ts b/src/app/store/test-stations/reducers/test-stations.reducer.spec.ts index c00f4cebd5..f07b83a390 100644 --- a/src/app/store/test-stations/reducers/test-stations.reducer.spec.ts +++ b/src/app/store/test-stations/reducers/test-stations.reducer.spec.ts @@ -1,99 +1,99 @@ import { TestStation } from '@models/test-stations/test-station.model'; import { - fetchTestStation, - fetchTestStationFailed, - fetchTestStations, - fetchTestStationsFailed, - fetchTestStationsSuccess, - fetchTestStationSuccess, + fetchTestStation, + fetchTestStationFailed, + fetchTestStationSuccess, + fetchTestStations, + fetchTestStationsFailed, + fetchTestStationsSuccess, } from '../actions/test-stations.actions'; -import { initialTestStationsState, testStationsReducer, TestStationsState } from './test-stations.reducer'; +import { TestStationsState, initialTestStationsState, testStationsReducer } from './test-stations.reducer'; describe('Test Stations Reducer', () => { - const expectedTestStations = [{ testStationId: 'someId' } as TestStation]; + const expectedTestStations = [{ testStationId: 'someId' } as TestStation]; - describe('unknown action', () => { - it('should return the default state', () => { - const action = { - type: 'Unknown', - }; - const state = testStationsReducer(initialTestStationsState, action); + describe('unknown action', () => { + it('should return the default state', () => { + const action = { + type: 'Unknown', + }; + const state = testStationsReducer(initialTestStationsState, action); - expect(state).toBe(initialTestStationsState); - }); - }); + expect(state).toBe(initialTestStationsState); + }); + }); - describe('fetchTestStations actions', () => { - it('should set loading to true', () => { - const newState: TestStationsState = { ...initialTestStationsState, loading: true }; - const action = fetchTestStations(); - const state = testStationsReducer(initialTestStationsState, action); + describe('fetchTestStations actions', () => { + it('should set loading to true', () => { + const newState: TestStationsState = { ...initialTestStationsState, loading: true }; + const action = fetchTestStations(); + const state = testStationsReducer(initialTestStationsState, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); - describe('fetchTestStationsSuccess', () => { - it('should set all test result records', () => { - const newState: TestStationsState = { - ...initialTestStationsState, - ids: ['someId'], - entities: { someId: expectedTestStations[0] }, - }; - const action = fetchTestStationsSuccess({ payload: [...expectedTestStations] }); - const state = testStationsReducer(initialTestStationsState, action); + describe('fetchTestStationsSuccess', () => { + it('should set all test result records', () => { + const newState: TestStationsState = { + ...initialTestStationsState, + ids: ['someId'], + entities: { someId: expectedTestStations[0] }, + }; + const action = fetchTestStationsSuccess({ payload: [...expectedTestStations] }); + const state = testStationsReducer(initialTestStationsState, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); - describe('fetchTestStationsFailed', () => { - it('should set error state', () => { - const newState = { ...initialTestStationsState, loading: false }; - const action = fetchTestStationsFailed({ error: 'unit testing error message' }); - const state = testStationsReducer({ ...initialTestStationsState, loading: true }, action); + describe('fetchTestStationsFailed', () => { + it('should set error state', () => { + const newState = { ...initialTestStationsState, loading: false }; + const action = fetchTestStationsFailed({ error: 'unit testing error message' }); + const state = testStationsReducer({ ...initialTestStationsState, loading: true }, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - }); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + }); + }); - describe('fetchTestStationById actions', () => { - it('should set loading to true', () => { - const newState: TestStationsState = { ...initialTestStationsState, loading: true }; - const action = fetchTestStation({ id: 'TestStationId0001' }); - const state = testStationsReducer(initialTestStationsState, action); + describe('fetchTestStationById actions', () => { + it('should set loading to true', () => { + const newState: TestStationsState = { ...initialTestStationsState, loading: true }; + const action = fetchTestStation({ id: 'TestStationId0001' }); + const state = testStationsReducer(initialTestStationsState, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); - describe('fetchTestStationsByIdSuccess', () => { - it('should set all test result records', () => { - const newState: TestStationsState = { - ...initialTestStationsState, - ids: ['someId'], - entities: { someId: expectedTestStations[0] }, - }; - const action = fetchTestStationSuccess({ id: 'TestStationId0001', payload: expectedTestStations[0] }); - const state = testStationsReducer(initialTestStationsState, action); + describe('fetchTestStationsByIdSuccess', () => { + it('should set all test result records', () => { + const newState: TestStationsState = { + ...initialTestStationsState, + ids: ['someId'], + entities: { someId: expectedTestStations[0] }, + }; + const action = fetchTestStationSuccess({ id: 'TestStationId0001', payload: expectedTestStations[0] }); + const state = testStationsReducer(initialTestStationsState, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); - describe('fetchTestStationsByIdFailed', () => { - it('should set error state', () => { - const newState = { ...initialTestStationsState, loading: false }; - const action = fetchTestStationFailed({ error: 'unit testing error message' }); - const state = testStationsReducer({ ...initialTestStationsState, loading: true }, action); + describe('fetchTestStationsByIdFailed', () => { + it('should set error state', () => { + const newState = { ...initialTestStationsState, loading: false }; + const action = fetchTestStationFailed({ error: 'unit testing error message' }); + const state = testStationsReducer({ ...initialTestStationsState, loading: true }, action); - expect(state).toEqual(newState); - expect(state).not.toBe(newState); - }); - }); - }); + expect(state).toEqual(newState); + expect(state).not.toBe(newState); + }); + }); + }); }); diff --git a/src/app/store/test-stations/reducers/test-stations.reducer.ts b/src/app/store/test-stations/reducers/test-stations.reducer.ts index b0a20e8b74..79f8bf21d3 100644 --- a/src/app/store/test-stations/reducers/test-stations.reducer.ts +++ b/src/app/store/test-stations/reducers/test-stations.reducer.ts @@ -1,18 +1,18 @@ import { TestStation } from '@models/test-stations/test-station.model'; -import { createEntityAdapter, EntityAdapter, EntityState } from '@ngrx/entity'; +import { EntityAdapter, EntityState, createEntityAdapter } from '@ngrx/entity'; import { createFeatureSelector, createReducer, on } from '@ngrx/store'; import { - fetchTestStation, - fetchTestStationFailed, - fetchTestStations, - fetchTestStationsFailed, - fetchTestStationsSuccess, - fetchTestStationSuccess, + fetchTestStation, + fetchTestStationFailed, + fetchTestStationSuccess, + fetchTestStations, + fetchTestStationsFailed, + fetchTestStationsSuccess, } from '../actions/test-stations.actions'; export interface TestStationsState extends EntityState { - loading: boolean; - error: string; + loading: boolean; + error: string; } export const STORE_FEATURE_TEST_STATIONS_KEY = 'testStations'; @@ -20,19 +20,25 @@ export const STORE_FEATURE_TEST_STATIONS_KEY = 'testStations'; export const testStationsFeatureState = createFeatureSelector(STORE_FEATURE_TEST_STATIONS_KEY); export const testStationsAdapter: EntityAdapter = createEntityAdapter({ - selectId: (testStation) => testStation.testStationId, + selectId: (testStation) => testStation.testStationId, }); export const initialTestStationsState = testStationsAdapter.getInitialState({ loading: false, error: '' }); export const testStationsReducer = createReducer( - initialTestStationsState, - - on(fetchTestStations, (state) => ({ ...state, loading: true })), - on(fetchTestStationsSuccess, (state, action) => ({ ...testStationsAdapter.setAll(action.payload, state), loading: false })), - on(fetchTestStationsFailed, (state) => ({ ...testStationsAdapter.setAll([], state), loading: false })), - - on(fetchTestStation, (state) => ({ ...state, loading: true })), - on(fetchTestStationSuccess, (state, action) => ({ ...testStationsAdapter.upsertOne(action.payload, state), loading: false })), - on(fetchTestStationFailed, (state) => ({ ...testStationsAdapter.setAll([], state), loading: false })), + initialTestStationsState, + + on(fetchTestStations, (state) => ({ ...state, loading: true })), + on(fetchTestStationsSuccess, (state, action) => ({ + ...testStationsAdapter.setAll(action.payload, state), + loading: false, + })), + on(fetchTestStationsFailed, (state) => ({ ...testStationsAdapter.setAll([], state), loading: false })), + + on(fetchTestStation, (state) => ({ ...state, loading: true })), + on(fetchTestStationSuccess, (state, action) => ({ + ...testStationsAdapter.upsertOne(action.payload, state), + loading: false, + })), + on(fetchTestStationFailed, (state) => ({ ...testStationsAdapter.setAll([], state), loading: false })) ); diff --git a/src/app/store/test-stations/selectors/test-stations.selectors.spec.ts b/src/app/store/test-stations/selectors/test-stations.selectors.spec.ts index b61bbbf669..90df98d4bb 100644 --- a/src/app/store/test-stations/selectors/test-stations.selectors.spec.ts +++ b/src/app/store/test-stations/selectors/test-stations.selectors.spec.ts @@ -1,57 +1,68 @@ import { TestStation } from '@models/test-stations/test-station.model'; -import { initialTestStationsState, TestStationsState } from '../reducers/test-stations.reducer'; +import { TestStationsState, initialTestStationsState } from '../reducers/test-stations.reducer'; import { - getTestStationFromProperty, testStation, testStations, testStationsLoadingState, + getTestStationFromProperty, + testStation, + testStations, + testStationsLoadingState, } from './test-stations.selectors'; describe('Test Results Selectors', () => { - describe('adapter selectors', () => { - it('should return correct state', () => { - const state = { ...initialTestStationsState, ids: ['1'], entities: { 1: { preparerId: '2' } } } as unknown as TestStationsState; + describe('adapter selectors', () => { + it('should return correct state', () => { + const state = { + ...initialTestStationsState, + ids: ['1'], + entities: { 1: { preparerId: '2' } }, + } as unknown as TestStationsState; - expect(testStations.projector(state)).toEqual([{ preparerId: '2' }]); - expect(testStation('1').projector(state)).toEqual({ preparerId: '2' }); - }); - }); + expect(testStations.projector(state)).toEqual([{ preparerId: '2' }]); + expect(testStation('1').projector(state)).toEqual({ preparerId: '2' }); + }); + }); - describe('testStationsLoadingState', () => { - it('should return loading state', () => { - const state: TestStationsState = { ...initialTestStationsState, loading: true }; - const selectedState = testStationsLoadingState.projector(state); - expect(selectedState).toBeTruthy(); - }); - }); + describe('testStationsLoadingState', () => { + it('should return loading state', () => { + const state: TestStationsState = { ...initialTestStationsState, loading: true }; + const selectedState = testStationsLoadingState.projector(state); + expect(selectedState).toBeTruthy(); + }); + }); - describe('getTestStationsFromProperty', () => { - it('return a test station with a matching testStationName', () => { - const testStationsArray = [ - { - testStationName: 'foo', - testStationPNumber: '1234', - testStationType: 'gvts', - }, - { - testStationName: 'bar', - testStationPNumber: '356728', - testStationType: 'atf', - }, - ] as TestStation[]; - expect(getTestStationFromProperty('testStationName', 'foo').projector(testStationsArray)).toEqual(testStationsArray[0]); - }); - it('return a test station with a matching PNumber', () => { - const testStationsArray = [ - { - testStationName: 'foo', - testStationPNumber: '1234', - testStationType: 'gvts', - }, - { - testStationName: 'bar', - testStationPNumber: '356728', - testStationType: 'atf', - }, - ] as TestStation[]; - expect(getTestStationFromProperty('testStationPNumber', '356728').projector(testStationsArray)).toEqual(testStationsArray[1]); - }); - }); + describe('getTestStationsFromProperty', () => { + it('return a test station with a matching testStationName', () => { + const testStationsArray = [ + { + testStationName: 'foo', + testStationPNumber: '1234', + testStationType: 'gvts', + }, + { + testStationName: 'bar', + testStationPNumber: '356728', + testStationType: 'atf', + }, + ] as TestStation[]; + expect(getTestStationFromProperty('testStationName', 'foo').projector(testStationsArray)).toEqual( + testStationsArray[0] + ); + }); + it('return a test station with a matching PNumber', () => { + const testStationsArray = [ + { + testStationName: 'foo', + testStationPNumber: '1234', + testStationType: 'gvts', + }, + { + testStationName: 'bar', + testStationPNumber: '356728', + testStationType: 'atf', + }, + ] as TestStation[]; + expect(getTestStationFromProperty('testStationPNumber', '356728').projector(testStationsArray)).toEqual( + testStationsArray[1] + ); + }); + }); }); diff --git a/src/app/store/test-stations/selectors/test-stations.selectors.ts b/src/app/store/test-stations/selectors/test-stations.selectors.ts index 470a02bbff..92853a3958 100644 --- a/src/app/store/test-stations/selectors/test-stations.selectors.ts +++ b/src/app/store/test-stations/selectors/test-stations.selectors.ts @@ -11,4 +11,4 @@ export const testStation = (id: string) => createSelector(testStationsFeatureSta export const testStationsLoadingState = createSelector(testStationsFeatureState, (state) => state.loading); export const getTestStationFromProperty = (property: keyof TestStation, value: string) => - createSelector(testStations, (stations) => stations.find((station) => station[`${property}`] === value)); + createSelector(testStations, (stations) => stations.find((station) => station[`${property}`] === value)); diff --git a/src/app/store/test-stations/test-stations-state.module.ts b/src/app/store/test-stations/test-stations-state.module.ts index 4fcdfe769f..616ce93cf0 100644 --- a/src/app/store/test-stations/test-stations-state.module.ts +++ b/src/app/store/test-stations/test-stations-state.module.ts @@ -6,11 +6,11 @@ import { TestStationsEffects } from './effects/test-stations.effects'; import { STORE_FEATURE_TEST_STATIONS_KEY, testStationsReducer } from './reducers/test-stations.reducer'; @NgModule({ - declarations: [], - imports: [ - CommonModule, - StoreModule.forFeature(STORE_FEATURE_TEST_STATIONS_KEY, testStationsReducer), - EffectsModule.forFeature([TestStationsEffects]), - ], + declarations: [], + imports: [ + CommonModule, + StoreModule.forFeature(STORE_FEATURE_TEST_STATIONS_KEY, testStationsReducer), + EffectsModule.forFeature([TestStationsEffects]), + ], }) export class TestStationsStateModule {} diff --git a/src/app/store/test-types/actions/test-types.actions.spec.ts b/src/app/store/test-types/actions/test-types.actions.spec.ts index 8019be9bca..3173b63028 100644 --- a/src/app/store/test-types/actions/test-types.actions.spec.ts +++ b/src/app/store/test-types/actions/test-types.actions.spec.ts @@ -1,9 +1,9 @@ -import { fetchTestTypes, fetchTestTypesSuccess, fetchTestTypesFailed } from './test-types.actions'; +import { fetchTestTypes, fetchTestTypesFailed, fetchTestTypesSuccess } from './test-types.actions'; describe('Test Result Actions', () => { - it('should return correct types', () => { - expect(fetchTestTypes.type).toBe('[API/test-types-taxonomy] Fetch All'); - expect(fetchTestTypesSuccess.type).toBe('[API/test-types-taxonomy] Fetch All Success'); - expect(fetchTestTypesFailed.type).toBe('[API/test-types-taxonomy] Fetch All Failed'); - }); + it('should return correct types', () => { + expect(fetchTestTypes.type).toBe('[API/test-types-taxonomy] Fetch All'); + expect(fetchTestTypesSuccess.type).toBe('[API/test-types-taxonomy] Fetch All Success'); + expect(fetchTestTypesFailed.type).toBe('[API/test-types-taxonomy] Fetch All Failed'); + }); }); diff --git a/src/app/store/test-types/actions/test-types.actions.ts b/src/app/store/test-types/actions/test-types.actions.ts index 4272b0b640..4c5d74d371 100644 --- a/src/app/store/test-types/actions/test-types.actions.ts +++ b/src/app/store/test-types/actions/test-types.actions.ts @@ -5,5 +5,8 @@ import { createAction, props } from '@ngrx/store'; const prefix = '[API/test-types-taxonomy] '; export const fetchTestTypes = createAction(`${prefix}Fetch All`); -export const fetchTestTypesSuccess = createAction(`${prefix}Fetch All Success`, props<{ payload: TestTypesTaxonomy }>()); +export const fetchTestTypesSuccess = createAction( + `${prefix}Fetch All Success`, + props<{ payload: TestTypesTaxonomy }>() +); export const fetchTestTypesFailed = createAction(`${prefix}Fetch All Failed`, props()); diff --git a/src/app/store/test-types/effects/test-types.effects.spec.ts b/src/app/store/test-types/effects/test-types.effects.spec.ts index 4635505c21..2a197a6e11 100644 --- a/src/app/store/test-types/effects/test-types.effects.spec.ts +++ b/src/app/store/test-types/effects/test-types.effects.spec.ts @@ -16,78 +16,80 @@ import { fetchTestTypes, fetchTestTypesFailed, fetchTestTypesSuccess } from '../ import { TestTypeEffects } from './test-types.effects'; describe('TestResultsEffects', () => { - let effects: TestTypeEffects; - let actions$ = new Observable(); - let testScheduler: TestScheduler; - let testTypesService: TestTypesService; + let effects: TestTypeEffects; + let actions$ = new Observable(); + let testScheduler: TestScheduler; + let testTypesService: TestTypesService; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule, TestTypesApiModule], - providers: [ - TestTypeEffects, - provideMockActions(() => actions$), - TestTypesService, - provideMockStore({ - initialState: initialAppState, - }), - RouterService, - { - provide: UserService, - useValue: { roles$: of(['TestResult.CreateDeskBased']) }, - }, - ], - }); + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [HttpClientTestingModule, TestTypesApiModule], + providers: [ + TestTypeEffects, + provideMockActions(() => actions$), + TestTypesService, + provideMockStore({ + initialState: initialAppState, + }), + RouterService, + { + provide: UserService, + useValue: { roles$: of(['TestResult.CreateDeskBased']) }, + }, + ], + }); - effects = TestBed.inject(TestTypeEffects); - testTypesService = TestBed.inject(TestTypesService); - }); + effects = TestBed.inject(TestTypeEffects); + testTypesService = TestBed.inject(TestTypesService); + }); - beforeEach(() => { - testScheduler = new TestScheduler((actual, expected) => { - expect(actual).toEqual(expected); - }); - }); + beforeEach(() => { + testScheduler = new TestScheduler((actual, expected) => { + expect(actual).toEqual(expected); + }); + }); - describe('fetchTestTypeTaxonomy$', () => { - it('should return fetchTestTypesSuccess action on successfull API call', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - const testTypes = {} as TestTypesTaxonomy; + describe('fetchTestTypeTaxonomy$', () => { + it('should return fetchTestTypesSuccess action on successfull API call', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + const testTypes = {} as TestTypesTaxonomy; - // mock action to trigger effect - actions$ = hot('-a--', { a: fetchTestTypes }); + // mock action to trigger effect + actions$ = hot('-a--', { a: fetchTestTypes }); - // mock service call - (testTypesService.getTestTypes as () => Observable) = jest.fn((): Observable => { - return cold('--a|', { a: testTypes }); - }); + // mock service call + (testTypesService.getTestTypes as () => Observable) = jest.fn( + (): Observable => { + return cold('--a|', { a: testTypes }); + } + ); - // expect effect to return success action - expectObservable(effects.fetchTestTypeTaxonomy$).toBe('---b', { - b: fetchTestTypesSuccess({ payload: testTypes }), - }); - }); - }); + // expect effect to return success action + expectObservable(effects.fetchTestTypeTaxonomy$).toBe('---b', { + b: fetchTestTypesSuccess({ payload: testTypes }), + }); + }); + }); - it('should return fetchTestTypesFailed action on successful API call', () => { - testScheduler.run(({ hot, cold, expectObservable }) => { - actions$ = hot('-a--', { a: fetchTestTypes }); + it('should return fetchTestTypesFailed action on successful API call', () => { + testScheduler.run(({ hot, cold, expectObservable }) => { + actions$ = hot('-a--', { a: fetchTestTypes }); - const expectedError = new HttpErrorResponse({ - status: 500, - statusText: 'Internal server error', - }); + const expectedError = new HttpErrorResponse({ + status: 500, + statusText: 'Internal server error', + }); - // mock service call - (testTypesService.getTestTypes as () => Observable) = jest.fn((): Observable => { - return cold('--#|', {}, expectedError); - }); + // mock service call + (testTypesService.getTestTypes as () => Observable) = jest.fn((): Observable => { + return cold('--#|', {}, expectedError); + }); - // expect effect to return success action - expectObservable(effects.fetchTestTypeTaxonomy$).toBe('---b', { - b: fetchTestTypesFailed({ error: expectedError.message }), - }); - }); - }); - }); + // expect effect to return success action + expectObservable(effects.fetchTestTypeTaxonomy$).toBe('---b', { + b: fetchTestTypesFailed({ error: expectedError.message }), + }); + }); + }); + }); }); diff --git a/src/app/store/test-types/effects/test-types.effects.ts b/src/app/store/test-types/effects/test-types.effects.ts index a77210ea62..e38d6a64f6 100644 --- a/src/app/store/test-types/effects/test-types.effects.ts +++ b/src/app/store/test-types/effects/test-types.effects.ts @@ -4,26 +4,31 @@ import { TypeOfTest } from '@models/test-results/typeOfTest.enum'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { TestTypesService } from '@services/test-types/test-types.service'; import { UserService } from '@services/user-service/user-service'; -import { - catchError, switchMap, map, of, -} from 'rxjs'; +import { catchError, map, of, switchMap } from 'rxjs'; import { fetchTestTypes, fetchTestTypesFailed, fetchTestTypesSuccess } from '../actions/test-types.actions'; @Injectable() export class TestTypeEffects { - fetchTestTypeTaxonomy$ = createEffect(() => - this.actions$.pipe( - ofType(fetchTestTypes), - switchMap(() => this.userService.roles$), - switchMap((roles) => { - const typeOfTest = Roles.TestResultCreateDeskAssessment.split(',').some((role) => roles?.includes(role)) ? TypeOfTest.DESK_BASED : undefined; + fetchTestTypeTaxonomy$ = createEffect(() => + this.actions$.pipe( + ofType(fetchTestTypes), + switchMap(() => this.userService.roles$), + switchMap((roles) => { + const typeOfTest = Roles.TestResultCreateDeskAssessment.split(',').some((role) => roles?.includes(role)) + ? TypeOfTest.DESK_BASED + : undefined; - return this.testTypeService.getTestTypes(typeOfTest).pipe( - map((testTypes) => fetchTestTypesSuccess({ payload: testTypes })), - catchError((e) => of(fetchTestTypesFailed({ error: e.message }))), - ); - }), - )); + return this.testTypeService.getTestTypes(typeOfTest).pipe( + map((testTypes) => fetchTestTypesSuccess({ payload: testTypes })), + catchError((e) => of(fetchTestTypesFailed({ error: e.message }))) + ); + }) + ) + ); - constructor(private actions$: Actions, private testTypeService: TestTypesService, private userService: UserService) { } + constructor( + private actions$: Actions, + private testTypeService: TestTypesService, + private userService: UserService + ) {} } diff --git a/src/app/store/test-types/reducers/test-types.reducer.spec.ts b/src/app/store/test-types/reducers/test-types.reducer.spec.ts index f0c3b1b400..7ca6de6011 100644 --- a/src/app/store/test-types/reducers/test-types.reducer.spec.ts +++ b/src/app/store/test-types/reducers/test-types.reducer.spec.ts @@ -1,54 +1,54 @@ import { TestTypeCategory, TestTypesTaxonomy } from '@api/test-types'; import { fetchTestTypes, fetchTestTypesFailed, fetchTestTypesSuccess } from '../actions/test-types.actions'; -import { initialTestTypeState, testTypesReducer, TestTypeState } from './test-types.reducer'; +import { TestTypeState, initialTestTypeState, testTypesReducer } from './test-types.reducer'; describe('Test Types Reducer', () => { - describe('unknown action', () => { - it('should return the default state', () => { - const action = { - type: 'Unknown', - }; - const state = testTypesReducer(initialTestTypeState, action); - - expect(state).toBe(initialTestTypeState); - }); - - it('should set loading to true', () => { - const oldState: TestTypeState = { ...initialTestTypeState, loading: false }; - const action = fetchTestTypes(); - const state = testTypesReducer(oldState, action); - - expect(state.loading).toBe(true); - expect(state).not.toBe(oldState); - }); - - it('should set the test types data on success and set loading to false on success action', () => { - const testTypes = [ - { id: '1', name: 'foo' }, - { id: '12', name: 'bar' }, - ] as TestTypesTaxonomy; - const newState: TestTypeState = { - ...initialTestTypeState, - entities: { - 1: { id: '1', name: 'foo' } as TestTypeCategory, - 12: { id: '12', name: 'bar' } as TestTypeCategory, - }, - ids: ['1', '12'], - loading: false, - }; - const action = fetchTestTypesSuccess({ payload: testTypes }); - const state = testTypesReducer({ ...initialTestTypeState, loading: true }, action); - - expect(state).toEqual(newState); - }); - - it('should set loading to false on failed action', () => { - const oldState: TestTypeState = { ...initialTestTypeState, loading: true }; - const action = fetchTestTypesFailed({ error: 'error' }); - const state = testTypesReducer(oldState, action); - - expect(state.loading).toBe(false); - expect(state).not.toBe(oldState); - }); - }); + describe('unknown action', () => { + it('should return the default state', () => { + const action = { + type: 'Unknown', + }; + const state = testTypesReducer(initialTestTypeState, action); + + expect(state).toBe(initialTestTypeState); + }); + + it('should set loading to true', () => { + const oldState: TestTypeState = { ...initialTestTypeState, loading: false }; + const action = fetchTestTypes(); + const state = testTypesReducer(oldState, action); + + expect(state.loading).toBe(true); + expect(state).not.toBe(oldState); + }); + + it('should set the test types data on success and set loading to false on success action', () => { + const testTypes = [ + { id: '1', name: 'foo' }, + { id: '12', name: 'bar' }, + ] as TestTypesTaxonomy; + const newState: TestTypeState = { + ...initialTestTypeState, + entities: { + 1: { id: '1', name: 'foo' } as TestTypeCategory, + 12: { id: '12', name: 'bar' } as TestTypeCategory, + }, + ids: ['1', '12'], + loading: false, + }; + const action = fetchTestTypesSuccess({ payload: testTypes }); + const state = testTypesReducer({ ...initialTestTypeState, loading: true }, action); + + expect(state).toEqual(newState); + }); + + it('should set loading to false on failed action', () => { + const oldState: TestTypeState = { ...initialTestTypeState, loading: true }; + const action = fetchTestTypesFailed({ error: 'error' }); + const state = testTypesReducer(oldState, action); + + expect(state.loading).toBe(false); + expect(state).not.toBe(oldState); + }); + }); }); diff --git a/src/app/store/test-types/reducers/test-types.reducer.ts b/src/app/store/test-types/reducers/test-types.reducer.ts index 6a983437ae..967829dfe6 100644 --- a/src/app/store/test-types/reducers/test-types.reducer.ts +++ b/src/app/store/test-types/reducers/test-types.reducer.ts @@ -1,23 +1,25 @@ import { TestType, TestTypeCategory } from '@api/test-types'; -import { EntityAdapter, createEntityAdapter, EntityState } from '@ngrx/entity'; +import { EntityAdapter, EntityState, createEntityAdapter } from '@ngrx/entity'; import { createFeatureSelector, createReducer, on } from '@ngrx/store'; -import { fetchTestTypesFailed, fetchTestTypesSuccess, fetchTestTypes } from '../actions/test-types.actions'; +import { fetchTestTypes, fetchTestTypesFailed, fetchTestTypesSuccess } from '../actions/test-types.actions'; export const STORE_FEATURE_TEST_TYPES_KEY = 'testTypes'; -export const testTypesAdapter: EntityAdapter = createEntityAdapter(); +export const testTypesAdapter: EntityAdapter = createEntityAdapter< + TestType | TestTypeCategory +>(); export interface TestTypeState extends EntityState { - loading: boolean; + loading: boolean; } export const initialTestTypeState = testTypesAdapter.getInitialState({ loading: false }); export const testTypesReducer = createReducer( - initialTestTypeState, - on(fetchTestTypes, (state) => ({ ...state, loading: true })), - on(fetchTestTypesSuccess, (state, action) => ({ ...testTypesAdapter.setAll(action.payload, state), loading: false })), - on(fetchTestTypesFailed, (state) => ({ ...state, loading: false })), + initialTestTypeState, + on(fetchTestTypes, (state) => ({ ...state, loading: true })), + on(fetchTestTypesSuccess, (state, action) => ({ ...testTypesAdapter.setAll(action.payload, state), loading: false })), + on(fetchTestTypesFailed, (state) => ({ ...state, loading: false })) ); export const testTypesFeatureState = createFeatureSelector(STORE_FEATURE_TEST_TYPES_KEY); diff --git a/src/app/store/test-types/selectors/test-types.selectors.spec.ts b/src/app/store/test-types/selectors/test-types.selectors.spec.ts index 626ed7003a..352282d914 100644 --- a/src/app/store/test-types/selectors/test-types.selectors.spec.ts +++ b/src/app/store/test-types/selectors/test-types.selectors.spec.ts @@ -5,370 +5,510 @@ import { StatusCodes, VehicleSubclass, VehicleTypes } from '@models/vehicle-tech import { selectTestType, selectTestTypesByVehicleType, sortedTestTypes } from './test-types.selectors'; describe('selectors', () => { - describe('selectTestTypesByVehicleType', () => { - it('test with no data', () => { - const selector = selectTestTypesByVehicleType.projector([], { vehicleType: 'psv' } as TestResultModel, []); - expect(selector).toHaveLength(0); - }); - - it('test with vehicle type', () => { - const testTypes = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - - const expectedTestTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }] }, - ] as TestTypesTaxonomy; - const selector = selectTestTypesByVehicleType.projector(testTypes, { vehicleType: 'psv' } as TestResultModel, []); - expect(selector).toHaveLength(3); - expect(selector).toEqual(expectedTestTypes); - }); - - it('test with techRecordHistorys', () => { - const techRecordHistorys: TechRecordSearchSchema[] = [{ - vin: 'iii', - techRecord_statusCode: 'current', - techRecord_vehicleType: 'trl', - createdTimestamp: '2022-01-01', - systemNumber: '000', - techRecord_manufactureYear: null, - }]; - const testTypes: TestTypesTaxonomy = [ - { - forVehicleType: ['trl'], forEuVehicleCategory: ['m1'], id: '41', forProvisionalStatus: true, forProvisionalStatusOnly: true, - }, - { - forVehicleType: ['trl'], forEuVehicleCategory: ['m2'], id: '1', - }, - { - forVehicleType: ['trl'], forEuVehicleCategory: ['m2'], id: '12', forProvisionalStatus: true, - }, - { - forVehicleType: ['trl', 'hgv'], - forProvisionalStatus: true, - forProvisionalStatusOnly: true, - }, - ] as TestTypesTaxonomy; - - const expectedTestTypes: TestTypesTaxonomy = [ - { - forVehicleType: ['trl'], forEuVehicleCategory: ['m2'], id: '12', forProvisionalStatus: true, - }, - { - forVehicleType: ['trl', 'hgv'], - forProvisionalStatus: true, - forProvisionalStatusOnly: true, - }, - ] as TestTypesTaxonomy; - - const additionalExpectedTestTypes: TestTypesTaxonomy = [ - { - forVehicleType: ['trl'], forEuVehicleCategory: ['m2'], id: '1', - }, - { - forVehicleType: ['trl'], forEuVehicleCategory: ['m2'], id: '12', forProvisionalStatus: true, - }, - ] as TestTypesTaxonomy; - const selector = selectTestTypesByVehicleType.projector(testTypes, { - vehicleType: VehicleTypes.TRL, - statusCode: StatusCodes.PROVISIONAL, - } as TestResultModel, techRecordHistorys); - expect(selector).toEqual(expectedTestTypes); - - const selectorAdditional = selectTestTypesByVehicleType.projector(testTypes, { - vehicleType: VehicleTypes.TRL, - statusCode: StatusCodes.CURRENT, - } as TestResultModel, techRecordHistorys); - - expect(selectorAdditional).toEqual(additionalExpectedTestTypes); - }); - - it('test with eu vehicle category', () => { - const testTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - - const expectedTestTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - const selector = selectTestTypesByVehicleType.projector(testTypes, { euVehicleCategory: 'm1' } as TestResultModel, []); - expect(selector).toHaveLength(3); - expect(selector).toEqual(expectedTestTypes); - }); - - it('test with vehicle size', () => { - const testTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - - const expectedTestTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - const selector = selectTestTypesByVehicleType.projector(testTypes, { vehicleSize: 'small' } as TestResultModel, []); - expect(selector).toHaveLength(4); - expect(selector).toEqual(expectedTestTypes); - }); - - it('test with vehicle configuration', () => { - const testTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleConfiguration: ['articulated'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - - const expectedTestTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - - const selector = selectTestTypesByVehicleType.projector(testTypes, { vehicleConfiguration: 'rigid' } as TestResultModel, []); - expect(selector).toHaveLength(4); - expect(selector).toEqual(expectedTestTypes); - - const selectorAdditional = selectTestTypesByVehicleType.projector(testTypes, { vehicleConfiguration: 'articulated' } as TestResultModel, []); - expect(selectorAdditional).toHaveLength(5); - }); - - it('test with vehicle number of axles', () => { - const testTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleAxles: [2] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - - const expectedTestTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - - const selector = selectTestTypesByVehicleType.projector(testTypes, { noOfAxles: 4 } as TestResultModel, []); - expect(selector).toHaveLength(4); - expect(selector).toEqual(expectedTestTypes); - - const selectorAdditional = selectTestTypesByVehicleType.projector(testTypes, { noOfAxles: 2 } as TestResultModel, []); - expect(selectorAdditional).toHaveLength(5); - }); - - it('test with vehicle class using code', () => { - const testTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleClass: ['n'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - - const expectedTestTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - - const selector = selectTestTypesByVehicleType.projector(testTypes, { vehicleClass: { code: 's' } } as TestResultModel, []); - expect(selector).toHaveLength(4); - expect(selector).toEqual(expectedTestTypes); - - const selectorAdditional = selectTestTypesByVehicleType.projector(testTypes, { vehicleClass: { code: 'n' } } as TestResultModel, []); - expect(selectorAdditional).toHaveLength(5); - }); - - it('test with vehicle class using description', () => { - const testTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleClass: ['3 wheelers'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - - const expectedTestTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - - const selector = selectTestTypesByVehicleType.projector(testTypes, { - vehicleClass: { description: 'motorbikes up to 200cc' }, - } as TestResultModel, []); - expect(selector).toHaveLength(4); - expect(selector).toEqual(expectedTestTypes); - - const selectorAdditional = selectTestTypesByVehicleType.projector(testTypes, { - vehicleClass: { description: '3 wheelers' }, - } as TestResultModel, []); - expect(selectorAdditional).toHaveLength(5); - }); - - it('test with vehicle subclass', () => { - const testTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleSubclass: ['test'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['lgv'], forVehicleSubclass: [VehicleSubclass.A] }, - { forVehicleType: ['motorcycle'], forVehicleSubclass: [VehicleSubclass.C] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - - const expectedTestTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - - const selector = selectTestTypesByVehicleType.projector(testTypes, { vehicleSubclass: [VehicleSubclass.L] } as TestResultModel, []); - expect(selector).toHaveLength(4); - expect(selector).toEqual(expectedTestTypes); - - const selectorAdditional = selectTestTypesByVehicleType.projector(testTypes, { vehicleSubclass: [VehicleSubclass.C] } as TestResultModel, []); - expect(selectorAdditional).toHaveLength(5); - }); - - it('test with vehicle number of wheels', () => { - const testTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleWheels: [4] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleWheels: [2] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - - const expectedTestTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleWheels: [4] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - ] as TestTypesTaxonomy; - - const selector = selectTestTypesByVehicleType.projector(testTypes, { numberOfWheelsDriven: 4 } as TestResultModel, []); - expect(selector).toHaveLength(5); - expect(selector).toEqual(expectedTestTypes); - - const selectorAdditional = selectTestTypesByVehicleType.projector(testTypes, { numberOfWheelsDriven: 2 } as TestResultModel, []); - expect(selectorAdditional).toHaveLength(5); - }); - - it('test with vehicle type, eu code, vehicle size', () => { - const testTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleSize: ['large'] }, - { forVehicleType: ['car'], forEuVehicleCategory: ['m1'], forVehicleSize: ['small'] }, - { forVehicleType: ['car'] }, - { forVehicleType: ['car', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }] }, - { - forVehicleType: ['psv', 'hgv'], - nextTestTypesOrCategories: [ - { forVehicleType: ['psv', 'hgv'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleSize: ['small'] }, - ], - }, - ] as TestTypesTaxonomy; - - const expectedTestTypes: TestTypesTaxonomy = [ - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleSize: ['small'] }, - { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }] }, - { - forVehicleType: ['psv', 'hgv'], - nextTestTypesOrCategories: [ - { forVehicleType: ['psv', 'hgv'] }, - { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleSize: ['small'] }, - ], - }, - ] as TestTypesTaxonomy; - const selector = selectTestTypesByVehicleType.projector(testTypes, { - vehicleType: 'psv', - euVehicleCategory: 'm1', - vehicleSize: 'small', - } as TestResultModel, []); - expect(selector).toHaveLength(3); - expect(selector).toEqual(expectedTestTypes); - }); - }); - - describe('sortedTestTypes', () => { - const unsortedData = [ - { id: '1', sortId: '4' }, - { id: '7', sortId: '1' }, - { id: '8' }, - { - id: '5', - sortId: '3', - nextTestTypesOrCategories: [ - { id: '39', sortId: '2' }, - { id: '40', sortId: '1' }, - ], - }, - ] as TestTypesTaxonomy; - - it('should sort test types by sortId', () => { - const expectedTestTypes: TestTypesTaxonomy = [ - { id: '8' }, - { id: '7', sortId: '1' }, - { - id: '5', - sortId: '3', - nextTestTypesOrCategories: [ - { id: '40', sortId: '1' }, - { id: '39', sortId: '2' }, - ], - }, - { id: '1', sortId: '4' }, - ] as TestTypesTaxonomy; - const sorted = sortedTestTypes.projector(unsortedData); - expect(sorted).toEqual(expectedTestTypes); - }); - }); - - describe('selectTestType', () => { - it('return the right test type', () => { - const exampleTestTypes: TestTypesTaxonomy = [ - { id: '8' }, - { id: '7', sortId: '1' }, - { - id: '5', - sortId: '3', - nextTestTypesOrCategories: [ - { id: '40', sortId: '1' }, - { id: '39', sortId: '2' }, - ], - }, - { id: '1', sortId: '4' }, - ] as TestTypesTaxonomy; - - const selector = selectTestType('39').projector(exampleTestTypes); - expect(selector).toEqual((exampleTestTypes[2] as TestTypeCategory).nextTestTypesOrCategories?.pop()); - }); - }); + describe('selectTestTypesByVehicleType', () => { + it('test with no data', () => { + const selector = selectTestTypesByVehicleType.projector([], { vehicleType: 'psv' } as TestResultModel, []); + expect(selector).toHaveLength(0); + }); + + it('test with vehicle type', () => { + const testTypes = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + + const expectedTestTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'] }, + { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }] }, + ] as TestTypesTaxonomy; + const selector = selectTestTypesByVehicleType.projector(testTypes, { vehicleType: 'psv' } as TestResultModel, []); + expect(selector).toHaveLength(3); + expect(selector).toEqual(expectedTestTypes); + }); + + it('test with techRecordHistorys', () => { + const techRecordHistorys: TechRecordSearchSchema[] = [ + { + vin: 'iii', + techRecord_statusCode: 'current', + techRecord_vehicleType: 'trl', + createdTimestamp: '2022-01-01', + systemNumber: '000', + techRecord_manufactureYear: null, + }, + ]; + const testTypes: TestTypesTaxonomy = [ + { + forVehicleType: ['trl'], + forEuVehicleCategory: ['m1'], + id: '41', + forProvisionalStatus: true, + forProvisionalStatusOnly: true, + }, + { + forVehicleType: ['trl'], + forEuVehicleCategory: ['m2'], + id: '1', + }, + { + forVehicleType: ['trl'], + forEuVehicleCategory: ['m2'], + id: '12', + forProvisionalStatus: true, + }, + { + forVehicleType: ['trl', 'hgv'], + forProvisionalStatus: true, + forProvisionalStatusOnly: true, + }, + ] as TestTypesTaxonomy; + + const expectedTestTypes: TestTypesTaxonomy = [ + { + forVehicleType: ['trl'], + forEuVehicleCategory: ['m2'], + id: '12', + forProvisionalStatus: true, + }, + { + forVehicleType: ['trl', 'hgv'], + forProvisionalStatus: true, + forProvisionalStatusOnly: true, + }, + ] as TestTypesTaxonomy; + + const additionalExpectedTestTypes: TestTypesTaxonomy = [ + { + forVehicleType: ['trl'], + forEuVehicleCategory: ['m2'], + id: '1', + }, + { + forVehicleType: ['trl'], + forEuVehicleCategory: ['m2'], + id: '12', + forProvisionalStatus: true, + }, + ] as TestTypesTaxonomy; + const selector = selectTestTypesByVehicleType.projector( + testTypes, + { + vehicleType: VehicleTypes.TRL, + statusCode: StatusCodes.PROVISIONAL, + } as TestResultModel, + techRecordHistorys + ); + expect(selector).toEqual(expectedTestTypes); + + const selectorAdditional = selectTestTypesByVehicleType.projector( + testTypes, + { + vehicleType: VehicleTypes.TRL, + statusCode: StatusCodes.CURRENT, + } as TestResultModel, + techRecordHistorys + ); + + expect(selectorAdditional).toEqual(additionalExpectedTestTypes); + }); + + it('test with eu vehicle category', () => { + const testTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + + const expectedTestTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + const selector = selectTestTypesByVehicleType.projector( + testTypes, + { euVehicleCategory: 'm1' } as TestResultModel, + [] + ); + expect(selector).toHaveLength(3); + expect(selector).toEqual(expectedTestTypes); + }); + + it('test with vehicle size', () => { + const testTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + + const expectedTestTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + const selector = selectTestTypesByVehicleType.projector( + testTypes, + { vehicleSize: 'small' } as TestResultModel, + [] + ); + expect(selector).toHaveLength(4); + expect(selector).toEqual(expectedTestTypes); + }); + + it('test with vehicle configuration', () => { + const testTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleConfiguration: ['articulated'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + + const expectedTestTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + + const selector = selectTestTypesByVehicleType.projector( + testTypes, + { vehicleConfiguration: 'rigid' } as TestResultModel, + [] + ); + expect(selector).toHaveLength(4); + expect(selector).toEqual(expectedTestTypes); + + const selectorAdditional = selectTestTypesByVehicleType.projector( + testTypes, + { vehicleConfiguration: 'articulated' } as TestResultModel, + [] + ); + expect(selectorAdditional).toHaveLength(5); + }); + + it('test with vehicle number of axles', () => { + const testTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleAxles: [2] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + + const expectedTestTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + + const selector = selectTestTypesByVehicleType.projector(testTypes, { noOfAxles: 4 } as TestResultModel, []); + expect(selector).toHaveLength(4); + expect(selector).toEqual(expectedTestTypes); + + const selectorAdditional = selectTestTypesByVehicleType.projector( + testTypes, + { noOfAxles: 2 } as TestResultModel, + [] + ); + expect(selectorAdditional).toHaveLength(5); + }); + + it('test with vehicle class using code', () => { + const testTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleClass: ['n'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + + const expectedTestTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + + const selector = selectTestTypesByVehicleType.projector( + testTypes, + { vehicleClass: { code: 's' } } as TestResultModel, + [] + ); + expect(selector).toHaveLength(4); + expect(selector).toEqual(expectedTestTypes); + + const selectorAdditional = selectTestTypesByVehicleType.projector( + testTypes, + { vehicleClass: { code: 'n' } } as TestResultModel, + [] + ); + expect(selectorAdditional).toHaveLength(5); + }); + + it('test with vehicle class using description', () => { + const testTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleClass: ['3 wheelers'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + + const expectedTestTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + + const selector = selectTestTypesByVehicleType.projector( + testTypes, + { + vehicleClass: { description: 'motorbikes up to 200cc' }, + } as TestResultModel, + [] + ); + expect(selector).toHaveLength(4); + expect(selector).toEqual(expectedTestTypes); + + const selectorAdditional = selectTestTypesByVehicleType.projector( + testTypes, + { + vehicleClass: { description: '3 wheelers' }, + } as TestResultModel, + [] + ); + expect(selectorAdditional).toHaveLength(5); + }); + + it('test with vehicle subclass', () => { + const testTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleSubclass: ['test'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, + { forVehicleType: ['car'] }, + { forVehicleType: ['lgv'], forVehicleSubclass: [VehicleSubclass.A] }, + { forVehicleType: ['motorcycle'], forVehicleSubclass: [VehicleSubclass.C] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + + const expectedTestTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + + const selector = selectTestTypesByVehicleType.projector( + testTypes, + { vehicleSubclass: [VehicleSubclass.L] } as TestResultModel, + [] + ); + expect(selector).toHaveLength(4); + expect(selector).toEqual(expectedTestTypes); + + const selectorAdditional = selectTestTypesByVehicleType.projector( + testTypes, + { vehicleSubclass: [VehicleSubclass.C] } as TestResultModel, + [] + ); + expect(selectorAdditional).toHaveLength(5); + }); + + it('test with vehicle number of wheels', () => { + const testTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleWheels: [4] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleWheels: [2] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + + const expectedTestTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleWheels: [4] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['large'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + ] as TestTypesTaxonomy; + + const selector = selectTestTypesByVehicleType.projector( + testTypes, + { numberOfWheelsDriven: 4 } as TestResultModel, + [] + ); + expect(selector).toHaveLength(5); + expect(selector).toEqual(expectedTestTypes); + + const selectorAdditional = selectTestTypesByVehicleType.projector( + testTypes, + { numberOfWheelsDriven: 2 } as TestResultModel, + [] + ); + expect(selectorAdditional).toHaveLength(5); + }); + + it('test with vehicle type, eu code, vehicle size', () => { + const testTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m2'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleSize: ['large'] }, + { forVehicleType: ['car'], forEuVehicleCategory: ['m1'], forVehicleSize: ['small'] }, + { forVehicleType: ['car'] }, + { + forVehicleType: ['car', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }, { forVehicleType: ['hgv'] }], + }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [ + { forVehicleType: ['psv', 'hgv'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleSize: ['small'] }, + ], + }, + ] as TestTypesTaxonomy; + + const expectedTestTypes: TestTypesTaxonomy = [ + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleSize: ['small'] }, + { forVehicleType: ['psv', 'hgv'], nextTestTypesOrCategories: [{ forVehicleType: ['psv', 'hgv'] }] }, + { + forVehicleType: ['psv', 'hgv'], + nextTestTypesOrCategories: [ + { forVehicleType: ['psv', 'hgv'] }, + { forVehicleType: ['psv'], forEuVehicleCategory: ['m1'], forVehicleSize: ['small'] }, + ], + }, + ] as TestTypesTaxonomy; + const selector = selectTestTypesByVehicleType.projector( + testTypes, + { + vehicleType: 'psv', + euVehicleCategory: 'm1', + vehicleSize: 'small', + } as TestResultModel, + [] + ); + expect(selector).toHaveLength(3); + expect(selector).toEqual(expectedTestTypes); + }); + }); + + describe('sortedTestTypes', () => { + const unsortedData = [ + { id: '1', sortId: '4' }, + { id: '7', sortId: '1' }, + { id: '8' }, + { + id: '5', + sortId: '3', + nextTestTypesOrCategories: [ + { id: '39', sortId: '2' }, + { id: '40', sortId: '1' }, + ], + }, + ] as TestTypesTaxonomy; + + it('should sort test types by sortId', () => { + const expectedTestTypes: TestTypesTaxonomy = [ + { id: '8' }, + { id: '7', sortId: '1' }, + { + id: '5', + sortId: '3', + nextTestTypesOrCategories: [ + { id: '40', sortId: '1' }, + { id: '39', sortId: '2' }, + ], + }, + { id: '1', sortId: '4' }, + ] as TestTypesTaxonomy; + const sorted = sortedTestTypes.projector(unsortedData); + expect(sorted).toEqual(expectedTestTypes); + }); + }); + + describe('selectTestType', () => { + it('return the right test type', () => { + const exampleTestTypes: TestTypesTaxonomy = [ + { id: '8' }, + { id: '7', sortId: '1' }, + { + id: '5', + sortId: '3', + nextTestTypesOrCategories: [ + { id: '40', sortId: '1' }, + { id: '39', sortId: '2' }, + ], + }, + { id: '1', sortId: '4' }, + ] as TestTypesTaxonomy; + + const selector = selectTestType('39').projector(exampleTestTypes); + expect(selector).toEqual((exampleTestTypes[2] as TestTypeCategory).nextTestTypesOrCategories?.pop()); + }); + }); }); diff --git a/src/app/store/test-types/selectors/test-types.selectors.ts b/src/app/store/test-types/selectors/test-types.selectors.ts index eb05f4a104..6f87e14aac 100644 --- a/src/app/store/test-types/selectors/test-types.selectors.ts +++ b/src/app/store/test-types/selectors/test-types.selectors.ts @@ -1,17 +1,15 @@ import { TestType } from '@api/test-types'; import { TestTypeCategory } from '@api/test-types/model/testTypeCategory'; import { TestTypesTaxonomy } from '@api/test-types/model/testTypesTaxonomy'; +import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; import { TestResultModel } from '@models/test-results/test-result.model'; import { StatusCodes, VehicleSubclass } from '@models/vehicle-tech-record.model'; import { createSelector } from '@ngrx/store'; -import { toEditOrNotToEdit } from '@store/test-records'; import { selectTechRecordHistory } from '@store/technical-records'; -import { TechRecordSearchSchema } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; +import { toEditOrNotToEdit } from '@store/test-records'; import { testTypesAdapter, testTypesFeatureState } from '../reducers/test-types.reducer'; -const { - selectIds, selectEntities, selectAll, selectTotal, -} = testTypesAdapter.getSelectors(); +const { selectIds, selectEntities, selectAll, selectTotal } = testTypesAdapter.getSelectors(); // select the array of ids export const selectTestTypesIds = createSelector(testTypesFeatureState, (state) => selectIds(state)); @@ -28,137 +26,168 @@ export const selectTestTypesTotal = createSelector(testTypesFeatureState, (state export const selectTestTypesLoadingState = createSelector(testTypesFeatureState, (state) => state.loading); export const selectTestTypesByVehicleType = createSelector( - selectAllTestTypes, - toEditOrNotToEdit, - selectTechRecordHistory, - (testTypes, testResult, techRecordHistory) => { - const hasCurrentRecordInHistory = techRecordHistory ? currentRecordInHistoryCheck(techRecordHistory) : false; - - if (testResult) { - return filterTestTypes(testTypes, testResult, hasCurrentRecordInHistory); - } - return []; - }, + selectAllTestTypes, + toEditOrNotToEdit, + selectTechRecordHistory, + (testTypes, testResult, techRecordHistory) => { + const hasCurrentRecordInHistory = techRecordHistory ? currentRecordInHistoryCheck(techRecordHistory) : false; + + if (testResult) { + return filterTestTypes(testTypes, testResult, hasCurrentRecordInHistory); + } + return []; + } ); export const sortedTestTypes = createSelector(selectTestTypesByVehicleType, (testTypes) => { - const sortTestTypes = (testTypesList: TestTypesTaxonomy): TestTypesTaxonomy => { - return testTypesList - .sort((a, b) => { - if (!Object.prototype.hasOwnProperty.call(b, 'sortId')) { - return 1; - } - - if (!Object.prototype.hasOwnProperty.call(a, 'sortId')) { - return -1; - } - - return parseInt((a as TestTypeCategory).sortId || '0', 10) - parseInt((b as TestTypeCategory).sortId || '0', 10); - }) - .map((testType) => { - const newTestType = { ...testType } as TestTypeCategory; - - if (Object.prototype.hasOwnProperty.call(newTestType, 'nextTestTypesOrCategories')) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - newTestType.nextTestTypesOrCategories = sortTestTypes(newTestType.nextTestTypesOrCategories!); - } - - return newTestType; - }); - }; - - return sortTestTypes(testTypes); + const sortTestTypes = (testTypesList: TestTypesTaxonomy): TestTypesTaxonomy => { + return testTypesList + .sort((a, b) => { + if (!Object.prototype.hasOwnProperty.call(b, 'sortId')) { + return 1; + } + + if (!Object.prototype.hasOwnProperty.call(a, 'sortId')) { + return -1; + } + + return ( + Number.parseInt((a as TestTypeCategory).sortId || '0', 10) - + Number.parseInt((b as TestTypeCategory).sortId || '0', 10) + ); + }) + .map((testType) => { + const newTestType = { ...testType } as TestTypeCategory; + + if (Object.prototype.hasOwnProperty.call(newTestType, 'nextTestTypesOrCategories')) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + newTestType.nextTestTypesOrCategories = sortTestTypes(newTestType.nextTestTypesOrCategories!); + } + + return newTestType; + }); + }; + + return sortTestTypes(testTypes); }); export const selectTestType = (id: string | undefined) => - createSelector(selectTestTypesByVehicleType, (testTypes): TestType | undefined => { - function findUsingId(idToSearch: string | undefined, testTypesList: TestTypesTaxonomy | undefined): TestType | undefined { - if (!testTypesList) { - return undefined; - } + createSelector(selectTestTypesByVehicleType, (testTypes): TestType | undefined => { + function findUsingId( + idToSearch: string | undefined, + testTypesList: TestTypesTaxonomy | undefined + ): TestType | undefined { + if (!testTypesList) { + return undefined; + } - // eslint-disable-next-line no-restricted-syntax - for (const testType of testTypesList) { - if (testType.id === idToSearch) { - return testType; - } + // eslint-disable-next-line no-restricted-syntax + for (const testType of testTypesList) { + if (testType.id === idToSearch) { + return testType; + } - const found = findUsingId(idToSearch, (testType as TestTypeCategory).nextTestTypesOrCategories); + const found = findUsingId(idToSearch, (testType as TestTypeCategory).nextTestTypesOrCategories); - if (found) { - return found; - } - } + if (found) { + return found; + } + } - return undefined; - } + return undefined; + } - return findUsingId(id, testTypes); - }); + return findUsingId(id, testTypes); + }); -export const getTypeOfTest = (id: string | undefined) => createSelector(selectTestType(id), (testTypes) => testTypes?.typeOfTest); +export const getTypeOfTest = (id: string | undefined) => + createSelector(selectTestType(id), (testTypes) => testTypes?.typeOfTest); function currentRecordInHistoryCheck(techRecordHistorys: TechRecordSearchSchema[]): boolean { - return techRecordHistorys.some((techRecordHis) => techRecordHis.techRecord_statusCode === 'current'); + return techRecordHistorys.some((techRecordHis) => techRecordHis.techRecord_statusCode === 'current'); } -function filterTestTypes(testTypes: TestTypesTaxonomy, testResult: TestResultModel, hasCurrentRecordInHistory: boolean): TestTypesTaxonomy { - const { - vehicleType, - statusCode, - euVehicleCategory, - vehicleSize, - vehicleConfiguration, - noOfAxles, - vehicleClass, - vehicleSubclass, - numberOfWheelsDriven, - } = testResult; - const filterFirstTestIds : string[] = ['41', '95', '82', '83', '119', '120', '65', '66', '67', '103', '104', '51']; - return ( - testTypes - .filter((testType) => !vehicleType || !testType.forVehicleType || testType.forVehicleType.includes(vehicleType)) - .filter((testType) => !vehicleType || !testType.forVehicleType || testType.forVehicleType.includes(vehicleType)) - .filter((testType) => !statusCode || statusCode !== StatusCodes.PROVISIONAL || testType.forProvisionalStatus) - .filter((testType) => !statusCode || !testType.forProvisionalStatusOnly || statusCode === StatusCodes.PROVISIONAL) - .filter((testType) => !euVehicleCategory || !testType.forEuVehicleCategory || testType.forEuVehicleCategory.includes(euVehicleCategory)) - .filter((testType) => !vehicleSize || !testType.forVehicleSize || testType.forVehicleSize.includes(vehicleSize)) - .filter( - (testType) => !vehicleConfiguration || !testType.forVehicleConfiguration || testType.forVehicleConfiguration.includes(vehicleConfiguration), - ) - .filter((testType) => !noOfAxles || !testType.forVehicleAxles || testType.forVehicleAxles.includes(noOfAxles)) - // if code AND description are null, or if either code OR description are in forVehicleClass, include in filter - .filter( - (testType) => - !vehicleClass - || !testType.forVehicleClass - || (!vehicleClass.code && !vehicleClass.description) - || (vehicleClass.code && testType.forVehicleClass.includes(vehicleClass.code as unknown as string)) - || (vehicleClass.description && testType.forVehicleClass.includes(vehicleClass.description as unknown as string)), - ) - .filter( - (testType) => - !vehicleSubclass - || !testType.forVehicleSubclass - || testType.forVehicleSubclass.some((forVehicleSubclass) => vehicleSubclass.includes(forVehicleSubclass as VehicleSubclass)), - ) - .filter((testType) => !numberOfWheelsDriven || !testType.forVehicleWheels || testType.forVehicleWheels.includes(numberOfWheelsDriven)) - // for some first tests, only show them for provisional record when there are no current records in history - .filter( - (testType) => !statusCode - || statusCode !== StatusCodes.PROVISIONAL - || !hasCurrentRecordInHistory - || !filterFirstTestIds.includes(testType.id), - ) - .map((testType: TestTypeCategory) => { - const newTestType = { ...testType } as TestTypeCategory; - - if (Object.prototype.hasOwnProperty.call(newTestType, 'nextTestTypesOrCategories')) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - newTestType.nextTestTypesOrCategories = filterTestTypes(newTestType.nextTestTypesOrCategories!, testResult, hasCurrentRecordInHistory); - } - - return newTestType; - }) - ); +function filterTestTypes( + testTypes: TestTypesTaxonomy, + testResult: TestResultModel, + hasCurrentRecordInHistory: boolean +): TestTypesTaxonomy { + const { + vehicleType, + statusCode, + euVehicleCategory, + vehicleSize, + vehicleConfiguration, + noOfAxles, + vehicleClass, + vehicleSubclass, + numberOfWheelsDriven, + } = testResult; + const filterFirstTestIds: string[] = ['41', '95', '82', '83', '119', '120', '65', '66', '67', '103', '104', '51']; + return ( + testTypes + .filter((testType) => !vehicleType || !testType.forVehicleType || testType.forVehicleType.includes(vehicleType)) + .filter((testType) => !vehicleType || !testType.forVehicleType || testType.forVehicleType.includes(vehicleType)) + .filter((testType) => !statusCode || statusCode !== StatusCodes.PROVISIONAL || testType.forProvisionalStatus) + .filter((testType) => !statusCode || !testType.forProvisionalStatusOnly || statusCode === StatusCodes.PROVISIONAL) + .filter( + (testType) => + !euVehicleCategory || + !testType.forEuVehicleCategory || + testType.forEuVehicleCategory.includes(euVehicleCategory) + ) + .filter((testType) => !vehicleSize || !testType.forVehicleSize || testType.forVehicleSize.includes(vehicleSize)) + .filter( + (testType) => + !vehicleConfiguration || + !testType.forVehicleConfiguration || + testType.forVehicleConfiguration.includes(vehicleConfiguration) + ) + .filter((testType) => !noOfAxles || !testType.forVehicleAxles || testType.forVehicleAxles.includes(noOfAxles)) + // if code AND description are null, or if either code OR description are in forVehicleClass, include in filter + .filter( + (testType) => + !vehicleClass || + !testType.forVehicleClass || + (!vehicleClass.code && !vehicleClass.description) || + (vehicleClass.code && testType.forVehicleClass.includes(vehicleClass.code as unknown as string)) || + (vehicleClass.description && testType.forVehicleClass.includes(vehicleClass.description as unknown as string)) + ) + .filter( + (testType) => + !vehicleSubclass || + !testType.forVehicleSubclass || + testType.forVehicleSubclass.some((forVehicleSubclass) => + vehicleSubclass.includes(forVehicleSubclass as VehicleSubclass) + ) + ) + .filter( + (testType) => + !numberOfWheelsDriven || + !testType.forVehicleWheels || + testType.forVehicleWheels.includes(numberOfWheelsDriven) + ) + // for some first tests, only show them for provisional record when there are no current records in history + .filter( + (testType) => + !statusCode || + statusCode !== StatusCodes.PROVISIONAL || + !hasCurrentRecordInHistory || + !filterFirstTestIds.includes(testType.id) + ) + .map((testType: TestTypeCategory) => { + const newTestType = { ...testType } as TestTypeCategory; + + if (Object.prototype.hasOwnProperty.call(newTestType, 'nextTestTypesOrCategories')) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + newTestType.nextTestTypesOrCategories = filterTestTypes( + newTestType.nextTestTypesOrCategories!, + testResult, + hasCurrentRecordInHistory + ); + } + + return newTestType; + }) + ); } diff --git a/src/app/store/test-types/test-types.module.ts b/src/app/store/test-types/test-types.module.ts index d194cd42c7..c015d75ad5 100644 --- a/src/app/store/test-types/test-types.module.ts +++ b/src/app/store/test-types/test-types.module.ts @@ -6,7 +6,11 @@ import { TestTypeEffects } from './effects/test-types.effects'; import { STORE_FEATURE_TEST_TYPES_KEY, testTypesReducer } from './reducers/test-types.reducer'; @NgModule({ - declarations: [], - imports: [CommonModule, StoreModule.forFeature(STORE_FEATURE_TEST_TYPES_KEY, testTypesReducer), EffectsModule.forFeature([TestTypeEffects])], + declarations: [], + imports: [ + CommonModule, + StoreModule.forFeature(STORE_FEATURE_TEST_TYPES_KEY, testTypesReducer), + EffectsModule.forFeature([TestTypeEffects]), + ], }) export class TestTypesStateModule {} diff --git a/src/app/store/user/user-service.actions.ts b/src/app/store/user/user-service.actions.ts index 90d3746849..7f8e0f6f6d 100644 --- a/src/app/store/user/user-service.actions.ts +++ b/src/app/store/user/user-service.actions.ts @@ -1,4 +1,7 @@ import { createAction, props } from '@ngrx/store'; -export const Login = createAction('[User Service] Login', props<{ name: string; userEmail: string; oid: string; roles: string[] }>()); +export const Login = createAction( + '[User Service] Login', + props<{ name: string; userEmail: string; oid: string; roles: string[] }>() +); export const Logout = createAction('[User Service] Logout'); diff --git a/src/app/store/user/user-service.reducer.ts b/src/app/store/user/user-service.reducer.ts index bad0c9a192..fda8dd90f7 100644 --- a/src/app/store/user/user-service.reducer.ts +++ b/src/app/store/user/user-service.reducer.ts @@ -1,24 +1,22 @@ import { Roles } from '@models/roles.enum'; -import { - createFeatureSelector, createReducer, createSelector, on, -} from '@ngrx/store'; +import { createFeatureSelector, createReducer, createSelector, on } from '@ngrx/store'; import { environment } from '../../../environments/environment'; import * as UserServiceActions from './user-service.actions'; export const STORE_FEATURE_USER_KEY = 'user'; export interface UserServiceState { - name: string; - userEmail: string; - oid: string; - roles: string[] | null; + name: string; + userEmail: string; + oid: string; + roles: string[] | null; } export const initialState: UserServiceState = { - name: '(Not logged in)', - userEmail: '', - oid: '', - roles: null, + name: '(Not logged in)', + userEmail: '', + oid: '', + roles: null, }; const getUserState = createFeatureSelector(STORE_FEATURE_USER_KEY); @@ -30,16 +28,28 @@ export const roles = createSelector(getUserState, (state) => state.roles); export const user = createSelector(getUserState, (state) => state); export const userServiceReducer = createReducer( - initialState, - on(UserServiceActions.Login, (state, { - // eslint-disable-next-line @typescript-eslint/no-shadow - name, userEmail, oid, roles, - }) => ({ - name, userEmail, oid, roles: getRoles(roles), - })), - on(UserServiceActions.Logout, () => initialState), + initialState, + on( + UserServiceActions.Login, + ( + state, + { + // eslint-disable-next-line @typescript-eslint/no-shadow + name, + userEmail, + oid, + roles, + } + ) => ({ + name, + userEmail, + oid, + roles: getRoles(roles), + }) + ), + on(UserServiceActions.Logout, () => initialState) ); function getRoles(rolesArray: string[]): string[] { - return environment.RemoveAADFullAccessRole ? rolesArray.filter((role) => role !== Roles.Admin) : rolesArray; + return environment.RemoveAADFullAccessRole ? rolesArray.filter((role) => role !== Roles.Admin) : rolesArray; } diff --git a/src/app/store/user/user-state.module.ts b/src/app/store/user/user-state.module.ts index 063572eca1..b0a7351d32 100644 --- a/src/app/store/user/user-state.module.ts +++ b/src/app/store/user/user-state.module.ts @@ -5,14 +5,14 @@ import { localStorageSync } from 'ngrx-store-localstorage'; import { STORE_FEATURE_USER_KEY, userServiceReducer } from './user-service.reducer'; export function localStorageSyncReducer(reducer: ActionReducer): ActionReducer { - return localStorageSync({ keys: ['name', 'userEmail', 'oid', 'roles'], rehydrate: true })(reducer); + return localStorageSync({ keys: ['name', 'userEmail', 'oid', 'roles'], rehydrate: true })(reducer); } // eslint-disable-next-line @typescript-eslint/no-explicit-any const metaReducers: Array> = [localStorageSyncReducer]; @NgModule({ - declarations: [], - imports: [CommonModule, StoreModule.forFeature(STORE_FEATURE_USER_KEY, userServiceReducer, { metaReducers })], + declarations: [], + imports: [CommonModule, StoreModule.forFeature(STORE_FEATURE_USER_KEY, userServiceReducer, { metaReducers })], }) export class UserStateModule {} diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index 71522599d3..05f2cadbb7 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -1,16 +1,16 @@ export const environment = { - production: true, - TARGET_ENV: 'prod', - RemoveAADFullAccessRole: true, - EnableDevTools: false, - VTM_CLIENT_ID: '', - VTM_AUTHORITY_ID: '', - VTM_REDIRECT_URI: '/', - VTM_API_URI: '', - VTM_API_CLIENT_ID: '', - DOCUMENT_RETRIEVAL_API_KEY: '', - FEEDBACK_URI: '', - SENTRY_DSN: '', - VTM_GTM_CONTAINER_ID: '', - VTM_GTM_MEASUREMENT_ID: '', + production: true, + TARGET_ENV: 'prod', + RemoveAADFullAccessRole: true, + EnableDevTools: false, + VTM_CLIENT_ID: '', + VTM_AUTHORITY_ID: '', + VTM_REDIRECT_URI: '/', + VTM_API_URI: '', + VTM_API_CLIENT_ID: '', + DOCUMENT_RETRIEVAL_API_KEY: '', + FEEDBACK_URI: '', + SENTRY_DSN: '', + VTM_GTM_CONTAINER_ID: '', + VTM_GTM_MEASUREMENT_ID: '', }; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index a0c7c4d134..ecc6dccebd 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -3,20 +3,20 @@ // The list of file replacements can be found in `angular.json`. export const environment = { - production: false, - TARGET_ENV: 'dev', - RemoveAADFullAccessRole: true, - EnableDevTools: true, - VTM_CLIENT_ID: '', - VTM_AUTHORITY_ID: '', - VTM_REDIRECT_URI: '/', - VTM_API_URI: '', - VTM_API_CLIENT_ID: '', - DOCUMENT_RETRIEVAL_API_KEY: '', - FEEDBACK_URI: '', - SENTRY_DSN: '', - VTM_GTM_CONTAINER_ID: '', - VTM_GTM_MEASUREMENT_ID: '', + production: false, + TARGET_ENV: 'dev', + RemoveAADFullAccessRole: true, + EnableDevTools: true, + VTM_CLIENT_ID: '', + VTM_AUTHORITY_ID: '', + VTM_REDIRECT_URI: '/', + VTM_API_URI: '', + VTM_API_CLIENT_ID: '', + DOCUMENT_RETRIEVAL_API_KEY: '', + FEEDBACK_URI: '', + SENTRY_DSN: '', + VTM_GTM_CONTAINER_ID: '', + VTM_GTM_MEASUREMENT_ID: '', }; /* diff --git a/src/main.ts b/src/main.ts index d9a2e7e4a5..9bd6fb69f4 100644 --- a/src/main.ts +++ b/src/main.ts @@ -5,9 +5,9 @@ import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; if (environment.production) { - enableProdMode(); + enableProdMode(); } platformBrowserDynamic() - .bootstrapModule(AppModule) - .catch((err) => console.error(err)); + .bootstrapModule(AppModule) + .catch((err) => console.error(err)); diff --git a/src/mocks/custom-defect.mock.ts b/src/mocks/custom-defect.mock.ts index 31ed641205..6eeb0d069f 100644 --- a/src/mocks/custom-defect.mock.ts +++ b/src/mocks/custom-defect.mock.ts @@ -1,14 +1,14 @@ import { CustomDefects } from '@models/test-types/test-type.model'; export const createMockCustomDefect = (params: Partial = {}): CustomDefects => ({ - referenceNumber: 'referenceNumber', - defectName: 'defectName', - defectNotes: 'defectNotes', - ...params, + referenceNumber: 'referenceNumber', + defectName: 'defectName', + defectNotes: 'defectNotes', + ...params, }); export const createMockAdditionalDefect = (params: Partial = {}): CustomDefects => ({ - defectName: 'defectName', - defectNotes: 'defectNotes', - ...params, + defectName: 'defectName', + defectNotes: 'defectNotes', + ...params, }); diff --git a/src/mocks/google-analytics-service.mock.ts b/src/mocks/google-analytics-service.mock.ts index 3cb76586d4..1f44d6f3f8 100644 --- a/src/mocks/google-analytics-service.mock.ts +++ b/src/mocks/google-analytics-service.mock.ts @@ -1,5 +1,5 @@ export class GoogleAnalyticsServiceMock { - checkForId() {} - pushTag() {} - addGtmToDom() {} + checkForId() {} + pushTag() {} + addGtmToDom() {} } diff --git a/src/mocks/hgv-record.mock.ts b/src/mocks/hgv-record.mock.ts index daab4cdc4a..2c1361088d 100644 --- a/src/mocks/hgv-record.mock.ts +++ b/src/mocks/hgv-record.mock.ts @@ -6,60 +6,60 @@ import { BodyTypeDescription } from '@models/body-type-enum'; import { FuelTypes, StatusCodes } from '../app/models/vehicle-tech-record.model'; export const createMockHgv = (systemNumber: number): TechRecordType<'hgv'> => ({ - systemNumber: 'HGV', - vin: `XMGDE03FS0H0${12344 + systemNumber + 1}`, - primaryVrm: `KP${String(systemNumber + 1).padStart(2, '0')} ABC`, - secondaryVrms: null, - createdTimestamp: new Date().toISOString(), - techRecord_createdAt: new Date().toISOString(), - techRecord_createdByName: 'Nathan', - techRecord_statusCode: StatusCodes.CURRENT, - techRecord_vehicleType: 'hgv', - techRecord_regnDate: '1234', - techRecord_manufactureYear: 2022, - techRecord_noOfAxles: 2, - techRecord_brakes_dtpNumber: '1234', - techRecord_speedLimiterMrk: true, - techRecord_tachoExemptMrk: true, - techRecord_euroStandard: '123', - techRecord_roadFriendly: true, - techRecord_fuelPropulsionSystem: FuelTypes.HYBRID, - techRecord_drawbarCouplingFitted: true, - techRecord_vehicleClass_description: 'heavy goods vehicle', - techRecord_vehicleClass_code: 'v', - techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, - techRecord_offRoad: true, - techRecord_euVehicleCategory: EUVehicleCategory.N1, - techRecord_emissionsLimit: 1234, - techRecord_departmentalVehicleMarker: true, - techRecord_reasonForCreation: 'Brake Failure', - techRecord_approvalType: ApprovalType.ECSSTA, - techRecord_approvalTypeNumber: 'approval123', - techRecord_axles: undefined, - techRecord_ntaNumber: 'nta789', - techRecord_variantNumber: 'variant123456', - techRecord_variantVersionNumber: 'variantversion123456', - techRecord_dimensions_length: 1, - techRecord_dimensions_width: 2, - techRecord_frontAxleToRearAxle: 3, - techRecord_frontVehicleTo5thWheelCouplingMin: 5, - techRecord_frontVehicleTo5thWheelCouplingMax: 6, - techRecord_frontAxleTo5thWheelMin: 7, - techRecord_frontAxleTo5thWheelMax: 8, - techRecord_plates: undefined, - techRecord_make: '1234', - techRecord_model: '1234', - techRecord_bodyType_description: BodyTypeDescription.OTHER, - techRecord_functionCode: '1', - techRecord_conversionRefNo: '1234', - techRecord_grossGbWeight: 2, - techRecord_grossEecWeight: 4, - techRecord_grossDesignWeight: 3, - techRecord_trainGbWeight: 3, - techRecord_trainEecWeight: 3, - techRecord_trainDesignWeight: 7, - partialVin: 'vin', - techRecord_createdById: '2', - techRecord_numberOfWheelsDriven: 4, - techRecord_recordCompleteness: 'testable', + systemNumber: 'HGV', + vin: `XMGDE03FS0H0${12344 + systemNumber + 1}`, + primaryVrm: `KP${String(systemNumber + 1).padStart(2, '0')} ABC`, + secondaryVrms: null, + createdTimestamp: new Date().toISOString(), + techRecord_createdAt: new Date().toISOString(), + techRecord_createdByName: 'Nathan', + techRecord_statusCode: StatusCodes.CURRENT, + techRecord_vehicleType: 'hgv', + techRecord_regnDate: '1234', + techRecord_manufactureYear: 2022, + techRecord_noOfAxles: 2, + techRecord_brakes_dtpNumber: '1234', + techRecord_speedLimiterMrk: true, + techRecord_tachoExemptMrk: true, + techRecord_euroStandard: '123', + techRecord_roadFriendly: true, + techRecord_fuelPropulsionSystem: FuelTypes.HYBRID, + techRecord_drawbarCouplingFitted: true, + techRecord_vehicleClass_description: 'heavy goods vehicle', + techRecord_vehicleClass_code: 'v', + techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, + techRecord_offRoad: true, + techRecord_euVehicleCategory: EUVehicleCategory.N1, + techRecord_emissionsLimit: 1234, + techRecord_departmentalVehicleMarker: true, + techRecord_reasonForCreation: 'Brake Failure', + techRecord_approvalType: ApprovalType.ECSSTA, + techRecord_approvalTypeNumber: 'approval123', + techRecord_axles: undefined, + techRecord_ntaNumber: 'nta789', + techRecord_variantNumber: 'variant123456', + techRecord_variantVersionNumber: 'variantversion123456', + techRecord_dimensions_length: 1, + techRecord_dimensions_width: 2, + techRecord_frontAxleToRearAxle: 3, + techRecord_frontVehicleTo5thWheelCouplingMin: 5, + techRecord_frontVehicleTo5thWheelCouplingMax: 6, + techRecord_frontAxleTo5thWheelMin: 7, + techRecord_frontAxleTo5thWheelMax: 8, + techRecord_plates: undefined, + techRecord_make: '1234', + techRecord_model: '1234', + techRecord_bodyType_description: BodyTypeDescription.OTHER, + techRecord_functionCode: '1', + techRecord_conversionRefNo: '1234', + techRecord_grossGbWeight: 2, + techRecord_grossEecWeight: 4, + techRecord_grossDesignWeight: 3, + techRecord_trainGbWeight: 3, + techRecord_trainEecWeight: 3, + techRecord_trainDesignWeight: 7, + partialVin: 'vin', + techRecord_createdById: '2', + techRecord_numberOfWheelsDriven: 4, + techRecord_recordCompleteness: 'testable', }); diff --git a/src/mocks/lgv-record.mock.ts b/src/mocks/lgv-record.mock.ts index 74a48b3a03..1be33bb8d7 100644 --- a/src/mocks/lgv-record.mock.ts +++ b/src/mocks/lgv-record.mock.ts @@ -4,19 +4,19 @@ import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/ import { StatusCodes } from '@models/vehicle-tech-record.model'; export const createMockLgv = (systemNumber: number): TechRecordType<'lgv'> => ({ - systemNumber: 'LGV', - vin: `XMGDE04FS0H0${12344 + systemNumber + 1}`, - secondaryVrms: null, - createdTimestamp: new Date().toISOString(), - techRecord_createdAt: new Date().toISOString(), - techRecord_createdByName: 'Nathan', - techRecord_statusCode: StatusCodes.CURRENT, - techRecord_vehicleType: 'lgv', - techRecord_regnDate: '1234', - techRecord_manufactureYear: 2022, - techRecord_noOfAxles: 2, - techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, - techRecord_euVehicleCategory: EUVehicleCategory.N1, - techRecord_reasonForCreation: 'Brake Failure', - techRecord_createdById: '0', + systemNumber: 'LGV', + vin: `XMGDE04FS0H0${12344 + systemNumber + 1}`, + secondaryVrms: null, + createdTimestamp: new Date().toISOString(), + techRecord_createdAt: new Date().toISOString(), + techRecord_createdByName: 'Nathan', + techRecord_statusCode: StatusCodes.CURRENT, + techRecord_vehicleType: 'lgv', + techRecord_regnDate: '1234', + techRecord_manufactureYear: 2022, + techRecord_noOfAxles: 2, + techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, + techRecord_euVehicleCategory: EUVehicleCategory.N1, + techRecord_reasonForCreation: 'Brake Failure', + techRecord_createdById: '0', }); diff --git a/src/mocks/mock-defects.ts b/src/mocks/mock-defects.ts index 5dca877f7f..15e41b07b0 100644 --- a/src/mocks/mock-defects.ts +++ b/src/mocks/mock-defects.ts @@ -3,27 +3,27 @@ import { DeficiencyCategoryEnum } from '../app/models/test-results/test-result-d export const mockDefectList = (numberOfDefects = 1) => new Array(numberOfDefects).fill(0).map((_, i) => mockDefect(i)); export const mockDefect = (i = 0) => ({ - deficiencyRef: `DeficiencyRef${i}`, - deficiencyCategory: DeficiencyCategoryEnum.Dangerous, - deficiencyId: 'deficiency ID', - deficiencySubId: 'deficiency sub ID', - deficiencyText: 'deficiency text', - imDescription: 'IM description', - imNumber: 34, - itemDescription: 'item description', - itemNumber: 6, - prohibitionIssued: false, - prs: false, - stdForProhibition: false, - additionalInformation: mockDefectAdditionalInformation(i), + deficiencyRef: `DeficiencyRef${i}`, + deficiencyCategory: DeficiencyCategoryEnum.Dangerous, + deficiencyId: 'deficiency ID', + deficiencySubId: 'deficiency sub ID', + deficiencyText: 'deficiency text', + imDescription: 'IM description', + imNumber: 34, + itemDescription: 'item description', + itemNumber: 6, + prohibitionIssued: false, + prs: false, + stdForProhibition: false, + additionalInformation: mockDefectAdditionalInformation(i), }); export const mockDefectAdditionalInformation = (i = 0) => ({ - location: mockDefectLocation(i), - notes: 'Defect notes', + location: mockDefectLocation(i), + notes: 'Defect notes', }); export const mockDefectLocation = (i = 0) => ({ - seatNumber: i + 1, - rowNumber: i + 1, + seatNumber: i + 1, + rowNumber: i + 1, }); diff --git a/src/mocks/mock-test-result.ts b/src/mocks/mock-test-result.ts index e7fd0e4da5..36b87e602c 100644 --- a/src/mocks/mock-test-result.ts +++ b/src/mocks/mock-test-result.ts @@ -6,88 +6,92 @@ import { OdometerReadingUnits } from '@models/test-types/odometer-unit.enum'; import { VehicleTypes } from '../app/models/vehicle-tech-record.model'; import { createMockTestType } from './test-type.mock'; -export const mockTestResult = (i = 0, vehicleType: VehicleTypes = VehicleTypes.PSV, systemNumber = 'SYS0001'): TestResultModel => ({ - testResultId: `TestResultId${String(i + 1).padStart(4, '0')}`, - systemNumber, - vin: 'XMGDE02FS0H012345', - vrm: 'KP02ABC', - createdAt: new Date().toISOString(), - testStartTimestamp: new Date().toISOString(), - testTypes: [createMockTestType(), createMockTestType()], - trailerId: `C${String(i + 1).padStart(5, '0')}`, - countryOfRegistration: 'gb', - euVehicleCategory: EUVehicleCategory.M3, - odometerReading: 100, - odometerReadingUnits: OdometerReadingUnits.KILOMETRES, - reasonForCreation: 'mock test result data', - preparerName: 'Durrell Truck & Van Centre', - preparerId: 'CM2254', - testStationName: 'Abshire-Kub', - testStationPNumber: 'P12346', - testStationType: TestStationType.ATF, - testerName: 'John Smith', - testerEmailAddress: 'john.smith@dvsa.gov.uk', - testStatus: TestResultStatus.SUBMITTED, - vehicleType, - testVersion: 'Current', - createdByName: 'Jane Doe', - testHistory: [ - mockTestResultArchived(0, `TestResultId${String(i + 1).padStart(4, '0')}`, vehicleType, systemNumber), - mockTestResultArchived(1, `TestResultId${String(i + 1).padStart(4, '0')}`, vehicleType, systemNumber), - mockTestResultArchived(2, `TestResultId${String(i + 1).padStart(4, '0')}`, vehicleType, systemNumber), - mockTestResultArchived(3, `TestResultId${String(i + 1).padStart(4, '0')}`, vehicleType, systemNumber), - mockTestResultArchived(4, `TestResultId${String(i + 1).padStart(4, '0')}`, vehicleType, systemNumber), - ], - testEndTimestamp: new Date().toISOString(), - testerStaffId: 'testerStaffId', +export const mockTestResult = ( + i = 0, + vehicleType: VehicleTypes = VehicleTypes.PSV, + systemNumber = 'SYS0001' +): TestResultModel => ({ + testResultId: `TestResultId${String(i + 1).padStart(4, '0')}`, + systemNumber, + vin: 'XMGDE02FS0H012345', + vrm: 'KP02ABC', + createdAt: new Date().toISOString(), + testStartTimestamp: new Date().toISOString(), + testTypes: [createMockTestType(), createMockTestType()], + trailerId: `C${String(i + 1).padStart(5, '0')}`, + countryOfRegistration: 'gb', + euVehicleCategory: EUVehicleCategory.M3, + odometerReading: 100, + odometerReadingUnits: OdometerReadingUnits.KILOMETRES, + reasonForCreation: 'mock test result data', + preparerName: 'Durrell Truck & Van Centre', + preparerId: 'CM2254', + testStationName: 'Abshire-Kub', + testStationPNumber: 'P12346', + testStationType: TestStationType.ATF, + testerName: 'John Smith', + testerEmailAddress: 'john.smith@dvsa.gov.uk', + testStatus: TestResultStatus.SUBMITTED, + vehicleType, + testVersion: 'Current', + createdByName: 'Jane Doe', + testHistory: [ + mockTestResultArchived(0, `TestResultId${String(i + 1).padStart(4, '0')}`, vehicleType, systemNumber), + mockTestResultArchived(1, `TestResultId${String(i + 1).padStart(4, '0')}`, vehicleType, systemNumber), + mockTestResultArchived(2, `TestResultId${String(i + 1).padStart(4, '0')}`, vehicleType, systemNumber), + mockTestResultArchived(3, `TestResultId${String(i + 1).padStart(4, '0')}`, vehicleType, systemNumber), + mockTestResultArchived(4, `TestResultId${String(i + 1).padStart(4, '0')}`, vehicleType, systemNumber), + ], + testEndTimestamp: new Date().toISOString(), + testerStaffId: 'testerStaffId', }); export const mockTestResultArchived = ( - i = 0, - testResultId = 'TestResultId0001', - vehicleType: VehicleTypes = VehicleTypes.PSV, - systemNumber = 'SYS0001', + i = 0, + testResultId = 'TestResultId0001', + vehicleType: VehicleTypes = VehicleTypes.PSV, + systemNumber = 'SYS0001' ) => { - const date = new Date('2022-01-02'); - const createdAt = date.setDate(date.getDate() - (i + 1)); - const testResult: TestResultModel = { - testResultId, - createdAt: new Date(createdAt).toISOString(), - systemNumber, - vin: 'XMGDE02FS0H012345', - vrm: 'KP02 ABC', - testStartTimestamp: new Date().toISOString(), - testTypes: [createMockTestType(), createMockTestType()], - testEndTimestamp: new Date().toISOString(), - testerStaffId: 'testerStaffId', - createdByName: `Person ${i}`, - trailerId: `C${String(i + 1).padStart(5, '0')}`, - countryOfRegistration: 'gb', - euVehicleCategory: EUVehicleCategory.M3, - odometerReading: 100, - odometerReadingUnits: OdometerReadingUnits.KILOMETRES, - reasonForCreation: `reason ${i}`, - preparerName: 'Durrell Truck & Van Centre', - preparerId: 'CM2254', - testStationName: 'Abshire-Kub', - testStationPNumber: 'P12346', - testStationType: TestStationType.ATF, - testerName: `tester ${i}`, - testerEmailAddress: 'john.smith@dvsa.gov.uk', - testVersion: 'Archived', - vehicleType, - }; + const date = new Date('2022-01-02'); + const createdAt = date.setDate(date.getDate() - (i + 1)); + const testResult: TestResultModel = { + testResultId, + createdAt: new Date(createdAt).toISOString(), + systemNumber, + vin: 'XMGDE02FS0H012345', + vrm: 'KP02 ABC', + testStartTimestamp: new Date().toISOString(), + testTypes: [createMockTestType(), createMockTestType()], + testEndTimestamp: new Date().toISOString(), + testerStaffId: 'testerStaffId', + createdByName: `Person ${i}`, + trailerId: `C${String(i + 1).padStart(5, '0')}`, + countryOfRegistration: 'gb', + euVehicleCategory: EUVehicleCategory.M3, + odometerReading: 100, + odometerReadingUnits: OdometerReadingUnits.KILOMETRES, + reasonForCreation: `reason ${i}`, + preparerName: 'Durrell Truck & Van Centre', + preparerId: 'CM2254', + testStationName: 'Abshire-Kub', + testStationPNumber: 'P12346', + testStationType: TestStationType.ATF, + testerName: `tester ${i}`, + testerEmailAddress: 'john.smith@dvsa.gov.uk', + testVersion: 'Archived', + vehicleType, + }; - return testResult; + return testResult; }; export const mockTestResultList = (items = 1, systemNumber = 'PSV') => { - switch (systemNumber.substring(0, 3)) { - case 'HGV': - return new Array(items).fill(0).map((_, i) => mockTestResult(i, VehicleTypes.HGV, systemNumber)); - case 'TRL': - return new Array(items).fill(0).map((_, i) => mockTestResult(i, VehicleTypes.TRL, systemNumber)); - default: - return new Array(items).fill(0).map((_, i) => mockTestResult(i)); - } + switch (systemNumber.substring(0, 3)) { + case 'HGV': + return new Array(items).fill(0).map((_, i) => mockTestResult(i, VehicleTypes.HGV, systemNumber)); + case 'TRL': + return new Array(items).fill(0).map((_, i) => mockTestResult(i, VehicleTypes.TRL, systemNumber)); + default: + return new Array(items).fill(0).map((_, i) => mockTestResult(i)); + } }; diff --git a/src/mocks/mock-vehicle-technical-record.mock.ts b/src/mocks/mock-vehicle-technical-record.mock.ts index acef5f0569..ebba747fbc 100644 --- a/src/mocks/mock-vehicle-technical-record.mock.ts +++ b/src/mocks/mock-vehicle-technical-record.mock.ts @@ -1,15 +1,15 @@ import { VehicleType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/get/search'; -import { createMockPsv } from './psv-record.mock'; import { createMockHgv } from './hgv-record.mock'; +import { createMockPsv } from './psv-record.mock'; import { createMockTrl } from './trl-record.mock'; export const mockVehicleTechnicalRecord = (vehicleType: VehicleType = 'psv', systemNumber = 0) => { - switch (vehicleType) { - case 'hgv': - return createMockHgv(systemNumber); - case 'trl': - return createMockTrl(systemNumber); - default: - return createMockPsv(systemNumber); - } + switch (vehicleType) { + case 'hgv': + return createMockHgv(systemNumber); + case 'trl': + return createMockTrl(systemNumber); + default: + return createMockPsv(systemNumber); + } }; diff --git a/src/mocks/psv-record.mock.ts b/src/mocks/psv-record.mock.ts index dc9676371c..af92110e8f 100644 --- a/src/mocks/psv-record.mock.ts +++ b/src/mocks/psv-record.mock.ts @@ -4,174 +4,170 @@ import { VehicleClassDescription } from '@dvsa/cvs-type-definitions/types/v3/tec import { VehicleConfiguration } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleConfigurationHgvPsv.enum.js'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-vehicle-type'; import { BodyTypeDescription } from '@models/body-type-enum'; -import { - Axles, - FuelTypes, Retarders, StatusCodes, - VehicleSizes, -} from '../app/models/vehicle-tech-record.model'; +import { Axles, FuelTypes, Retarders, StatusCodes, VehicleSizes } from '../app/models/vehicle-tech-record.model'; export const createMockPsv = (systemNumber: number): TechRecordType<'psv'> => ({ - systemNumber: 'PSV', - vin: `XMGDE02FS0H0${12344 + systemNumber + 1}`, - primaryVrm: 'KP01ABC', - secondaryVrms: undefined, - createdTimestamp: 'now', - techRecord_createdAt: new Date().toISOString(), - techRecord_createdByName: 'Nathan', - techRecord_statusCode: StatusCodes.PROVISIONAL, - techRecord_vehicleType: 'psv', - techRecord_regnDate: '1234', - techRecord_manufactureYear: 2022, - techRecord_axles: axles as unknown as Axles<'psv'>, - techRecord_noOfAxles: 2, - techRecord_brakes_dtpNumber: '1234', - techRecord_brakes_brakeCode: '1234', - techRecord_brakes_dataTrBrakeOne: '12', - techRecord_brakes_dataTrBrakeTwo: '34', - techRecord_brakes_dataTrBrakeThree: '56', - techRecord_brakes_retarderBrakeOne: Retarders.ELECTRIC, - techRecord_brakes_retarderBrakeTwo: Retarders.ELECTRIC, - techRecord_brakes_brakeCodeOriginal: 'original', - techRecord_brakes_brakeForceWheelsNotLocked_parkingBrakeForceA: 1234, - techRecord_brakes_brakeForceWheelsNotLocked_secondaryBrakeForceA: 1234, - techRecord_brakes_brakeForceWheelsNotLocked_serviceBrakeForceA: 1234, - techRecord_brakes_brakeForceWheelsUpToHalfLocked_parkingBrakeForceB: 1234, - techRecord_brakes_brakeForceWheelsUpToHalfLocked_secondaryBrakeForceB: 1234, - techRecord_brakes_brakeForceWheelsUpToHalfLocked_serviceBrakeForceB: 1234, - techRecord_speedLimiterMrk: true, - techRecord_speedRestriction: 54, - techRecord_tachoExemptMrk: true, - techRecord_euroStandard: 'Euro 4', - techRecord_fuelPropulsionSystem: FuelTypes.HYBRID, + systemNumber: 'PSV', + vin: `XMGDE02FS0H0${12344 + systemNumber + 1}`, + primaryVrm: 'KP01ABC', + secondaryVrms: undefined, + createdTimestamp: 'now', + techRecord_createdAt: new Date().toISOString(), + techRecord_createdByName: 'Nathan', + techRecord_statusCode: StatusCodes.PROVISIONAL, + techRecord_vehicleType: 'psv', + techRecord_regnDate: '1234', + techRecord_manufactureYear: 2022, + techRecord_axles: axles as unknown as Axles<'psv'>, + techRecord_noOfAxles: 2, + techRecord_brakes_dtpNumber: '1234', + techRecord_brakes_brakeCode: '1234', + techRecord_brakes_dataTrBrakeOne: '12', + techRecord_brakes_dataTrBrakeTwo: '34', + techRecord_brakes_dataTrBrakeThree: '56', + techRecord_brakes_retarderBrakeOne: Retarders.ELECTRIC, + techRecord_brakes_retarderBrakeTwo: Retarders.ELECTRIC, + techRecord_brakes_brakeCodeOriginal: 'original', + techRecord_brakes_brakeForceWheelsNotLocked_parkingBrakeForceA: 1234, + techRecord_brakes_brakeForceWheelsNotLocked_secondaryBrakeForceA: 1234, + techRecord_brakes_brakeForceWheelsNotLocked_serviceBrakeForceA: 1234, + techRecord_brakes_brakeForceWheelsUpToHalfLocked_parkingBrakeForceB: 1234, + techRecord_brakes_brakeForceWheelsUpToHalfLocked_secondaryBrakeForceB: 1234, + techRecord_brakes_brakeForceWheelsUpToHalfLocked_serviceBrakeForceB: 1234, + techRecord_speedLimiterMrk: true, + techRecord_speedRestriction: 54, + techRecord_tachoExemptMrk: true, + techRecord_euroStandard: 'Euro 4', + techRecord_fuelPropulsionSystem: FuelTypes.HYBRID, - techRecord_vehicleClass_description: VehicleClassDescription.LARGE_PSV, - techRecord_vehicleClass_code: '1', - techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, - techRecord_euVehicleCategory: EUVehicleCategory.M1, - techRecord_emissionsLimit: 1234, - techRecord_seatsLowerDeck: 1234, - techRecord_seatsUpperDeck: 1234, - techRecord_standingCapacity: 1234, - techRecord_vehicleSize: VehicleSizes.SMALL, - techRecord_numberOfSeatbelts: '1234', - techRecord_seatbeltInstallationApprovalDate: '1234', - techRecord_departmentalVehicleMarker: true, + techRecord_vehicleClass_description: VehicleClassDescription.LARGE_PSV, + techRecord_vehicleClass_code: '1', + techRecord_vehicleConfiguration: VehicleConfiguration.ARTICULATED, + techRecord_euVehicleCategory: EUVehicleCategory.M1, + techRecord_emissionsLimit: 1234, + techRecord_seatsLowerDeck: 1234, + techRecord_seatsUpperDeck: 1234, + techRecord_standingCapacity: 1234, + techRecord_vehicleSize: VehicleSizes.SMALL, + techRecord_numberOfSeatbelts: '1234', + techRecord_seatbeltInstallationApprovalDate: '1234', + techRecord_departmentalVehicleMarker: true, - techRecord_dimensions_height: 30000, - techRecord_dimensions_length: 25000, - techRecord_dimensions_width: 10000, - techRecord_frontAxleToRearAxle: 5000, - techRecord_approvalType: ApprovalType.ECSSTA, - techRecord_approvalTypeNumber: 'approval123', - techRecord_ntaNumber: 'nta789', - techRecord_coifSerialNumber: 'coifSerial123456', - techRecord_coifCertifierName: 'coifName', - techRecord_coifDate: new Date().toISOString(), - techRecord_variantNumber: 'variant123456', - techRecord_variantVersionNumber: 'variantversion123456', + techRecord_dimensions_height: 30000, + techRecord_dimensions_length: 25000, + techRecord_dimensions_width: 10000, + techRecord_frontAxleToRearAxle: 5000, + techRecord_approvalType: ApprovalType.ECSSTA, + techRecord_approvalTypeNumber: 'approval123', + techRecord_ntaNumber: 'nta789', + techRecord_coifSerialNumber: 'coifSerial123456', + techRecord_coifCertifierName: 'coifName', + techRecord_coifDate: new Date().toISOString(), + techRecord_variantNumber: 'variant123456', + techRecord_variantVersionNumber: 'variantversion123456', - techRecord_applicantDetails_name: 'Test', - techRecord_applicantDetails_address1: 'address1', - techRecord_applicantDetails_address2: 'address2', - techRecord_applicantDetails_postTown: 'town', - techRecord_applicantDetails_address3: 'address3', - techRecord_applicantDetails_postCode: 'postCode', - techRecord_applicantDetails_telephoneNumber: '0121', - techRecord_applicantDetails_emailAddress: 'test@email.com', + techRecord_applicantDetails_name: 'Test', + techRecord_applicantDetails_address1: 'address1', + techRecord_applicantDetails_address2: 'address2', + techRecord_applicantDetails_postTown: 'town', + techRecord_applicantDetails_address3: 'address3', + techRecord_applicantDetails_postCode: 'postCode', + techRecord_applicantDetails_telephoneNumber: '0121', + techRecord_applicantDetails_emailAddress: 'test@email.com', - // techRecord_microfilmDocumentType: 'AAT - Trailer Annual Test', - // techRecord_microfilmRollNumber: 'nb123456', - // techRecord_microfilmSerialNumber: 'ser123456', - techRecord_remarks: 'Some notes about the vehicle', - techRecord_dispensations: 'reason given', - techRecord_reasonForCreation: 'Brake Failure', - techRecord_modelLiteral: 'Vehicle model', - techRecord_chassisMake: 'Chassis make', - techRecord_chassisModel: 'Chassis model', - techRecord_bodyMake: 'Body make', - techRecord_bodyModel: 'Body model', - techRecord_bodyType_description: BodyTypeDescription.DOUBLE_DECKER, - techRecord_functionCode: 'r', - techRecord_conversionRefNo: '345345', + // techRecord_microfilmDocumentType: 'AAT - Trailer Annual Test', + // techRecord_microfilmRollNumber: 'nb123456', + // techRecord_microfilmSerialNumber: 'ser123456', + techRecord_remarks: 'Some notes about the vehicle', + techRecord_dispensations: 'reason given', + techRecord_reasonForCreation: 'Brake Failure', + techRecord_modelLiteral: 'Vehicle model', + techRecord_chassisMake: 'Chassis make', + techRecord_chassisModel: 'Chassis model', + techRecord_bodyMake: 'Body make', + techRecord_bodyModel: 'Body model', + techRecord_bodyType_description: BodyTypeDescription.DOUBLE_DECKER, + techRecord_functionCode: 'r', + techRecord_conversionRefNo: '345345', - // Gross vehicle weights - techRecord_grossKerbWeight: 1, - techRecord_grossLadenWeight: 2, - techRecord_grossGbWeight: 3, - // TODO: missing from types package - // techRecord_grossEecWeight: 4, - techRecord_grossDesignWeight: 5, - techRecord_unladenWeight: 6, + // Gross vehicle weights + techRecord_grossKerbWeight: 1, + techRecord_grossLadenWeight: 2, + techRecord_grossGbWeight: 3, + // TODO: missing from types package + // techRecord_grossEecWeight: 4, + techRecord_grossDesignWeight: 5, + techRecord_unladenWeight: 6, - // Train weights - techRecord_maxTrainGbWeight: 7, - techRecord_trainDesignWeight: 8, - techRecord_dda_certificateIssued: true, - techRecord_dda_wheelchairCapacity: 5, - techRecord_dda_wheelchairFittings: 'data', - techRecord_dda_wheelchairLiftPresent: false, - techRecord_dda_wheelchairLiftInformation: 'more data', - techRecord_dda_wheelchairRampPresent: true, - techRecord_dda_wheelchairRampInformation: 'ramp data', - techRecord_dda_minEmergencyExits: 3, - techRecord_dda_outswing: 'Anderson', - techRecord_dda_ddaSchedules: 'dda', - techRecord_dda_seatbeltsFitted: 51, - techRecord_dda_ddaNotes: 'This is a note', + // Train weights + techRecord_maxTrainGbWeight: 7, + techRecord_trainDesignWeight: 8, + techRecord_dda_certificateIssued: true, + techRecord_dda_wheelchairCapacity: 5, + techRecord_dda_wheelchairFittings: 'data', + techRecord_dda_wheelchairLiftPresent: false, + techRecord_dda_wheelchairLiftInformation: 'more data', + techRecord_dda_wheelchairRampPresent: true, + techRecord_dda_wheelchairRampInformation: 'ramp data', + techRecord_dda_minEmergencyExits: 3, + techRecord_dda_outswing: 'Anderson', + techRecord_dda_ddaSchedules: 'dda', + techRecord_dda_seatbeltsFitted: 51, + techRecord_dda_ddaNotes: 'This is a note', }); const axles = [ - { - axleNumber: 1, - tyres_tyreSize: '295/80-22.5', - tyres_speedCategorySymbol: 'p', - tyres_fitmentCode: 'double', - tyres_dataTrAxles: 0, - tyres_plyRating: 'A', - tyres_tyreCode: 456, - parkingBrakeMrk: 'false', + { + axleNumber: 1, + tyres_tyreSize: '295/80-22.5', + tyres_speedCategorySymbol: 'p', + tyres_fitmentCode: 'double', + tyres_dataTrAxles: 0, + tyres_plyRating: 'A', + tyres_tyreCode: 456, + parkingBrakeMrk: 'false', - weights_kerbWeight: 1, - weights_ladenWeight: 2, - weights_gbWeight: 3, - // TODO: V3 2 eecweights in type package, which is this? - // weights_eecWeight: 4, - weights_designWeight: 5, - }, - { - axleNumber: 2, - parkingBrakeMrk: 'true', + weights_kerbWeight: 1, + weights_ladenWeight: 2, + weights_gbWeight: 3, + // TODO: V3 2 eecweights in type package, which is this? + // weights_eecWeight: 4, + weights_designWeight: 5, + }, + { + axleNumber: 2, + parkingBrakeMrk: 'true', - tyres_tyreSize: '295/80-22.5', - tyres_speedCategorySymbol: 'p', - tyres_fitmentCode: 'double', - tyres_dataTrAxles: 0, - tyres_plyRating: 'A', - tyres_tyreCode: 456, + tyres_tyreSize: '295/80-22.5', + tyres_speedCategorySymbol: 'p', + tyres_fitmentCode: 'double', + tyres_dataTrAxles: 0, + tyres_plyRating: 'A', + tyres_tyreCode: 456, - weights_kerbWeight: 1, - weights_ladenWeight: 2, - weights_gbWeight: 3, - // weights_eecWeight: 4, - weights_designWeight: 5, - }, - { - axleNumber: 3, - parkingBrakeMrk: 'true', + weights_kerbWeight: 1, + weights_ladenWeight: 2, + weights_gbWeight: 3, + // weights_eecWeight: 4, + weights_designWeight: 5, + }, + { + axleNumber: 3, + parkingBrakeMrk: 'true', - tyres_tyreSize: '295/80-22.5', - tyres_speedCategorySymbol: 'p', - tyres_fitmentCode: 'double', - tyres_dataTrAxles: 0, - tyres_plyRating: 'A', - tyres_tyreCode: 456, + tyres_tyreSize: '295/80-22.5', + tyres_speedCategorySymbol: 'p', + tyres_fitmentCode: 'double', + tyres_dataTrAxles: 0, + tyres_plyRating: 'A', + tyres_tyreCode: 456, - weights_kerbWeight: 1, - weights_ladenWeight: 2, - weights_gbWeight: 3, - // weights_eecWeight: 4, - weights_designWeight: 5, - }, + weights_kerbWeight: 1, + weights_ladenWeight: 2, + weights_gbWeight: 3, + // weights_eecWeight: 4, + weights_designWeight: 5, + }, ]; // const provisionalTechRecord = { diff --git a/src/mocks/reference-data/mock-countries-of-registration.reference-data.ts b/src/mocks/reference-data/mock-countries-of-registration.reference-data.ts index 7829bc4bab..b80a59673f 100644 --- a/src/mocks/reference-data/mock-countries-of-registration.reference-data.ts +++ b/src/mocks/reference-data/mock-countries-of-registration.reference-data.ts @@ -1,194 +1,194 @@ import { ReferenceDataModelBase, ReferenceDataResourceType } from '@models/reference-data.model'; export const mockCountriesOfRegistration: ReferenceDataModelBase[] = [ - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'gb', - description: 'Great Britain and Northern Ireland - GB', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'gba', - description: 'Alderney - GBA', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'gbg', - description: 'Guernsey - GBG', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'gbj', - description: 'Jersey - GBJ', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'gbm', - description: 'Isle of Man - GBM', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'gbz', - description: 'Gibraltar - GBZ', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'a', - description: 'Austria - A', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'b', - description: 'Belgium - B', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'bih', - description: 'BosniaAndHerzegovina - BIH', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'bg', - description: 'Bulgaria - BG', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'hr', - description: 'Croatia - HR', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'cy', - description: 'Cyprus - CY', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'cz', - description: 'CzechRepublic - CZ', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'dk', - description: 'Denmark - DK', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'est', - description: 'Estonia - EST', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'fin', - description: 'Finland - FIN', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'f', - description: 'France - F', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'd', - description: 'Germany - D', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'gr', - description: 'Greece - GR', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'h', - description: 'Hungary - H', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'irl', - description: 'Ireland - IRL', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'i', - description: 'Italy - I', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'lv', - description: 'Latvia - LV', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'lt', - description: 'Lithuania - LT', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'l', - description: 'Luxembourg - L', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'm', - description: 'Malta - M', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'nl', - description: 'Netherlands - NL', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'n', - description: 'Norway - N', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'pl', - description: 'Poland - PL', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'p', - description: 'Portugal - P', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'ro', - description: 'Romania - RO', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'sk', - description: 'Slovakia - SK', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'slo', - description: 'Slovenia - SLO', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'e', - description: 'Spain - E', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 's', - description: 'Sweden - S', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'ch', - description: 'Switzerland - CH', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'non-eu', - description: 'Non EU', - }, - { - resourceType: ReferenceDataResourceType.CountryOfRegistration, - resourceKey: 'not-known', - description: 'Country Not Known', - }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'gb', + description: 'Great Britain and Northern Ireland - GB', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'gba', + description: 'Alderney - GBA', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'gbg', + description: 'Guernsey - GBG', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'gbj', + description: 'Jersey - GBJ', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'gbm', + description: 'Isle of Man - GBM', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'gbz', + description: 'Gibraltar - GBZ', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'a', + description: 'Austria - A', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'b', + description: 'Belgium - B', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'bih', + description: 'BosniaAndHerzegovina - BIH', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'bg', + description: 'Bulgaria - BG', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'hr', + description: 'Croatia - HR', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'cy', + description: 'Cyprus - CY', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'cz', + description: 'CzechRepublic - CZ', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'dk', + description: 'Denmark - DK', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'est', + description: 'Estonia - EST', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'fin', + description: 'Finland - FIN', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'f', + description: 'France - F', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'd', + description: 'Germany - D', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'gr', + description: 'Greece - GR', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'h', + description: 'Hungary - H', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'irl', + description: 'Ireland - IRL', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'i', + description: 'Italy - I', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'lv', + description: 'Latvia - LV', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'lt', + description: 'Lithuania - LT', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'l', + description: 'Luxembourg - L', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'm', + description: 'Malta - M', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'nl', + description: 'Netherlands - NL', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'n', + description: 'Norway - N', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'pl', + description: 'Poland - PL', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'p', + description: 'Portugal - P', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'ro', + description: 'Romania - RO', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'sk', + description: 'Slovakia - SK', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'slo', + description: 'Slovenia - SLO', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'e', + description: 'Spain - E', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 's', + description: 'Sweden - S', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'ch', + description: 'Switzerland - CH', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'non-eu', + description: 'Non EU', + }, + { + resourceType: ReferenceDataResourceType.CountryOfRegistration, + resourceKey: 'not-known', + description: 'Country Not Known', + }, ]; diff --git a/src/mocks/test-result.mock.ts b/src/mocks/test-result.mock.ts index daf66f0ddb..ef9a6f471d 100644 --- a/src/mocks/test-result.mock.ts +++ b/src/mocks/test-result.mock.ts @@ -5,25 +5,25 @@ import { OdometerReadingUnits } from '@models/test-types/odometer-unit.enum'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; export const createMockTestResult = (params: Partial = {}): TestResultModel => ({ - testResultId: '', - systemNumber: '', - vin: '', - testStartTimestamp: '', - testEndTimestamp: '', - testTypes: [], - trailerId: 'trailerId', - countryOfRegistration: '', - euVehicleCategory: EUVehicleCategory.M1, - odometerReading: 0, - odometerReadingUnits: OdometerReadingUnits.KILOMETRES, - preparerName: '', - preparerId: '', - testStationName: '', - testStationPNumber: '', - testStationType: TestStationType.ATF, - testerName: '', - testerEmailAddress: '', - testerStaffId: '', - vehicleType: VehicleTypes.CAR, - ...params, + testResultId: '', + systemNumber: '', + vin: '', + testStartTimestamp: '', + testEndTimestamp: '', + testTypes: [], + trailerId: 'trailerId', + countryOfRegistration: '', + euVehicleCategory: EUVehicleCategory.M1, + odometerReading: 0, + odometerReadingUnits: OdometerReadingUnits.KILOMETRES, + preparerName: '', + preparerId: '', + testStationName: '', + testStationPNumber: '', + testStationType: TestStationType.ATF, + testerName: '', + testerEmailAddress: '', + testerStaffId: '', + vehicleType: VehicleTypes.CAR, + ...params, }); diff --git a/src/mocks/test-type-category.mock.ts b/src/mocks/test-type-category.mock.ts index b6a45226ef..d1ab3acfa4 100644 --- a/src/mocks/test-type-category.mock.ts +++ b/src/mocks/test-type-category.mock.ts @@ -1,8 +1,8 @@ import { TestTypeCategory } from '@api/test-types'; export const createMockTestTypeCategory = (params: Partial = {}): TestTypeCategory => ({ - id: 'testTypeCategoryId', - name: 'testNameCategoryName', - forVehicleType: ['car'], - ...params, + id: 'testTypeCategoryId', + name: 'testNameCategoryName', + forVehicleType: ['car'], + ...params, }); diff --git a/src/mocks/test-type.mock.ts b/src/mocks/test-type.mock.ts index ef15adda5e..18f60e2151 100644 --- a/src/mocks/test-type.mock.ts +++ b/src/mocks/test-type.mock.ts @@ -1,47 +1,47 @@ -import { - EmissionStandard, FuelType, ModTypeCode, ModeTypeDescription, -} from '@models/test-types/emissions.enum'; +import { EmissionStandard, FuelType, ModTypeCode, ModeTypeDescription } from '@models/test-types/emissions.enum'; import { TestType, resultOfTestEnum } from '@models/test-types/test-type.model'; export const createMockTestType = (params: Partial = {}): TestType => ({ - testTypeId: 'testTypeId', - testNumber: 'testNumber', - name: 'testName', - testCode: 'testCode', - testTypeName: 'testTypeName', - testTypeStartTimestamp: '', - testTypeEndTimestamp: '', - testExpiryDate: '', - certificateNumber: '', - reasonForAbandoning: '', - testAnniversaryDate: 'testAnniversaryDate', - prohibitionIssued: false, - testResult: resultOfTestEnum.fail, - seatbeltInstallationCheckDate: false, - numberOfSeatbeltsFitted: 0, - lastSeatbeltInstallationCheckDate: '', - emissionStandard: EmissionStandard.Euro3, - smokeTestKLimitApplied: 'smokeTestKLimitApplied', - fuelType: FuelType.Diesel, - modificationTypeUsed: 'modificationTypeUsed', - particulateTrapFitted: 'particulateTrapFitted', - particulateTrapSerialNumber: 'particulateTrapSerialNumber', - modType: { - code: ModTypeCode.g, - description: ModeTypeDescription.Engine, - }, - customDefects: [], - additionalNotesRecorded: '', - requiredStandards: [{ - sectionNumber: 'string', - sectionDescription: 'string', - rsNumber: 1, - requiredStandard: 'string', - refCalculation: 'string', - additionalInfo: false, - inspectionTypes: ['basic'], - prs: false, - additionalNotes: 'string', - }], - ...params, + testTypeId: 'testTypeId', + testNumber: 'testNumber', + name: 'testName', + testCode: 'testCode', + testTypeName: 'testTypeName', + testTypeStartTimestamp: '', + testTypeEndTimestamp: '', + testExpiryDate: '', + certificateNumber: '', + reasonForAbandoning: '', + testAnniversaryDate: 'testAnniversaryDate', + prohibitionIssued: false, + testResult: resultOfTestEnum.fail, + seatbeltInstallationCheckDate: false, + numberOfSeatbeltsFitted: 0, + lastSeatbeltInstallationCheckDate: '', + emissionStandard: EmissionStandard.Euro3, + smokeTestKLimitApplied: 'smokeTestKLimitApplied', + fuelType: FuelType.Diesel, + modificationTypeUsed: 'modificationTypeUsed', + particulateTrapFitted: 'particulateTrapFitted', + particulateTrapSerialNumber: 'particulateTrapSerialNumber', + modType: { + code: ModTypeCode.g, + description: ModeTypeDescription.Engine, + }, + customDefects: [], + additionalNotesRecorded: '', + requiredStandards: [ + { + sectionNumber: 'string', + sectionDescription: 'string', + rsNumber: 1, + requiredStandard: 'string', + refCalculation: 'string', + additionalInfo: false, + inspectionTypes: ['basic'], + prs: false, + additionalNotes: 'string', + }, + ], + ...params, }); diff --git a/src/mocks/trl-record.mock.ts b/src/mocks/trl-record.mock.ts index d8508044ae..40d7064aa1 100644 --- a/src/mocks/trl-record.mock.ts +++ b/src/mocks/trl-record.mock.ts @@ -5,43 +5,43 @@ import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/ import { FrameDescriptions, StatusCodes } from '@models/vehicle-tech-record.model'; export const createMockTrl = (systemNumber: number): TechRecordType<'trl'> => ({ - systemNumber: 'TRL', - vin: `XMGDE04FS0H0${12344 + systemNumber + 1}`, - trailerId: 'TestId', - techRecord_createdAt: new Date().toISOString(), - techRecord_createdByName: 'Nathan', - techRecord_statusCode: StatusCodes.CURRENT, - techRecord_vehicleType: 'trl', - techRecord_regnDate: '1234', - techRecord_firstUseDate: '1234', - techRecord_manufactureYear: 2022, - techRecord_noOfAxles: 2, - techRecord_brakes_dtpNumber: '1234', - techRecord_brakes_loadSensingValve: true, - techRecord_brakes_antilockBrakingSystem: true, - techRecord_axles: undefined, - techRecord_dimensions_length: 25000, - techRecord_dimensions_width: 10000, - techRecord_suspensionType: '1', - techRecord_roadFriendly: true, - techRecord_vehicleClass_description: 'trailer', - techRecord_vehicleClass_code: 't', - techRecord_vehicleConfiguration: VehicleConfiguration.SEMI_TRAILER, - techRecord_couplingType: '1', - techRecord_maxLoadOnCoupling: 1234, - techRecord_frameDescription: FrameDescriptions.FRAME_SECTION, - techRecord_euVehicleCategory: EUVehicleCategory.M1, - techRecord_departmentalVehicleMarker: true, - techRecord_reasonForCreation: 'Brake Failure', - techRecord_approvalType: ApprovalType.ECSSTA, - techRecord_approvalTypeNumber: 'approval123', - techRecord_ntaNumber: 'nta789', - techRecord_variantNumber: 'variant123456', - techRecord_variantVersionNumber: 'variantversion123456', - techRecord_plates: undefined, - createdTimestamp: new Date().toISOString(), - partialVin: 'vin', - techRecord_bodyType_code: '', - techRecord_bodyType_description: '', - techRecord_createdById: '', + systemNumber: 'TRL', + vin: `XMGDE04FS0H0${12344 + systemNumber + 1}`, + trailerId: 'TestId', + techRecord_createdAt: new Date().toISOString(), + techRecord_createdByName: 'Nathan', + techRecord_statusCode: StatusCodes.CURRENT, + techRecord_vehicleType: 'trl', + techRecord_regnDate: '1234', + techRecord_firstUseDate: '1234', + techRecord_manufactureYear: 2022, + techRecord_noOfAxles: 2, + techRecord_brakes_dtpNumber: '1234', + techRecord_brakes_loadSensingValve: true, + techRecord_brakes_antilockBrakingSystem: true, + techRecord_axles: undefined, + techRecord_dimensions_length: 25000, + techRecord_dimensions_width: 10000, + techRecord_suspensionType: '1', + techRecord_roadFriendly: true, + techRecord_vehicleClass_description: 'trailer', + techRecord_vehicleClass_code: 't', + techRecord_vehicleConfiguration: VehicleConfiguration.SEMI_TRAILER, + techRecord_couplingType: '1', + techRecord_maxLoadOnCoupling: 1234, + techRecord_frameDescription: FrameDescriptions.FRAME_SECTION, + techRecord_euVehicleCategory: EUVehicleCategory.M1, + techRecord_departmentalVehicleMarker: true, + techRecord_reasonForCreation: 'Brake Failure', + techRecord_approvalType: ApprovalType.ECSSTA, + techRecord_approvalTypeNumber: 'approval123', + techRecord_ntaNumber: 'nta789', + techRecord_variantNumber: 'variant123456', + techRecord_variantVersionNumber: 'variantversion123456', + techRecord_plates: undefined, + createdTimestamp: new Date().toISOString(), + partialVin: 'vin', + techRecord_bodyType_code: '', + techRecord_bodyType_description: '', + techRecord_createdById: '', }); From c21e3858c0a2ef4c7e12eb8a07a3bcb95b245c02 Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Tue, 13 Aug 2024 12:20:20 +0100 Subject: [PATCH 02/21] fix(linting-1): disable rules --- biome.json | 47 ++++++++++- .../api/document-retrieval/configuration.ts | 11 +-- src/app/api/reference-data/configuration.ts | 11 +-- src/app/api/test-results/configuration.ts | 11 +-- src/app/api/test-types/configuration.ts | 11 +-- src/app/api/vehicle/configuration.ts | 11 +-- .../accordion-control.component.ts | 80 +++++++++---------- .../effects/test-records.effects.spec.ts | 22 +++-- 8 files changed, 115 insertions(+), 89 deletions(-) diff --git a/biome.json b/biome.json index 7b0ae1910b..102eda6361 100644 --- a/biome.json +++ b/biome.json @@ -1,3 +1,48 @@ { - "extends": ["@dvsa/biome-config/biome"] + "extends": ["@dvsa/biome-config/biome"], + "formatter": { + "ignore": ["src/app/api/**"] + }, + "overrides": [ + { + "include": ["**/*.mock.ts", "**/*.spec.ts", "**/*.ts"], + "linter": { + "rules": { + "complexity": { + "noBannedTypes": "off", + "noForEach": "off", + "noThisInStatic": "off", + "noUselessConstructor": "off", + "useLiteralKeys": "off", + "useOptionalChain": "off", + "useRegexLiterals": "off" + }, + "correctness": { + "noInvalidUseBeforeDeclaration": "off", + "noVoidTypeReturn": "off", + "noSwitchDeclarations": "off" + }, + "performance": { + "noAccumulatingSpread": "off", + "noDelete": "off" + }, + "suspicious": { + "noAssignInExpressions": "off", + "noDoubleEquals": "off", + "noDuplicateTestHooks": "off", + "noExplicitAny": "off", + "noImplicitAnyLet": "off", + "noPrototypeBuiltins": "off", + "noShadowRestrictedNames": "off", + "useValidTypeof": "off" + }, + "style": { + "noNonNullAssertion": "off", + "noParameterAssign": "off", + "useTemplate": "off" + } + } + } + } + ] } diff --git a/src/app/api/document-retrieval/configuration.ts b/src/app/api/document-retrieval/configuration.ts index 698dce114c..8a8c9a845e 100644 --- a/src/app/api/document-retrieval/configuration.ts +++ b/src/app/api/document-retrieval/configuration.ts @@ -72,11 +72,8 @@ export class Configuration { * @param mime - MIME (Multipurpose Internet Mail Extensions) * @return True if the given MIME is JSON, false otherwise. */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = /^(application\\/jnos | [^;\/ \t]+\; - \/[^ - \/ \t]+[+]json)[ \t]*( - .*)?$/i - return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } } diff --git a/src/app/api/reference-data/configuration.ts b/src/app/api/reference-data/configuration.ts index 698dce114c..8a8c9a845e 100644 --- a/src/app/api/reference-data/configuration.ts +++ b/src/app/api/reference-data/configuration.ts @@ -72,11 +72,8 @@ export class Configuration { * @param mime - MIME (Multipurpose Internet Mail Extensions) * @return True if the given MIME is JSON, false otherwise. */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = /^(application\\/jnos | [^;\/ \t]+\; - \/[^ - \/ \t]+[+]json)[ \t]*( - .*)?$/i - return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } } diff --git a/src/app/api/test-results/configuration.ts b/src/app/api/test-results/configuration.ts index 698dce114c..8a8c9a845e 100644 --- a/src/app/api/test-results/configuration.ts +++ b/src/app/api/test-results/configuration.ts @@ -72,11 +72,8 @@ export class Configuration { * @param mime - MIME (Multipurpose Internet Mail Extensions) * @return True if the given MIME is JSON, false otherwise. */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = /^(application\\/jnos | [^;\/ \t]+\; - \/[^ - \/ \t]+[+]json)[ \t]*( - .*)?$/i - return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } } diff --git a/src/app/api/test-types/configuration.ts b/src/app/api/test-types/configuration.ts index 698dce114c..8a8c9a845e 100644 --- a/src/app/api/test-types/configuration.ts +++ b/src/app/api/test-types/configuration.ts @@ -72,11 +72,8 @@ export class Configuration { * @param mime - MIME (Multipurpose Internet Mail Extensions) * @return True if the given MIME is JSON, false otherwise. */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = /^(application\\/jnos | [^;\/ \t]+\; - \/[^ - \/ \t]+[+]json)[ \t]*( - .*)?$/i - return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } } diff --git a/src/app/api/vehicle/configuration.ts b/src/app/api/vehicle/configuration.ts index 698dce114c..8a8c9a845e 100644 --- a/src/app/api/vehicle/configuration.ts +++ b/src/app/api/vehicle/configuration.ts @@ -72,11 +72,8 @@ export class Configuration { * @param mime - MIME (Multipurpose Internet Mail Extensions) * @return True if the given MIME is JSON, false otherwise. */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = /^(application\\/jnos | [^;\/ \t]+\; - \/[^ - \/ \t]+[+]json)[ \t]*( - .*)?$/i - return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } } diff --git a/src/app/shared/components/accordion-control/accordion-control.component.ts b/src/app/shared/components/accordion-control/accordion-control.component.ts index 8bf0e776da..f7130b8bc6 100644 --- a/src/app/shared/components/accordion-control/accordion-control.component.ts +++ b/src/app/shared/components/accordion-control/accordion-control.component.ts @@ -19,51 +19,49 @@ export class AccordionControlComponent { get accordions(): QueryList | undefined { return this.accordionsList; } - @ContentChildren(AccordionComponent, { descendants: true, emitDistinctChangesOnly: false }) set accordions( - value: QueryList | undefined - , - ) { - this. - accordionsList = value; - if (this.accordionsList?.length === this.sectionState?.length) { - this.isExpanded = true; - } - if (this.isExpanded) { - this.toggleAccordions(); - } - this; - . - expandAccordions(); -} + @ContentChildren(AccordionComponent, { + descendants: true, + emitDistinctChangesOnly: false, + }) + set accordions(value: QueryList | undefined) { + this.accordionsList = value; + if (this.accordionsList?.length === this.sectionState?.length) { + this.isExpanded = true; + } + if (this.isExpanded) { + this.toggleAccordions(); + } + this.expandAccordions(); + } -@Input() -isExpanded = false; -@Input() -layout?: string; -@Input() class = ''; - @Input() sectionState: (string | number)[] | undefined | null = []; + @Input() + isExpanded = false; + @Input() + layout?: string; + @Input() class = ''; + @Input() sectionState: (string | number)[] | undefined | null = []; - constructor(private cdr: ChangeDetectorRef) {} + constructor(private cdr: ChangeDetectorRef) {} - get iconStyle(): string { - return `govuk-accordion-nav__chevron${(this.isExpanded ? '' : ' govuk-accordion-nav__chevron--down')}`; - } + get iconStyle(): string { + return `govuk-accordion-nav__chevron${this.isExpanded ? '' : ' govuk-accordion-nav__chevron--down'}`; + } - toggle(): void { - this.isExpanded = !this.isExpanded; - this.toggleAccordions(); - this.cdr.markForCheck(); - } + toggle(): void { + this.isExpanded = !this.isExpanded; + this.toggleAccordions(); + this.cdr.markForCheck(); + } - private expandAccordions(): void { - if (this.accordions && this.sectionState && this.sectionState.length > 0) { - this.accordions?.forEach((a) => (this.sectionState?.includes(a.id) ? a.open(a.id) : a.close(a.id))); - } - } + private expandAccordions(): void { + if (this.accordions && this.sectionState && this.sectionState.length > 0) { + this.accordions?.forEach((a) => (this.sectionState?.includes(a.id) ? a.open(a.id) : a.close(a.id))); + } + } - private toggleAccordions(): void { - if (this.accordions) { - this.accordions.forEach((a) => (this.isExpanded ? a.open(a.id) : a.close(a.id))); - } - } + private toggleAccordions(): void { + if (this.accordions) { + this.accordions.forEach((a) => (this.isExpanded ? a.open(a.id) : a.close(a.id))); + } + } } diff --git a/src/app/store/test-records/effects/test-records.effects.spec.ts b/src/app/store/test-records/effects/test-records.effects.spec.ts index 01c5e2543f..2700964336 100644 --- a/src/app/store/test-records/effects/test-records.effects.spec.ts +++ b/src/app/store/test-records/effects/test-records.effects.spec.ts @@ -332,18 +332,16 @@ describe('TestResultsEffects', () => { testScheduler.run(({ hot, cold, expectObservable }) => { actions$ = hot('-a-', { a: updateTestResult({ value: newTestResult }) }); - jest - .spyOn(testResultsService, 'saveTestResult') - .mockReturnValue( - cold( - '---#|', - {}, - new HttpErrorResponse({ - status: 400, - error: { errors: ['"name" is missing', '"age" is missing', 'random error'] }, - }) - ) - ); + jest.spyOn(testResultsService, 'saveTestResult').mockReturnValue( + cold( + '---#|', + {}, + new HttpErrorResponse({ + status: 400, + error: { errors: ['"name" is missing', '"age" is missing', 'random error'] }, + }) + ) + ); const expectedErrors: GlobalError[] = [ { error: '"name" is missing', anchorLink: 'name' }, From c933c30aa031c3a74f29d7939079707ae5375f8e Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Tue, 13 Aug 2024 15:49:01 +0100 Subject: [PATCH 03/21] chore(linting-1): enable useTemplate --- biome.json | 3 +-- .../document-retrieval/api/document-retrieval.service.ts | 6 +++--- src/app/api/test-results/api/archiveTestResults.service.ts | 2 +- src/app/api/test-results/api/default.service.ts | 2 +- src/app/api/test-results/api/getTestResults.service.ts | 2 +- src/app/api/test-results/api/updateTestResults.service.ts | 2 +- src/app/api/test-types/api/testTypes.service.ts | 4 ++-- src/app/api/vehicle/api/addProvisionalTechRecord.service.ts | 2 +- src/app/api/vehicle/api/archiveTechRecordStatus.service.ts | 2 +- src/app/api/vehicle/api/getTechRecords.service.ts | 2 +- src/app/api/vehicle/api/postTechRecords.service.ts | 2 +- src/app/api/vehicle/api/updateTechRecords.service.ts | 2 +- 12 files changed, 15 insertions(+), 16 deletions(-) diff --git a/biome.json b/biome.json index 102eda6361..bf25f4de61 100644 --- a/biome.json +++ b/biome.json @@ -38,8 +38,7 @@ }, "style": { "noNonNullAssertion": "off", - "noParameterAssign": "off", - "useTemplate": "off" + "noParameterAssign": "off" } } } diff --git a/src/app/api/document-retrieval/api/document-retrieval.service.ts b/src/app/api/document-retrieval/api/document-retrieval.service.ts index 5d1ef449ea..74b5345c6a 100644 --- a/src/app/api/document-retrieval/api/document-retrieval.service.ts +++ b/src/app/api/document-retrieval/api/document-retrieval.service.ts @@ -80,7 +80,7 @@ export class DocumentRetrievalService { typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); + headers = headers.set('Authorization', `Bearer ${accessToken}`); } // api keys @@ -140,7 +140,7 @@ export class DocumentRetrievalService { typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); + headers = headers.set('Authorization', `Bearer ${accessToken}`); } // api keys @@ -182,7 +182,7 @@ export class DocumentRetrievalService { typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); + headers = headers.set('Authorization', `Bearer ${accessToken}`); } if (this.configuration.apiKeys) { diff --git a/src/app/api/test-results/api/archiveTestResults.service.ts b/src/app/api/test-results/api/archiveTestResults.service.ts index 747db0ca46..515506d8fb 100644 --- a/src/app/api/test-results/api/archiveTestResults.service.ts +++ b/src/app/api/test-results/api/archiveTestResults.service.ts @@ -104,7 +104,7 @@ export class ArchiveTestResultsService { typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); + headers = headers.set('Authorization', `Bearer ${accessToken}`); } // to determine the Accept header diff --git a/src/app/api/test-results/api/default.service.ts b/src/app/api/test-results/api/default.service.ts index 57b689c012..99679e7b7e 100644 --- a/src/app/api/test-results/api/default.service.ts +++ b/src/app/api/test-results/api/default.service.ts @@ -84,7 +84,7 @@ export class DefaultService { typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); + headers = headers.set('Authorization', `Bearer ${accessToken}`); } // to determine the Accept header diff --git a/src/app/api/test-results/api/getTestResults.service.ts b/src/app/api/test-results/api/getTestResults.service.ts index 612651208d..bff70116a5 100644 --- a/src/app/api/test-results/api/getTestResults.service.ts +++ b/src/app/api/test-results/api/getTestResults.service.ts @@ -135,7 +135,7 @@ export class GetTestResultsService { typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); + headers = headers.set('Authorization', `Bearer ${accessToken}`); } // to determine the Accept header diff --git a/src/app/api/test-results/api/updateTestResults.service.ts b/src/app/api/test-results/api/updateTestResults.service.ts index 52e310e045..c23a1edf93 100644 --- a/src/app/api/test-results/api/updateTestResults.service.ts +++ b/src/app/api/test-results/api/updateTestResults.service.ts @@ -101,7 +101,7 @@ export class UpdateTestResultsService { typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); + headers = headers.set('Authorization', `Bearer ${accessToken}`); } // to determine the Accept header diff --git a/src/app/api/test-types/api/testTypes.service.ts b/src/app/api/test-types/api/testTypes.service.ts index 278ae06052..8741ea5c4e 100644 --- a/src/app/api/test-types/api/testTypes.service.ts +++ b/src/app/api/test-types/api/testTypes.service.ts @@ -87,7 +87,7 @@ export class TestTypesService { typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); + headers = headers.set('Authorization', `Bearer ${accessToken}`); } // to determine the Accept header @@ -230,7 +230,7 @@ export class TestTypesService { typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); + headers = headers.set('Authorization', `Bearer ${accessToken}`); } // to determine the Accept header diff --git a/src/app/api/vehicle/api/addProvisionalTechRecord.service.ts b/src/app/api/vehicle/api/addProvisionalTechRecord.service.ts index f56cb1b070..68d5a9bd09 100644 --- a/src/app/api/vehicle/api/addProvisionalTechRecord.service.ts +++ b/src/app/api/vehicle/api/addProvisionalTechRecord.service.ts @@ -102,7 +102,7 @@ export class AddProvisionalTechRecordService { typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); + headers = headers.set('Authorization', `Bearer ${accessToken}`); } // to determine the Accept header diff --git a/src/app/api/vehicle/api/archiveTechRecordStatus.service.ts b/src/app/api/vehicle/api/archiveTechRecordStatus.service.ts index 9878327475..a173683d17 100644 --- a/src/app/api/vehicle/api/archiveTechRecordStatus.service.ts +++ b/src/app/api/vehicle/api/archiveTechRecordStatus.service.ts @@ -102,7 +102,7 @@ export class ArchiveTechRecordStatusService { typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); + headers = headers.set('Authorization', `Bearer ${accessToken}`); } // to determine the Accept header diff --git a/src/app/api/vehicle/api/getTechRecords.service.ts b/src/app/api/vehicle/api/getTechRecords.service.ts index 0037eec10b..41a73c3ae0 100644 --- a/src/app/api/vehicle/api/getTechRecords.service.ts +++ b/src/app/api/vehicle/api/getTechRecords.service.ts @@ -119,7 +119,7 @@ export class GetTechRecordsService { typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); + headers = headers.set('Authorization', `Bearer ${accessToken}`); } // to determine the Accept header diff --git a/src/app/api/vehicle/api/postTechRecords.service.ts b/src/app/api/vehicle/api/postTechRecords.service.ts index d0017d5b2a..f3215ca8c5 100644 --- a/src/app/api/vehicle/api/postTechRecords.service.ts +++ b/src/app/api/vehicle/api/postTechRecords.service.ts @@ -84,7 +84,7 @@ export class PostTechRecordsService { typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); + headers = headers.set('Authorization', `Bearer ${accessToken}`); } // to determine the Accept header diff --git a/src/app/api/vehicle/api/updateTechRecords.service.ts b/src/app/api/vehicle/api/updateTechRecords.service.ts index ca299c9b5a..ab1f7841a5 100644 --- a/src/app/api/vehicle/api/updateTechRecords.service.ts +++ b/src/app/api/vehicle/api/updateTechRecords.service.ts @@ -113,7 +113,7 @@ export class UpdateTechRecordsService { typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; - headers = headers.set('Authorization', 'Bearer ' + accessToken); + headers = headers.set('Authorization', `Bearer ${accessToken}`); } // to determine the Accept header From 2693501eb1768dfdb9b46e88d4e0c8d8ba120e45 Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Tue, 13 Aug 2024 15:55:51 +0100 Subject: [PATCH 04/21] chore(linting-1): enable no this in static --- biome.json | 1 - src/app/forms/services/dynamic-form.service.ts | 8 ++++---- src/app/forms/validators/custom-async-validators.ts | 11 ++++------- src/app/forms/validators/custom-validators.ts | 8 ++++---- src/app/forms/validators/date/date.validators.ts | 2 +- tsconfig.json | 6 +++--- 6 files changed, 16 insertions(+), 20 deletions(-) diff --git a/biome.json b/biome.json index bf25f4de61..d8d8ffdd9a 100644 --- a/biome.json +++ b/biome.json @@ -11,7 +11,6 @@ "complexity": { "noBannedTypes": "off", "noForEach": "off", - "noThisInStatic": "off", "noUselessConstructor": "off", "useLiteralKeys": "off", "useOptionalChain": "off", diff --git a/src/app/forms/services/dynamic-form.service.ts b/src/app/forms/services/dynamic-form.service.ts index de464f6635..6bc01f6fd7 100644 --- a/src/app/forms/services/dynamic-form.service.ts +++ b/src/app/forms/services/dynamic-form.service.ts @@ -194,17 +194,17 @@ export class DynamicFormService { errors: GlobalError[], updateValidity = true ) { - this.getFormLevelErrors(form, errors); + DynamicFormService.getFormLevelErrors(form, errors); Object.entries(form.controls).forEach(([, value]) => { if (!(value instanceof FormControl || value instanceof CustomFormControl)) { - this.validate(value as CustomFormGroup | CustomFormArray, errors, updateValidity); + DynamicFormService.validate(value as CustomFormGroup | CustomFormArray, errors, updateValidity); } else { value.markAsTouched(); if (updateValidity) { value.updateValueAndValidity(); } (value as CustomFormControl).meta?.changeDetection?.detectChanges(); - this.getControlErrors(value, errors); + DynamicFormService.getControlErrors(value, errors); } }); } @@ -228,7 +228,7 @@ export class DynamicFormService { static validateControl(control: FormControl | CustomFormControl, errors: GlobalError[]) { control.markAsTouched(); (control as CustomFormControl).meta?.changeDetection?.detectChanges(); - this.getControlErrors(control, errors); + DynamicFormService.getControlErrors(control, errors); } private static getControlErrors(control: FormControl | CustomFormControl, validationErrorList: GlobalError[]) { diff --git a/src/app/forms/validators/custom-async-validators.ts b/src/app/forms/validators/custom-async-validators.ts index 228338da9e..cc79f6f06c 100644 --- a/src/app/forms/validators/custom-async-validators.ts +++ b/src/app/forms/validators/custom-async-validators.ts @@ -1,6 +1,5 @@ import { AbstractControl, AsyncValidatorFn, ValidationErrors, Validators } from '@angular/forms'; import { Condition, operatorEnum } from '@forms/models/condition.model'; -// eslint-disable-next-line import/no-cycle import { CustomFormControl } from '@forms/services/dynamic-form.types'; import { User } from '@models/reference-data.model'; import { TestResultModel } from '@models/test-results/test-result.model'; @@ -189,11 +188,11 @@ export class CustomAsyncValidators { } static requiredIfNotFail(store: Store): AsyncValidatorFn { - return this.requiredIfNotResult(store, resultOfTestEnum.fail); + return CustomAsyncValidators.requiredIfNotResult(store, resultOfTestEnum.fail); } static requiredIfNotAbandoned(store: Store): AsyncValidatorFn { - return this.requiredIfNotResult(store, resultOfTestEnum.abandoned); + return CustomAsyncValidators.requiredIfNotResult(store, resultOfTestEnum.abandoned); } static requiredIfNotResultAndSiblingEquals( @@ -285,10 +284,8 @@ export class CustomAsyncValidators { private static checkCondition(testResult: TestResultModel, condition: Condition) { const { field, operator, value } = condition; - // eslint-disable-next-line no-prototype-builtins - const fieldValue = testResult.testTypes[0].hasOwnProperty(field) - ? // eslint-disable-next-line @typescript-eslint/no-explicit-any, security/detect-object-injection - (testResult.testTypes[0] as any)[field] + const fieldValue = Object.hasOwn(testResult.testTypes[0], field) + ? (testResult.testTypes[0] as any)[field] : testResult[field as keyof TestResultModel]; const isTrue = Array.isArray(value) ? value.includes(fieldValue) : fieldValue === value; diff --git a/src/app/forms/validators/custom-validators.ts b/src/app/forms/validators/custom-validators.ts index a677459a20..b39f83e09a 100644 --- a/src/app/forms/validators/custom-validators.ts +++ b/src/app/forms/validators/custom-validators.ts @@ -237,18 +237,18 @@ export class CustomValidators { }; static validateVinCharacters() { - return this.customPattern(['^(?!.*[OIQ]).*$', 'should not contain O, I or Q']); + return CustomValidators.customPattern(['^(?!.*[OIQ]).*$', 'should not contain O, I or Q']); } static alphanumeric(): ValidatorFn { - return this.customPattern(['^[a-zA-Z0-9]*$', 'must be alphanumeric']); + return CustomValidators.customPattern(['^[a-zA-Z0-9]*$', 'must be alphanumeric']); } static numeric(): ValidatorFn { - return this.customPattern(['^\\d*$', 'must be a whole number']); + return CustomValidators.customPattern(['^\\d*$', 'must be a whole number']); } static email(): ValidatorFn { - return this.customPattern([ + return CustomValidators.customPattern([ '^[\\w\\-\\.\\+]+@([\\w-]+\\.)+[\\w-]{2,}$', 'Enter an email address in the correct format, like name@example.com', ]); diff --git a/src/app/forms/validators/date/date.validators.ts b/src/app/forms/validators/date/date.validators.ts index 591d60f018..cd5cae5308 100644 --- a/src/app/forms/validators/date/date.validators.ts +++ b/src/app/forms/validators/date/date.validators.ts @@ -21,7 +21,7 @@ export class DateValidators { } if (displayTime) { - return this.validateTime(t, label); + return DateValidators.validateTime(t, label); } return null; diff --git a/tsconfig.json b/tsconfig.json index 61f67dff15..0ac4ba9e7b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,11 +16,11 @@ "moduleResolution": "node", "resolveJsonModule": true, "importHelpers": true, - "target": "es2017", + "target": "ES2022", + "module": "ES2022", "allowSyntheticDefaultImports": true, - "module": "es2020", "lib": [ - "es2020", + "es2023", "dom" ], "paths": { From 4deb3c9964dce1e7a0c219418bed47ca61dcaaac Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Tue, 13 Aug 2024 15:57:24 +0100 Subject: [PATCH 05/21] chore(linting-1): enable use optional chain --- biome.json | 1 - .../tech-record-summary-changes.component.ts | 3 +-- .../approval-type/approval-type.component.ts | 2 +- .../base-control/base-control.component.ts | 2 +- .../checkbox-group/checkbox-group.component.ts | 5 ++--- src/app/forms/components/date/date.component.ts | 2 +- .../dynamic-form-group.component.ts | 2 +- src/app/forms/validators/adr/adr.validators.ts | 2 +- src/app/forms/validators/custom-validators.ts | 12 ++++++------ .../forms/validators/defects/defect.validators.ts | 2 +- src/app/services/axles/axles.service.ts | 3 +-- .../services/test-records/test-records.service.ts | 2 +- .../reducers/test-records.reducer.spec.ts | 5 +---- 13 files changed, 18 insertions(+), 25 deletions(-) diff --git a/biome.json b/biome.json index d8d8ffdd9a..61e581b20a 100644 --- a/biome.json +++ b/biome.json @@ -13,7 +13,6 @@ "noForEach": "off", "noUselessConstructor": "off", "useLiteralKeys": "off", - "useOptionalChain": "off", "useRegexLiterals": "off" }, "correctness": { diff --git a/src/app/features/tech-record/components/tech-record-summary-changes/tech-record-summary-changes.component.ts b/src/app/features/tech-record/components/tech-record-summary-changes/tech-record-summary-changes.component.ts index d8e2896158..0aa44a27fa 100644 --- a/src/app/features/tech-record/components/tech-record-summary-changes/tech-record-summary-changes.component.ts +++ b/src/app/features/tech-record/components/tech-record-summary-changes/tech-record-summary-changes.component.ts @@ -229,8 +229,7 @@ export class TechRecordSummaryChangesComponent implements OnInit, OnDestroy { })) .filter( (section) => - Boolean(section && section.children && section.children.length > 0) || - this.sectionsWhitelist.includes(section.name) + Boolean(section?.children && section.children.length > 0) || this.sectionsWhitelist.includes(section.name) ); } diff --git a/src/app/forms/components/approval-type/approval-type.component.ts b/src/app/forms/components/approval-type/approval-type.component.ts index 4d4ae1a8be..0d7a0b102b 100644 --- a/src/app/forms/components/approval-type/approval-type.component.ts +++ b/src/app/forms/components/approval-type/approval-type.component.ts @@ -192,7 +192,7 @@ export class ApprovalTypeInputComponent } ngOnDestroy(): void { - this.subscriptions.forEach((s) => s && s.unsubscribe()); + this.subscriptions.forEach((s) => s?.unsubscribe()); } onTechRecord_approvalTypeNumber1_Change(event: string | undefined) { diff --git a/src/app/forms/components/base-control/base-control.component.ts b/src/app/forms/components/base-control/base-control.component.ts index 01641e5065..2f97b1d972 100644 --- a/src/app/forms/components/base-control/base-control.component.ts +++ b/src/app/forms/components/base-control/base-control.component.ts @@ -54,7 +54,7 @@ export class BaseControlComponent implements ControlValueAccessor, AfterContentI const ngControl: NgControl | null = this.injector.get(NgControl, null); if (ngControl) { this.control = ngControl.control as CustomControl; - if (this.control && this.control.meta) { + if (this.control?.meta) { this.control.meta.changeDetection = this.cdr; } } else { diff --git a/src/app/forms/components/checkbox-group/checkbox-group.component.ts b/src/app/forms/components/checkbox-group/checkbox-group.component.ts index 00c9982fa9..10e7119ff7 100644 --- a/src/app/forms/components/checkbox-group/checkbox-group.component.ts +++ b/src/app/forms/components/checkbox-group/checkbox-group.component.ts @@ -20,7 +20,7 @@ export class CheckboxGroupComponent extends BaseControlComponent { @Input() delimited?: { regex?: string; separator: string }; isChecked(option: string | number | boolean): boolean { - return this.value && this.value.includes(option); + return this.value?.includes(option); } handleChange(event: boolean, option: FormNodeOption): void { @@ -39,8 +39,7 @@ export class CheckboxGroupComponent extends BaseControlComponent { private remove(option: FormNodeOption) { // eslint-disable-next-line security/detect-non-literal-regexp - const separator = - this.delimited && this.delimited?.regex ? new RegExp(this.delimited?.regex) : this.delimited?.separator; + const separator = this.delimited?.regex ? new RegExp(this.delimited?.regex) : this.delimited?.separator; let newValue = separator ? this.value?.split(separator) : [...this.value]; diff --git a/src/app/forms/components/date/date.component.ts b/src/app/forms/components/date/date.component.ts index e686f2ce2c..1b6f102d14 100644 --- a/src/app/forms/components/date/date.component.ts +++ b/src/app/forms/components/date/date.component.ts @@ -108,7 +108,7 @@ export class DateComponent extends BaseControlComponent implements OnInit, OnDes } ngOnDestroy(): void { - this.subscriptions.forEach((s) => s && s.unsubscribe()); + this.subscriptions.forEach((s) => s?.unsubscribe()); } onDayChange(event: number | undefined) { diff --git a/src/app/forms/components/dynamic-form-group/dynamic-form-group.component.ts b/src/app/forms/components/dynamic-form-group/dynamic-form-group.component.ts index 4989d18fb6..976610accc 100644 --- a/src/app/forms/components/dynamic-form-group/dynamic-form-group.component.ts +++ b/src/app/forms/components/dynamic-form-group/dynamic-form-group.component.ts @@ -44,7 +44,7 @@ export class DynamicFormGroupComponent implements OnChanges, OnInit, OnDestroy { ngOnChanges(changes: SimpleChanges): void { const { template, data } = changes; - if (template && template.currentValue) { + if (template?.currentValue) { this.form = this.dfs.createForm(template.currentValue, this.data); } if (data?.currentValue && data.currentValue !== data.previousValue) { diff --git a/src/app/forms/validators/adr/adr.validators.ts b/src/app/forms/validators/adr/adr.validators.ts index c6440d1db4..dfe11946b7 100644 --- a/src/app/forms/validators/adr/adr.validators.ts +++ b/src/app/forms/validators/adr/adr.validators.ts @@ -50,7 +50,7 @@ export class AdrValidators { } // If any of the control indices have length greater than 1500 characters, show an error message for each - if (control.value && control.value.some((unNumber: string) => unNumber.length > 1500)) { + if (control.value?.some((unNumber: string) => unNumber.length > 1500)) { return { multiple: control.value .map((unNumber: string, index: number) => diff --git a/src/app/forms/validators/custom-validators.ts b/src/app/forms/validators/custom-validators.ts index b39f83e09a..3d3b91b1f4 100644 --- a/src/app/forms/validators/custom-validators.ts +++ b/src/app/forms/validators/custom-validators.ts @@ -74,7 +74,7 @@ export class CustomValidators { static hideIfParentSiblingNotEqual = (parentSibling: string, value: unknown): ValidatorFn => { return (control: AbstractControl): ValidationErrors | null => { - if (control?.parent && control.parent.parent) { + if (control?.parent?.parent) { const siblingControl = control.parent.parent.get(parentSibling) as CustomFormControl; siblingControl.meta.hide = Array.isArray(value) ? !value.includes(control.value) : control.value !== value; @@ -86,7 +86,7 @@ export class CustomValidators { static hideIfParentSiblingEquals = (parentSibling: string, value: unknown): ValidatorFn => { return (control: AbstractControl): ValidationErrors | null => { - if (control?.parent && control.parent.parent) { + if (control?.parent?.parent) { const siblingControl = control.parent.parent.get(parentSibling) as CustomFormControl; siblingControl.meta.hide = Array.isArray(value) && control.value ? value.includes(control.value) : control.value === value; @@ -281,7 +281,7 @@ export class CustomValidators { Number.parseInt(yyyy ?? '', 10), label ); - return checks && checks.error ? { dateIsInvalid: { message: checks.errors?.[0]?.reason } } : null; + return checks?.error ? { dateIsInvalid: { message: checks.errors?.[0]?.reason } } : null; }; static pastDate: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { @@ -469,7 +469,7 @@ export class CustomValidators { static hideGroupsWhenIncludes = (values: unknown[] | undefined, groups: string[]): ValidatorFn => { return (control: AbstractControl): ValidationErrors | null => { - if (values && values.some((value) => control.value?.includes(value))) { + if (values?.some((value) => control.value?.includes(value))) { this.setHidePropertyForGroups(control, groups, true); } @@ -479,7 +479,7 @@ export class CustomValidators { static showGroupsWhenExcludes = (values: unknown[] | undefined, groups: string[]): ValidatorFn => { return (control: AbstractControl): ValidationErrors | null => { - if (values && values.some((value) => control.value?.includes(value))) return null; + if (values?.some((value) => control.value?.includes(value))) return null; this.setHidePropertyForGroups(control, groups, false); return null; @@ -488,7 +488,7 @@ export class CustomValidators { static hideGroupsWhenExcludes = (values: unknown[] | undefined, groups: string[]): ValidatorFn => { return (control: AbstractControl): ValidationErrors | null => { - if (values && values.some((value) => control.value?.includes(value))) return null; + if (values?.some((value) => control.value?.includes(value))) return null; this.setHidePropertyForGroups(control, groups, true); return null; diff --git a/src/app/forms/validators/defects/defect.validators.ts b/src/app/forms/validators/defects/defect.validators.ts index e8f8e27c26..50dfa5331d 100644 --- a/src/app/forms/validators/defects/defect.validators.ts +++ b/src/app/forms/validators/defects/defect.validators.ts @@ -3,7 +3,7 @@ import { deficiencyCategory } from '@models/defects/deficiency-category.enum'; export class DefectValidators { static validateDefectNotes: ValidatorFn = (control: AbstractControl): ValidationErrors | null => { - if (control?.parent && control.parent.parent) { + if (control?.parent?.parent) { const grandParent = control.parent.parent; const defCategory = grandParent?.get('deficiencyCategory')?.value as deficiencyCategory; const prohibitionIssued = grandParent.get('prohibitionIssued')?.value as boolean; diff --git a/src/app/services/axles/axles.service.ts b/src/app/services/axles/axles.service.ts index 3e2bfc27c3..326218282f 100644 --- a/src/app/services/axles/axles.service.ts +++ b/src/app/services/axles/axles.service.ts @@ -28,8 +28,7 @@ export class AxlesService { while (axleNumber < numberOfAxles) { axleSpacing.push({ axles: `${axleNumber}-${axleNumber + 1}`, - value: - axleSpacingOriginal && axleSpacingOriginal[axleNumber - 1] ? axleSpacingOriginal[axleNumber - 1].value : null, + value: axleSpacingOriginal?.[axleNumber - 1] ? axleSpacingOriginal[axleNumber - 1].value : null, }); axleNumber++; } diff --git a/src/app/services/test-records/test-records.service.ts b/src/app/services/test-records/test-records.service.ts index db0d0ca0ec..f45264fcca 100644 --- a/src/app/services/test-records/test-records.service.ts +++ b/src/app/services/test-records/test-records.service.ts @@ -211,7 +211,7 @@ export class TestRecordsService { } const { vehicleType } = testResult; - const testTypeId = testResult.testTypes && testResult.testTypes[0].testTypeId; + const testTypeId = testResult.testTypes?.[0].testTypeId; const testTypeGroup = TestRecordsService.getTestTypeGroup(testTypeId); const vehicleTpl = vehicleType && templateMap[`${vehicleType}`]; diff --git a/src/app/store/test-records/reducers/test-records.reducer.spec.ts b/src/app/store/test-records/reducers/test-records.reducer.spec.ts index bc3eead17a..6cf6150114 100644 --- a/src/app/store/test-records/reducers/test-records.reducer.spec.ts +++ b/src/app/store/test-records/reducers/test-records.reducer.spec.ts @@ -412,10 +412,7 @@ describe('Test Results Reducer', () => { const action = updateDefect({ defect: newDefect, index: 0 }); const newState = testResultsReducer({ ...initialTestResultsState, editingTestResult: testResult }, action); - const path = - newState.editingTestResult?.testTypes[0] && - newState.editingTestResult?.testTypes[0].defects && - newState.editingTestResult?.testTypes[0].defects[0].imNumber; + const path = newState.editingTestResult?.testTypes[0]?.defects?.[0].imNumber; expect(path).toBe(1); }); From fa407712ffac00b0992bec71b7a0407ee8627bf9 Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Tue, 13 Aug 2024 16:00:31 +0100 Subject: [PATCH 06/21] chore(linting-1): enable no accumulating spread --- biome.json | 1 - .../reference-data/reducers/reference-data.reducer.spec.ts | 1 + .../reference-data/selectors/reference-data.selectors.spec.ts | 2 ++ 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/biome.json b/biome.json index 61e581b20a..e92d9de8d6 100644 --- a/biome.json +++ b/biome.json @@ -21,7 +21,6 @@ "noSwitchDeclarations": "off" }, "performance": { - "noAccumulatingSpread": "off", "noDelete": "off" }, "suspicious": { diff --git a/src/app/store/reference-data/reducers/reference-data.reducer.spec.ts b/src/app/store/reference-data/reducers/reference-data.reducer.spec.ts index 9c6c511e00..77bb9a3def 100644 --- a/src/app/store/reference-data/reducers/reference-data.reducer.spec.ts +++ b/src/app/store/reference-data/reducers/reference-data.reducer.spec.ts @@ -61,6 +61,7 @@ describe('Reference Data Reducer', () => { const { resourceType, payload } = value; const ids = payload.map((v) => v.resourceKey); const entities: Dictionary = payload.reduce( + // biome-ignore lint/performance/noAccumulatingSpread: Ignoring as it's a spec (acc, v) => ({ ...acc, [v.resourceKey]: v }), {} as { [V in ReferenceDataModelBase as V['resourceKey']]: V } ); diff --git a/src/app/store/reference-data/selectors/reference-data.selectors.spec.ts b/src/app/store/reference-data/selectors/reference-data.selectors.spec.ts index 73975c54b1..8ebb60b560 100644 --- a/src/app/store/reference-data/selectors/reference-data.selectors.spec.ts +++ b/src/app/store/reference-data/selectors/reference-data.selectors.spec.ts @@ -12,6 +12,7 @@ describe('Reference Data Selectors', () => { const { resourceType, payload } = value; const ids = payload.map((v) => v.resourceKey); const entities: Dictionary = payload.reduce( + // biome-ignore lint/performance/noAccumulatingSpread: Ignoring as it's a spec (acc, v) => ({ ...acc, [v.resourceKey]: v }), {} as { [V in ReferenceDataModelBase as V['resourceKey']]: V } ); @@ -30,6 +31,7 @@ describe('Reference Data Selectors', () => { const { resourceType, payload } = value; const ids: string[] = payload.map((v) => v.resourceKey as string); const entities: Dictionary = payload.reduce( + // biome-ignore lint/performance/noAccumulatingSpread: Ignoring as it's a spec (acc, v) => ({ ...acc, [v.resourceKey]: v }), {} as { [V in ReferenceDataModelBase as V['resourceKey']]: V } ); From 339272ffbe9fd7c613fe1714bac1d924726da560 Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Tue, 13 Aug 2024 16:02:26 +0100 Subject: [PATCH 07/21] chore(linting-1): enable no shadow restricted names --- biome.json | 1 - .../global-error/global-error.stories.ts | 15 --------- src/app/features/search/search.stories.ts | 31 ------------------- 3 files changed, 47 deletions(-) delete mode 100644 src/app/core/components/global-error/global-error.stories.ts delete mode 100644 src/app/features/search/search.stories.ts diff --git a/biome.json b/biome.json index e92d9de8d6..6b3cac680e 100644 --- a/biome.json +++ b/biome.json @@ -30,7 +30,6 @@ "noExplicitAny": "off", "noImplicitAnyLet": "off", "noPrototypeBuiltins": "off", - "noShadowRestrictedNames": "off", "useValidTypeof": "off" }, "style": { diff --git a/src/app/core/components/global-error/global-error.stories.ts b/src/app/core/components/global-error/global-error.stories.ts deleted file mode 100644 index 6430a0a5e1..0000000000 --- a/src/app/core/components/global-error/global-error.stories.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Meta, Story } from '@storybook/angular'; -import { GlobalErrorComponent } from './global-error.component'; - -export default { - title: 'Global Error Component', - component: GlobalErrorComponent, -} as Meta; - -export const NoErrors: Story = () => ({ - props: {}, -}); - -export const Error: Story = () => ({ - props: { errorMessage$: 'error' }, -}); diff --git a/src/app/features/search/search.stories.ts b/src/app/features/search/search.stories.ts deleted file mode 100644 index f28c11f69e..0000000000 --- a/src/app/features/search/search.stories.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { HttpClientModule } from '@angular/common/http'; -import { Meta, Story, moduleMetadata } from '@storybook/angular'; -import { SearchComponent } from './search.component'; - -export default { - title: 'Search Page', - component: SearchComponent, - decorators: [ - moduleMetadata({ - declarations: [SearchComponent], - imports: [HttpClientModule], - }), - ], -} as Meta; - -const Template: Story = (args) => ({ - props: args, -}); - -export const Initial = Template.bind({}); -Initial.args = {}; - -export const Loading = Template.bind({}); -Loading.args = { - isLoading: true, -}; - -export const Error = Template.bind({}); -Error.args = { - searchError: 'This is an error', -}; From 8890b32991b4c48e58b1cf8aada4e21203726e2e Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Tue, 13 Aug 2024 16:05:56 +0100 Subject: [PATCH 08/21] chore(linting-1): enable no void type return --- biome.json | 1 - .../adr-generate-certificate.component.ts | 5 ++++- .../tech-record-change-type.component.ts | 6 ++++-- .../tech-record-generate-letter.component.ts | 8 ++++++-- .../tech-record-generate-plate.component.ts | 5 ++++- .../batch-vehicle-template.component.ts | 2 +- .../components/checkbox-group/checkbox-group.component.ts | 6 +++++- src/app/services/reference-data/reference-data.service.ts | 2 +- 8 files changed, 25 insertions(+), 10 deletions(-) diff --git a/biome.json b/biome.json index 6b3cac680e..4a2ba9d10a 100644 --- a/biome.json +++ b/biome.json @@ -17,7 +17,6 @@ }, "correctness": { "noInvalidUseBeforeDeclaration": "off", - "noVoidTypeReturn": "off", "noSwitchDeclarations": "off" }, "performance": { diff --git a/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.ts b/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.ts index 3bfad24248..1ca0698bcc 100644 --- a/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.ts +++ b/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.ts @@ -75,12 +75,15 @@ export class AdrGenerateCertificateComponent implements OnInit, OnDestroy { handleSubmit(): void { this.globalErrorService.clearErrors(); + if (!this.form.value.certificateType) { - return this.globalErrorService.addError({ + this.globalErrorService.addError({ error: 'ADR Certificate Type is required', anchorLink: 'certificateType', }); + return; } + this.store.dispatch( generateADRCertificate({ systemNumber: this.systemNumber ?? '', diff --git a/src/app/features/tech-record/components/tech-record-change-type/tech-record-change-type.component.ts b/src/app/features/tech-record/components/tech-record-change-type/tech-record-change-type.component.ts index 373e44d106..dd2d2dc462 100644 --- a/src/app/features/tech-record/components/tech-record-change-type/tech-record-change-type.component.ts +++ b/src/app/features/tech-record/components/tech-record-change-type/tech-record-change-type.component.ts @@ -74,9 +74,10 @@ export class ChangeVehicleTypeComponent implements OnInit { handleSubmit(selectedVehicleType: VehicleTypes): void { if (!selectedVehicleType) { - return this.globalErrorService.setErrors([ + this.globalErrorService.setErrors([ { error: 'You must provide a new vehicle type', anchorLink: 'selectedVehicleType' }, ]); + return; } if ( @@ -84,12 +85,13 @@ export class ChangeVehicleTypeComponent implements OnInit { ((this.techRecord as TechRecordTypeByVehicle<'trl'>)?.techRecord_euVehicleCategory === EUVehicleCategory.O1 || (this.techRecord as TechRecordTypeByVehicle<'trl'>)?.techRecord_euVehicleCategory === EUVehicleCategory.O2) ) { - return this.globalErrorService.setErrors([ + this.globalErrorService.setErrors([ { error: "You cannot change vehicle type to TRL when EU vehicle category is set to 'O1' or 'O2'", anchorLink: 'selectedVehicleType', }, ]); + return; } this.store.dispatch(changeVehicleType({ techRecord_vehicleType: selectedVehicleType })); diff --git a/src/app/features/tech-record/components/tech-record-generate-letter/tech-record-generate-letter.component.ts b/src/app/features/tech-record/components/tech-record-generate-letter/tech-record-generate-letter.component.ts index 0161005f92..77ec56becc 100644 --- a/src/app/features/tech-record/components/tech-record-generate-letter/tech-record-generate-letter.component.ts +++ b/src/app/features/tech-record/components/tech-record-generate-letter/tech-record-generate-letter.component.ts @@ -86,11 +86,15 @@ export class GenerateLetterComponent implements OnInit { handleSubmit(): void { this.globalErrorService.clearErrors(); + if (this.form.value.letterType === '') { - return this.globalErrorService.addError({ error: 'Letter type is required', anchorLink: 'letterType' }); + this.globalErrorService.addError({ error: 'Letter type is required', anchorLink: 'letterType' }); + return; } + if (!this.techRecord) { - return this.globalErrorService.addError({ error: 'Could not retrieve current technical record' }); + this.globalErrorService.addError({ error: 'Could not retrieve current technical record' }); + return; } const paragraphId = diff --git a/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.ts b/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.ts index d329add78c..8ef15a6de0 100644 --- a/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.ts +++ b/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.ts @@ -87,12 +87,15 @@ export class GeneratePlateComponent implements OnInit { handleSubmit(): void { this.globalErrorService.clearErrors(); + if (!this.form.value.reason) { - return this.globalErrorService.addError({ + this.globalErrorService.addError({ error: 'Reason for generating plate is required', anchorLink: 'reason', }); + return; } + this.store.dispatch(generatePlate({ reason: this.form.value.reason })); this.store.dispatch(cannotGeneratePlate()); } diff --git a/src/app/features/tech-record/create-batch/components/batch-vehicle-template/batch-vehicle-template.component.ts b/src/app/features/tech-record/create-batch/components/batch-vehicle-template/batch-vehicle-template.component.ts index 4a7d7933d0..ab8d0891ec 100644 --- a/src/app/features/tech-record/create-batch/components/batch-vehicle-template/batch-vehicle-template.component.ts +++ b/src/app/features/tech-record/create-batch/components/batch-vehicle-template/batch-vehicle-template.component.ts @@ -90,7 +90,7 @@ export class BatchVehicleTemplateComponent { } statusChange(): void { - return this.batchTechRecordService.setVehicleStatus(this.form.get('vehicleStatus')?.value); + this.batchTechRecordService.setVehicleStatus(this.form.get('vehicleStatus')?.value); } get isVehicleStatusValid(): boolean { diff --git a/src/app/forms/components/checkbox-group/checkbox-group.component.ts b/src/app/forms/components/checkbox-group/checkbox-group.component.ts index 10e7119ff7..867678772b 100644 --- a/src/app/forms/components/checkbox-group/checkbox-group.component.ts +++ b/src/app/forms/components/checkbox-group/checkbox-group.component.ts @@ -24,7 +24,11 @@ export class CheckboxGroupComponent extends BaseControlComponent { } handleChange(event: boolean, option: FormNodeOption): void { - return event ? this.add(option) : this.remove(option); + if (event) { + this.add(option); + } else { + this.remove(option); + } } private add(option: FormNodeOption) { diff --git a/src/app/services/reference-data/reference-data.service.ts b/src/app/services/reference-data/reference-data.service.ts index 5aef4fd692..c433257227 100644 --- a/src/app/services/reference-data/reference-data.service.ts +++ b/src/app/services/reference-data/reference-data.service.ts @@ -129,7 +129,7 @@ export class ReferenceDataService extends ReferenceDataApiService { } loadReferenceDataByKey(resourceType: ReferenceDataResourceType, resourceKey: string | number): void { - return this.store.dispatch(fetchReferenceDataByKey({ resourceType, resourceKey })); + this.store.dispatch(fetchReferenceDataByKey({ resourceType, resourceKey })); } fetchReferenceDataByKeySearch( From aceeb0a3acb00fb97e3a75a29a1d3821b3fb658e Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Tue, 13 Aug 2024 16:09:06 +0100 Subject: [PATCH 09/21] chore(linting-1): enable no assign in expressions --- biome.json | 1 - .../api/document-retrieval/api/document-retrieval.service.ts | 4 +++- .../feature-toggle-service/feature-toggle-service.ts | 4 ++-- .../reducers/technical-record-service.reducer.ts | 5 +++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/biome.json b/biome.json index 4a2ba9d10a..00c1954cbb 100644 --- a/biome.json +++ b/biome.json @@ -23,7 +23,6 @@ "noDelete": "off" }, "suspicious": { - "noAssignInExpressions": "off", "noDoubleEquals": "off", "noDuplicateTestHooks": "off", "noExplicitAny": "off", diff --git a/src/app/api/document-retrieval/api/document-retrieval.service.ts b/src/app/api/document-retrieval/api/document-retrieval.service.ts index 74b5345c6a..a35c44cae5 100644 --- a/src/app/api/document-retrieval/api/document-retrieval.service.ts +++ b/src/app/api/document-retrieval/api/document-retrieval.service.ts @@ -198,7 +198,9 @@ export class DocumentRetrievalService { let params = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); - paramMap.forEach((value, key) => (params = params.set(key, value))); + paramMap.forEach((value, key) => { + params = params.set(key, value); + }); return this.httpClient.get(`${this.basePath}/v1/document-retrieval`, { headers, diff --git a/src/app/services/feature-toggle-service/feature-toggle-service.ts b/src/app/services/feature-toggle-service/feature-toggle-service.ts index 21c930a63a..cd118db15d 100644 --- a/src/app/services/feature-toggle-service/feature-toggle-service.ts +++ b/src/app/services/feature-toggle-service/feature-toggle-service.ts @@ -18,8 +18,8 @@ export class FeatureToggleService { constructor(private http: HttpClient) {} async loadConfig() { - // eslint-disable-next-line no-return-assign - return (this.config = await lastValueFrom(this.http.get(this.configPath).pipe(take(1)))); + this.config = await lastValueFrom(this.http.get(this.configPath).pipe(take(1))); + return this.config; } getConfig() { diff --git a/src/app/store/technical-records/reducers/technical-record-service.reducer.ts b/src/app/store/technical-records/reducers/technical-record-service.reducer.ts index 26c805c29d..e28bf589f1 100644 --- a/src/app/store/technical-records/reducers/technical-record-service.reducer.ts +++ b/src/app/store/technical-records/reducers/technical-record-service.reducer.ts @@ -353,8 +353,9 @@ function handleRemoveAxle(state: TechnicalRecordServiceState, action: { index: n newState.editingTechRecord.techRecord_axles.splice(action.index, 1); - // eslint-disable-next-line no-return-assign - newState.editingTechRecord.techRecord_axles.forEach((axle, i) => (axle.axleNumber = i + 1)); + newState.editingTechRecord.techRecord_axles.forEach((axle, i) => { + axle.axleNumber = i + 1; + }); newState.editingTechRecord.techRecord_noOfAxles = newState.editingTechRecord.techRecord_axles.length; From 0429d40b1770cc3b57653daf560a7b60c1cea188 Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Tue, 13 Aug 2024 16:11:34 +0100 Subject: [PATCH 10/21] chore(linting-1): enable no invalid use before declaration --- biome.json | 1 - src/app/forms/services/dynamic-form.types.ts | 78 ++++++++++---------- 2 files changed, 39 insertions(+), 40 deletions(-) diff --git a/biome.json b/biome.json index 00c1954cbb..b0aa789850 100644 --- a/biome.json +++ b/biome.json @@ -16,7 +16,6 @@ "useRegexLiterals": "off" }, "correctness": { - "noInvalidUseBeforeDeclaration": "off", "noSwitchDeclarations": "off" }, "performance": { diff --git a/src/app/forms/services/dynamic-form.types.ts b/src/app/forms/services/dynamic-form.types.ts index 1741082f66..cf823cfa79 100644 --- a/src/app/forms/services/dynamic-form.types.ts +++ b/src/app/forms/services/dynamic-form.types.ts @@ -25,6 +25,45 @@ import { Observable, map } from 'rxjs'; import { DynamicFormService } from './dynamic-form.service'; import { SpecialRefData } from './multi-options.service'; +// TODO: clean this +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const cleanValue = (form: CustomFormGroup | CustomFormArray): Record | Array<[]> => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const localCleanValue = form instanceof CustomFormArray ? [] : ({} as Record); + Object.keys(form.controls).forEach((key) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any, security/detect-object-injection + const control = (form.controls as any)[key]; + if (control instanceof CustomFormGroup && control.meta.type === FormNodeTypes.GROUP) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any, security/detect-object-injection + (localCleanValue as any)[key] = objectOrNull(control.getCleanValue(control)); + } else if (control instanceof CustomFormArray) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any, security/detect-object-injection + (localCleanValue as any)[key] = control.getCleanValue(control); + } else if (control instanceof CustomFormControl && control.meta.type === FormNodeTypes.CONTROL) { + if (control.meta.required && control.meta.hide) { + pushOrAssignAt(control.meta.value || null, localCleanValue, key); + } else if (!control.meta.hide) { + pushOrAssignAt(control.value, localCleanValue, key); + } + } + }); + + return localCleanValue; +}; + +function objectOrNull(obj: Object) { + return Object.values(obj).some((value) => undefined !== value) ? obj : null; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function pushOrAssignAt(value: any, localCleanValue: Array<[]> | Record, key: string) { + if (Array.isArray(localCleanValue)) { + localCleanValue.push(value); + } else { + localCleanValue[`${key}`] = value; + } +} + export enum FormNodeViewTypes { DATE = 'date', DATETIME = 'dateTime', @@ -265,42 +304,3 @@ export class CustomFormArray extends FormArray implements CustomArray, BaseForm } } } - -// TODO: clean this -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const cleanValue = (form: CustomFormGroup | CustomFormArray): Record | Array<[]> => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const localCleanValue = form instanceof CustomFormArray ? [] : ({} as Record); - Object.keys(form.controls).forEach((key) => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any, security/detect-object-injection - const control = (form.controls as any)[key]; - if (control instanceof CustomFormGroup && control.meta.type === FormNodeTypes.GROUP) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any, security/detect-object-injection - (localCleanValue as any)[key] = objectOrNull(control.getCleanValue(control)); - } else if (control instanceof CustomFormArray) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any, security/detect-object-injection - (localCleanValue as any)[key] = control.getCleanValue(control); - } else if (control instanceof CustomFormControl && control.meta.type === FormNodeTypes.CONTROL) { - if (control.meta.required && control.meta.hide) { - pushOrAssignAt(control.meta.value || null, localCleanValue, key); - } else if (!control.meta.hide) { - pushOrAssignAt(control.value, localCleanValue, key); - } - } - }); - - return localCleanValue; -}; - -function objectOrNull(obj: Object) { - return Object.values(obj).some((value) => undefined !== value) ? obj : null; -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function pushOrAssignAt(value: any, localCleanValue: Array<[]> | Record, key: string) { - if (Array.isArray(localCleanValue)) { - localCleanValue.push(value); - } else { - localCleanValue[`${key}`] = value; - } -} From 60ae90a078b6a41a7f2a6baf06bfdbe074070e9f Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Tue, 13 Aug 2024 16:12:43 +0100 Subject: [PATCH 11/21] chore(linting-1): enable no switch declarations --- biome.json | 3 --- .../forms/components/defect-select/defect-select.component.ts | 4 +++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/biome.json b/biome.json index b0aa789850..90b55d6b2a 100644 --- a/biome.json +++ b/biome.json @@ -15,9 +15,6 @@ "useLiteralKeys": "off", "useRegexLiterals": "off" }, - "correctness": { - "noSwitchDeclarations": "off" - }, "performance": { "noDelete": "off" }, diff --git a/src/app/forms/components/defect-select/defect-select.component.ts b/src/app/forms/components/defect-select/defect-select.component.ts index 59b3c737ff..4eef17b02f 100644 --- a/src/app/forms/components/defect-select/defect-select.component.ts +++ b/src/app/forms/components/defect-select/defect-select.component.ts @@ -96,8 +96,9 @@ export class DefectSelectComponent implements OnInit, OnDestroy { queryParamsHandling: 'merge', }); break; - default: + default: { let advisoryRoute = `${this.selectedDefect?.imNumber}.${this.selectedItem?.itemNumber}.advisory`; + if (this.selectedDefect?.imNumber === 71 && this.selectedItem?.itemNumber === 1) { advisoryRoute += this.selectedItem.itemDescription === 'All Roller Brake Test Machines:' ? '.0' : '.1'; } @@ -107,6 +108,7 @@ export class DefectSelectComponent implements OnInit, OnDestroy { queryParamsHandling: 'merge', }); break; + } } } } From 64c2e38892e0334e9ea5be6c10dcb5681b516281 Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Tue, 13 Aug 2024 16:13:17 +0100 Subject: [PATCH 12/21] chore(linting-1): enable no prototype builtins --- biome.json | 1 - 1 file changed, 1 deletion(-) diff --git a/biome.json b/biome.json index 90b55d6b2a..1fed16ac44 100644 --- a/biome.json +++ b/biome.json @@ -23,7 +23,6 @@ "noDuplicateTestHooks": "off", "noExplicitAny": "off", "noImplicitAnyLet": "off", - "noPrototypeBuiltins": "off", "useValidTypeof": "off" }, "style": { From 351875b0479679134d3e5e1135674e4ca60f7a6b Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Tue, 13 Aug 2024 16:21:29 +0100 Subject: [PATCH 13/21] chore(linting-1): enable no parameter assign --- biome.json | 3 +-- src/app/api/document-retrieval/encoder.ts | 11 +++++----- src/app/api/reference-data/encoder.ts | 11 +++++----- src/app/api/test-results/encoder.ts | 9 +++++---- src/app/api/test-types/encoder.ts | 9 +++++---- src/app/api/vehicle/encoder.ts | 11 +++++----- src/app/features/search/search.component.ts | 7 ++++--- .../forms/services/dynamic-form.service.ts | 5 ++--- src/app/forms/validators/custom-validators.ts | 6 ++++-- .../ref-data-decode/ref-data-decode.pipe.ts | 20 ++++++++++--------- .../store/defects/actions/defects.actions.ts | 4 ++-- .../actions/tech-record-search.actions.ts | 4 ++-- .../actions/test-stations.actions.ts | 4 ++-- 13 files changed, 56 insertions(+), 48 deletions(-) diff --git a/biome.json b/biome.json index 1fed16ac44..9fbb51786e 100644 --- a/biome.json +++ b/biome.json @@ -26,8 +26,7 @@ "useValidTypeof": "off" }, "style": { - "noNonNullAssertion": "off", - "noParameterAssign": "off" + "noNonNullAssertion": "off" } } } diff --git a/src/app/api/document-retrieval/encoder.ts b/src/app/api/document-retrieval/encoder.ts index 233fb78e4a..1d5c24dfd9 100644 --- a/src/app/api/document-retrieval/encoder.ts +++ b/src/app/api/document-retrieval/encoder.ts @@ -1,4 +1,4 @@ -import { HttpUrlEncodingCodec } from '@angular/common/http'; +import {HttpUrlEncodingCodec} from '@angular/common/http'; /** * CustomHttpUrlEncodingCodec @@ -6,12 +6,13 @@ import { HttpUrlEncodingCodec } from '@angular/common/http'; * See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 */ export class CustomHttpUrlEncodingCodec extends HttpUrlEncodingCodec { - override encodeKey(k: string): string { - k = super.encodeKey(k); + override encodeKey(key: string): string { + const k = super.encodeKey(key); return k.replace(/\+/gi, '%2B'); } - override encodeValue(v: string): string { - v = super.encodeValue(v); + + override encodeValue(value: string): string { + const v = super.encodeValue(value); return v.replace(/\+/gi, '%2B'); } } diff --git a/src/app/api/reference-data/encoder.ts b/src/app/api/reference-data/encoder.ts index 233fb78e4a..1d5c24dfd9 100644 --- a/src/app/api/reference-data/encoder.ts +++ b/src/app/api/reference-data/encoder.ts @@ -1,4 +1,4 @@ -import { HttpUrlEncodingCodec } from '@angular/common/http'; +import {HttpUrlEncodingCodec} from '@angular/common/http'; /** * CustomHttpUrlEncodingCodec @@ -6,12 +6,13 @@ import { HttpUrlEncodingCodec } from '@angular/common/http'; * See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 */ export class CustomHttpUrlEncodingCodec extends HttpUrlEncodingCodec { - override encodeKey(k: string): string { - k = super.encodeKey(k); + override encodeKey(key: string): string { + const k = super.encodeKey(key); return k.replace(/\+/gi, '%2B'); } - override encodeValue(v: string): string { - v = super.encodeValue(v); + + override encodeValue(value: string): string { + const v = super.encodeValue(value); return v.replace(/\+/gi, '%2B'); } } diff --git a/src/app/api/test-results/encoder.ts b/src/app/api/test-results/encoder.ts index 233fb78e4a..b80138427a 100644 --- a/src/app/api/test-results/encoder.ts +++ b/src/app/api/test-results/encoder.ts @@ -6,12 +6,13 @@ import { HttpUrlEncodingCodec } from '@angular/common/http'; * See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 */ export class CustomHttpUrlEncodingCodec extends HttpUrlEncodingCodec { - override encodeKey(k: string): string { - k = super.encodeKey(k); + override encodeKey(key: string): string { + const k = super.encodeKey(key); return k.replace(/\+/gi, '%2B'); } - override encodeValue(v: string): string { - v = super.encodeValue(v); + + override encodeValue(value: string): string { + const v = super.encodeValue(value); return v.replace(/\+/gi, '%2B'); } } diff --git a/src/app/api/test-types/encoder.ts b/src/app/api/test-types/encoder.ts index 233fb78e4a..b80138427a 100644 --- a/src/app/api/test-types/encoder.ts +++ b/src/app/api/test-types/encoder.ts @@ -6,12 +6,13 @@ import { HttpUrlEncodingCodec } from '@angular/common/http'; * See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 */ export class CustomHttpUrlEncodingCodec extends HttpUrlEncodingCodec { - override encodeKey(k: string): string { - k = super.encodeKey(k); + override encodeKey(key: string): string { + const k = super.encodeKey(key); return k.replace(/\+/gi, '%2B'); } - override encodeValue(v: string): string { - v = super.encodeValue(v); + + override encodeValue(value: string): string { + const v = super.encodeValue(value); return v.replace(/\+/gi, '%2B'); } } diff --git a/src/app/api/vehicle/encoder.ts b/src/app/api/vehicle/encoder.ts index 233fb78e4a..1d5c24dfd9 100644 --- a/src/app/api/vehicle/encoder.ts +++ b/src/app/api/vehicle/encoder.ts @@ -1,4 +1,4 @@ -import { HttpUrlEncodingCodec } from '@angular/common/http'; +import {HttpUrlEncodingCodec} from '@angular/common/http'; /** * CustomHttpUrlEncodingCodec @@ -6,12 +6,13 @@ import { HttpUrlEncodingCodec } from '@angular/common/http'; * See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 */ export class CustomHttpUrlEncodingCodec extends HttpUrlEncodingCodec { - override encodeKey(k: string): string { - k = super.encodeKey(k); + override encodeKey(key: string): string { + const k = super.encodeKey(key); return k.replace(/\+/gi, '%2B'); } - override encodeValue(v: string): string { - v = super.encodeValue(v); + + override encodeValue(value: string): string { + const v = super.encodeValue(value); return v.replace(/\+/gi, '%2B'); } } diff --git a/src/app/features/search/search.component.ts b/src/app/features/search/search.component.ts index cba92aacbd..cea2f14f62 100644 --- a/src/app/features/search/search.component.ts +++ b/src/app/features/search/search.component.ts @@ -27,14 +27,15 @@ export class SearchComponent { this.globalErrorService.clearErrors(); this.store.dispatch(clearAllSectionStates()); this.store.dispatch(clearScrollPosition()); - term = term.trim(); - if (!term) { + const formattedTerm = term.trim(); + + if (!formattedTerm) { this.globalErrorService.addError({ error: this.missingTermErrorMessage, anchorLink: 'search-term' }); } else if (!Object.values(SEARCH_TYPES).includes(type as SEARCH_TYPES)) { this.globalErrorService.addError({ error: this.missingTypeErrorMessage, anchorLink: 'search-type' }); } else { - void this.router.navigate(['/search/results'], { queryParams: { [type]: term } }); + void this.router.navigate(['/search/results'], { queryParams: { [type]: formattedTerm } }); } } diff --git a/src/app/forms/services/dynamic-form.service.ts b/src/app/forms/services/dynamic-form.service.ts index 6bc01f6fd7..404b55d971 100644 --- a/src/app/forms/services/dynamic-form.service.ts +++ b/src/app/forms/services/dynamic-form.service.ts @@ -125,8 +125,7 @@ export class DynamicFormService { [AsyncValidatorNames.Custom]: (...args) => CustomAsyncValidators.custom(this.store, ...args), }; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - createForm(formNode: FormNode, data?: any): CustomFormGroup | CustomFormArray { + createForm(formNode: FormNode, originalData?: any): CustomFormGroup | CustomFormArray { if (!formNode) { return new CustomFormGroup(formNode, {}); } @@ -136,7 +135,7 @@ export class DynamicFormService { ? new CustomFormArray(formNode, [], this.store) : new CustomFormGroup(formNode, {}); - data = data ?? (formNode.type === FormNodeTypes.ARRAY ? [] : {}); + const data = originalData ?? (formNode.type === FormNodeTypes.ARRAY ? [] : {}); formNode.children?.forEach((child) => { const { name, type, value, validators, asyncValidators, disabled } = child; diff --git a/src/app/forms/validators/custom-validators.ts b/src/app/forms/validators/custom-validators.ts index 3d3b91b1f4..6f3ff0fb5f 100644 --- a/src/app/forms/validators/custom-validators.ts +++ b/src/app/forms/validators/custom-validators.ts @@ -400,10 +400,12 @@ export class CustomValidators { checkEnum: Record, options: Partial = {} ): ValidatorFn => { - options = { allowFalsy: false, ...options }; + const opts = { allowFalsy: false, ...options }; return (control: AbstractControl): ValidationErrors | null => { - if (options.allowFalsy && !control.value) return null; + if (opts.allowFalsy && !control.value) { + return null; + } return Object.values(checkEnum).includes(control.value) ? null : { enum: true }; }; }; diff --git a/src/app/shared/pipes/ref-data-decode/ref-data-decode.pipe.ts b/src/app/shared/pipes/ref-data-decode/ref-data-decode.pipe.ts index 9e972bb656..88f81388c4 100644 --- a/src/app/shared/pipes/ref-data-decode/ref-data-decode.pipe.ts +++ b/src/app/shared/pipes/ref-data-decode/ref-data-decode.pipe.ts @@ -39,44 +39,46 @@ export class RefDataDecodePipe implements PipeTransform, OnDestroy { return of(value); } - if (resourceType === SpecialRefData.ReasonsForAbandoning) { + let calculatedResourceType = resourceType; + + if (calculatedResourceType === SpecialRefData.ReasonsForAbandoning) { this.store .select(getSingleVehicleType) .pipe(take(1)) .subscribe((vehicleType) => { switch (vehicleType) { case VehicleTypes.HGV: - resourceType = ReferenceDataResourceType.ReasonsForAbandoningHgv; + calculatedResourceType = ReferenceDataResourceType.ReasonsForAbandoningHgv; break; case VehicleTypes.PSV: - resourceType = ReferenceDataResourceType.ReasonsForAbandoningPsv; + calculatedResourceType = ReferenceDataResourceType.ReasonsForAbandoningPsv; break; case VehicleTypes.TRL: - resourceType = ReferenceDataResourceType.ReasonsForAbandoningTrl; + calculatedResourceType = ReferenceDataResourceType.ReasonsForAbandoningTrl; break; default: - resourceType = ReferenceDataResourceType.ReasonsForAbandoningHgv; + calculatedResourceType = ReferenceDataResourceType.ReasonsForAbandoningHgv; break; } }); } asapScheduler.schedule(() => { - this.store.dispatch(fetchReferenceData({ resourceType: resourceType as ReferenceDataResourceType })); + this.store.dispatch(fetchReferenceData({ resourceType: calculatedResourceType as ReferenceDataResourceType })); }); asapScheduler.schedule(() => { this.store.dispatch( fetchReferenceDataByKeySearch({ - resourceType: `${resourceType}#AUDIT` as ReferenceDataResourceType, + resourceType: `${calculatedResourceType}#AUDIT` as ReferenceDataResourceType, resourceKey: `${value}#`, }) ); }); return combineLatest([ - this.store.select(selectReferenceDataByResourceKey(resourceType as ReferenceDataResourceType, value)), - this.store.select(selectSearchReturn(`${resourceType}#AUDIT` as ReferenceDataResourceTypeAudit)), + this.store.select(selectReferenceDataByResourceKey(calculatedResourceType as ReferenceDataResourceType, value)), + this.store.select(selectSearchReturn(`${calculatedResourceType}#AUDIT` as ReferenceDataResourceTypeAudit)), ]).pipe( map(([refDataItem, refDataItemAudit]) => { if (!refDataItem) { diff --git a/src/app/store/defects/actions/defects.actions.ts b/src/app/store/defects/actions/defects.actions.ts index b2d49ae7e5..73226bc7f9 100644 --- a/src/app/store/defects/actions/defects.actions.ts +++ b/src/app/store/defects/actions/defects.actions.ts @@ -12,6 +12,6 @@ export const fetchDefectFailed = createAction(getTitle(false, 'Failed'), props()); function getTitle(suffix = ''): string { - suffix = suffix ? ` ${suffix}` : suffix; - return `[API/tech-records search] Search Results ${suffix}`; + const title = suffix ? ` ${suffix}` : suffix; + return `[API/tech-records search] Search Results ${title}`; } diff --git a/src/app/store/test-stations/actions/test-stations.actions.ts b/src/app/store/test-stations/actions/test-stations.actions.ts index 42d6128c83..6cceb1495b 100644 --- a/src/app/store/test-stations/actions/test-stations.actions.ts +++ b/src/app/store/test-stations/actions/test-stations.actions.ts @@ -15,6 +15,6 @@ export const fetchTestStationFailed = createAction(getTitle(false, 'Failed'), pr function getTitle(isPlural = false, suffix = ''): string { const plural = isPlural ? 's' : ' by ID'; - suffix = suffix ? ` ${suffix}` : suffix; - return `[API/test-stations] Fetch Test Station${plural}${suffix}`; + const title = suffix ? ` ${suffix}` : suffix; + return `[API/test-stations] Fetch Test Station${plural}${title}`; } From a1351f2072097a00d753d568f9614442325e7cdb Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Tue, 13 Aug 2024 16:35:34 +0100 Subject: [PATCH 14/21] chore(linting-1): enable no non null assertion --- biome.json | 3 -- .../select-vehicle-type.component.ts | 6 ++-- .../defect/defect.component.ts | 7 +++-- .../dimensions/dimensions.component.ts | 3 +- .../required-standard.component.ts | 10 ++++--- .../technical-record-service.reducer.spec.ts | 2 +- .../technical-record-service.reducer.ts | 12 ++++---- .../effects/test-records.effects.ts | 29 +++++++++++-------- .../selectors/test-types.selectors.ts | 6 ++-- 9 files changed, 41 insertions(+), 37 deletions(-) diff --git a/biome.json b/biome.json index 9fbb51786e..03b4620c81 100644 --- a/biome.json +++ b/biome.json @@ -24,9 +24,6 @@ "noExplicitAny": "off", "noImplicitAnyLet": "off", "useValidTypeof": "off" - }, - "style": { - "noNonNullAssertion": "off" } } } diff --git a/src/app/features/tech-record/create-batch/components/select-vehicle-type/select-vehicle-type.component.ts b/src/app/features/tech-record/create-batch/components/select-vehicle-type/select-vehicle-type.component.ts index 196ad264a4..bb05600577 100644 --- a/src/app/features/tech-record/create-batch/components/select-vehicle-type/select-vehicle-type.component.ts +++ b/src/app/features/tech-record/create-batch/components/select-vehicle-type/select-vehicle-type.component.ts @@ -88,11 +88,13 @@ export class SelectVehicleTypeComponent { this.store .select(selectTechRecord) .pipe(take(1)) - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion .subscribe( (vehicle) => !vehicle && - this.trs.updateEditingTechRecord({ ...vehicle!, techRecord_vehicleType: type } as TechRecordType<'put'>) + this.trs.updateEditingTechRecord({ + ...(vehicle || {}), + techRecord_vehicleType: type, + } as TechRecordType<'put'>) ); this.trs.generateEditingVehicleTechnicalRecordFromVehicleType(type); diff --git a/src/app/forms/custom-sections/defect/defect.component.ts b/src/app/forms/custom-sections/defect/defect.component.ts index 270dee2d2b..240e0a8fa1 100644 --- a/src/app/forms/custom-sections/defect/defect.component.ts +++ b/src/app/forms/custom-sections/defect/defect.component.ts @@ -84,7 +84,7 @@ export class DefectComponent implements OnInit, OnDestroy { this.index = Number(defectIndexValue); this.form = this.defectsForm.controls[this.index] as CustomFormGroup; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.defect = this.defects![this.index]; + this.defect = this.defects?.[this.index]; } else if (defectRefValue && this.vehicleType) { this.store .select(selectByDeficiencyRef(defectRefValue, this.vehicleType)) @@ -182,12 +182,13 @@ export class DefectComponent implements OnInit, OnDestroy { if (info) { type LocationKey = keyof typeof info.location; - Object.keys(info.location).forEach((key) => { + for (const key of Object.keys(info.location)) { const options = info?.location[key as LocationKey]; + if (options) { this.infoDictionary[`${key}`] = this.mapOptions(options); } - }); + } } } diff --git a/src/app/forms/custom-sections/dimensions/dimensions.component.ts b/src/app/forms/custom-sections/dimensions/dimensions.component.ts index 79dc58a25a..05012bb523 100644 --- a/src/app/forms/custom-sections/dimensions/dimensions.component.ts +++ b/src/app/forms/custom-sections/dimensions/dimensions.component.ts @@ -31,8 +31,7 @@ export class DimensionsComponent implements OnInit, OnChanges, OnDestroy { constructor(private dfs: DynamicFormService) {} ngOnInit(): void { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.form = this.dfs.createForm(this.template!, this.techRecord) as CustomFormGroup; + this.form = this.dfs.createForm(this.template as FormNode, this.techRecord) as CustomFormGroup; this.form.cleanValueChanges .pipe(debounceTime(400), takeUntil(this.destroy$)) diff --git a/src/app/forms/custom-sections/required-standard/required-standard.component.ts b/src/app/forms/custom-sections/required-standard/required-standard.component.ts index 4d8f112977..5837e224fc 100644 --- a/src/app/forms/custom-sections/required-standard/required-standard.component.ts +++ b/src/app/forms/custom-sections/required-standard/required-standard.component.ts @@ -81,13 +81,15 @@ export class RequiredStandardComponent implements OnInit, OnDestroy { takeUntil(this.onDestroy$) ) .subscribe((requiredStandard) => { - if (!requiredStandard) this.navigateBack(); + if (!requiredStandard) { + this.navigateBack(); + } + const rsControl = { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - ...requiredStandard!, + ...(requiredStandard || {}), prs: false, additionalNotes: '', - }; + } as TestResultRequiredStandard; this.requiredStandard = rsControl; this.requiredStandardForm?.addControl(rsControl); diff --git a/src/app/store/technical-records/reducers/technical-record-service.reducer.spec.ts b/src/app/store/technical-records/reducers/technical-record-service.reducer.spec.ts index 8d2ae2ccc4..207d4d8ab9 100644 --- a/src/app/store/technical-records/reducers/technical-record-service.reducer.spec.ts +++ b/src/app/store/technical-records/reducers/technical-record-service.reducer.spec.ts @@ -687,7 +687,7 @@ describe('Vehicle Technical Record Reducer', () => { const action = updateExistingADRAdditionalExaminerNote({ additionalExaminerNote: newNote, examinerNoteIndex: 0 }); const newState = vehicleTechRecordReducer(state, action); const editingTechRecord = newState.editingTechRecord as unknown as NonVerbTechRecordType<'hgv' | 'lgv' | 'trl'>; - expect(editingTechRecord.techRecord_adrDetails_additionalExaminerNotes![0].note).toEqual(newNote); + expect(editingTechRecord.techRecord_adrDetails_additionalExaminerNotes?.[0].note).toEqual(newNote); }); }); }); diff --git a/src/app/store/technical-records/reducers/technical-record-service.reducer.ts b/src/app/store/technical-records/reducers/technical-record-service.reducer.ts index e28bf589f1..b8b2b61fe1 100644 --- a/src/app/store/technical-records/reducers/technical-record-service.reducer.ts +++ b/src/app/store/technical-records/reducers/technical-record-service.reducer.ts @@ -230,11 +230,8 @@ function handleUpdateBrakeForces( if (data.grossLadenWeight) { const prefix = `${Math.round(data.grossLadenWeight / 100)}`; - newState.editingTechRecord.techRecord_brakes_brakeCode = - (prefix.length <= 2 - ? `0${prefix}` - : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - prefix) + newState.editingTechRecord.techRecord_brakes_brakeCodeOriginal!; + newState.editingTechRecord.techRecord_brakes_brakeCode = ((prefix.length <= 2 ? `0${prefix}` : prefix) + + newState.editingTechRecord.techRecord_brakes_brakeCodeOriginal) as string; newState.editingTechRecord.techRecord_brakes_brakeForceWheelsNotLocked_serviceBrakeForceA = Math.round( (data.grossLadenWeight * 16) / 100 ); @@ -606,7 +603,10 @@ function handleUpdateExistingADRExaminerNote( const editedTechRecord = editingTechRecord as unknown as NonVerbTechRecordType<'hgv' | 'lgv' | 'trl'>; if (editedTechRecord) { const examinerNotes = editedTechRecord.techRecord_adrDetails_additionalExaminerNotes; - examinerNotes![action.examinerNoteIndex].note = action.additionalExaminerNote; + + if (examinerNotes) { + examinerNotes[action.examinerNoteIndex].note = action.additionalExaminerNote; + } } return { ...state, editingTechRecord: editingTechRecord as unknown as TechRecordType<'put'> }; } diff --git a/src/app/store/test-records/effects/test-records.effects.ts b/src/app/store/test-records/effects/test-records.effects.ts index 1fd6ebe83f..19adbbcdad 100644 --- a/src/app/store/test-records/effects/test-records.effects.ts +++ b/src/app/store/test-records/effects/test-records.effects.ts @@ -3,6 +3,7 @@ import { Router } from '@angular/router'; import { GlobalError } from '@core/components/global-error/global-error.interface'; import { TEST_TYPES } from '@forms/models/testTypeId.enum'; import { DynamicFormService } from '@forms/services/dynamic-form.service'; +import { FormNode } from '@forms/services/dynamic-form.types'; import { contingencyTestTemplates } from '@forms/templates/test-records/create-master.template'; import { masterTpl } from '@forms/templates/test-records/master.template'; import { TestResultModel } from '@models/test-results/test-result.model'; @@ -203,31 +204,35 @@ export class TestResultsEffects { concatMap(([action, selectedTestResult, isEditing, isOldIVAorMSVAtest]) => { const { testTypeId } = action; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const { vehicleType } = selectedTestResult!; + const { vehicleType } = selectedTestResult ?? {}; + if (!vehicleType || !Object.prototype.hasOwnProperty.call(masterTpl, vehicleType)) { return of(templateSectionsChanged({ sectionTemplates: [], sectionsValue: undefined })); } + const testTypeGroup = TestRecordsService.getTestTypeGroup(testTypeId); // tech-debt: feature flag check to be removed when required standard is enabled const isRequiredStandardsEnabled = this.featureToggleService.isFeatureEnabled('requiredStandards'); + const isIVAorMSVATest = testTypeGroup === 'testTypesSpecialistGroup1' || testTypeGroup === 'testTypesSpecialistGroup5'; const vehicleTpl = masterTpl[`${vehicleType}`]; + const testTypeGroupString = (!isRequiredStandardsEnabled || isOldIVAorMSVAtest) && isIVAorMSVATest ? `${testTypeGroup}OldIVAorMSVA` : testTypeGroup; - let tpl; + let tpl: Record | undefined; + if (testTypeGroupString && Object.prototype.hasOwnProperty.call(vehicleTpl, testTypeGroupString)) { tpl = vehicleTpl[testTypeGroupString as keyof typeof TEST_TYPES]; } else if (isEditing === 'true') { tpl = undefined; } else { - tpl = vehicleTpl['default']; + tpl = vehicleTpl.default; } if (!tpl) { @@ -235,10 +240,11 @@ export class TestResultsEffects { } const mergedForms = {}; - Object.values(tpl).forEach((node) => { + + for (const node of Object.values(tpl)) { const form = this.dfs.createForm(node, selectedTestResult); merge(mergedForms, form.getCleanValue(form)); - }); + } if (testTypeId) { (mergedForms as TestResultModel).testTypes[0].testTypeId = testTypeId; @@ -290,14 +296,14 @@ export class TestResultsEffects { const tpl = testTypeGroupString && Object.prototype.hasOwnProperty.call(vehicleTpl, testTypeGroupString) ? vehicleTpl[testTypeGroupString as keyof typeof TEST_TYPES] - : vehicleTpl['default']; + : vehicleTpl.default; const mergedForms = {} as TestResultModel; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - Object.values(tpl!).forEach((node) => { + + for (const node of Object.values(tpl || {})) { const form = this.dfs.createForm(node, editedTestResult); merge(mergedForms, form.getCleanValue(form)); - }); + } mergedForms.testTypes[0].testTypeId = id; mergedForms.testTypes[0].name = testTypeTaxonomy?.name ?? ''; @@ -319,8 +325,7 @@ export class TestResultsEffects { mergedForms.testStationType = TestStationType.ATF; } - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - return of(templateSectionsChanged({ sectionTemplates: Object.values(tpl!), sectionsValue: mergedForms })); + return of(templateSectionsChanged({ sectionTemplates: Object.values(tpl || {}), sectionsValue: mergedForms })); }) ) ); diff --git a/src/app/store/test-types/selectors/test-types.selectors.ts b/src/app/store/test-types/selectors/test-types.selectors.ts index 6f87e14aac..7597c514e9 100644 --- a/src/app/store/test-types/selectors/test-types.selectors.ts +++ b/src/app/store/test-types/selectors/test-types.selectors.ts @@ -60,8 +60,7 @@ export const sortedTestTypes = createSelector(selectTestTypesByVehicleType, (tes const newTestType = { ...testType } as TestTypeCategory; if (Object.prototype.hasOwnProperty.call(newTestType, 'nextTestTypesOrCategories')) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - newTestType.nextTestTypesOrCategories = sortTestTypes(newTestType.nextTestTypesOrCategories!); + newTestType.nextTestTypesOrCategories = sortTestTypes(newTestType.nextTestTypesOrCategories || []); } return newTestType; @@ -179,9 +178,8 @@ function filterTestTypes( const newTestType = { ...testType } as TestTypeCategory; if (Object.prototype.hasOwnProperty.call(newTestType, 'nextTestTypesOrCategories')) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion newTestType.nextTestTypesOrCategories = filterTestTypes( - newTestType.nextTestTypesOrCategories!, + newTestType.nextTestTypesOrCategories || [], testResult, hasCurrentRecordInHistory ); From 7c4d383619c1eabab84d174bcc22f56afb706e45 Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Wed, 14 Aug 2024 08:33:23 +0100 Subject: [PATCH 15/21] chore(linting-1): enable no banned types --- biome.json | 4 +++- src/app/accessible-autocomplete.d.ts | 2 +- src/app/forms/services/dynamic-form.types.ts | 2 +- src/app/forms/utils/error-message-map.ts | 5 ++++- .../technical-record-http/technical-record-http.service.ts | 6 +++--- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/biome.json b/biome.json index 03b4620c81..9deb6a4085 100644 --- a/biome.json +++ b/biome.json @@ -3,13 +3,15 @@ "formatter": { "ignore": ["src/app/api/**"] }, + "linter": { + "ignore": ["src/app/api/**"] + }, "overrides": [ { "include": ["**/*.mock.ts", "**/*.spec.ts", "**/*.ts"], "linter": { "rules": { "complexity": { - "noBannedTypes": "off", "noForEach": "off", "noUselessConstructor": "off", "useLiteralKeys": "off", diff --git a/src/app/accessible-autocomplete.d.ts b/src/app/accessible-autocomplete.d.ts index 8975a41770..88d4bc8e35 100644 --- a/src/app/accessible-autocomplete.d.ts +++ b/src/app/accessible-autocomplete.d.ts @@ -14,7 +14,7 @@ declare module 'accessible-autocomplete/dist/accessible-autocomplete.min' { defaultValue?: string; autoselect?: boolean; showAllValues?: boolean; - dropdownArrow?: Function; + dropdownArrow?: () => unknown; } export interface AutocompleteParams extends DefaultParams, ElementParam {} diff --git a/src/app/forms/services/dynamic-form.types.ts b/src/app/forms/services/dynamic-form.types.ts index cf823cfa79..3c6b873107 100644 --- a/src/app/forms/services/dynamic-form.types.ts +++ b/src/app/forms/services/dynamic-form.types.ts @@ -51,7 +51,7 @@ const cleanValue = (form: CustomFormGroup | CustomFormArray): Record(obj: T) { return Object.values(obj).some((value) => undefined !== value) ? obj : null; } diff --git a/src/app/forms/utils/error-message-map.ts b/src/app/forms/utils/error-message-map.ts index 9f301062a7..622169df22 100644 --- a/src/app/forms/utils/error-message-map.ts +++ b/src/app/forms/utils/error-message-map.ts @@ -3,7 +3,10 @@ import { AsyncValidatorNames } from '@forms/models/async-validators.enum'; import { ValidatorNames } from '@forms/models/validators.enum'; const DEFAULT_LABEL = 'This field'; -export const ErrorMessageMap: Record = { + +type ErrorMessageFunction = (err: any, label?: string) => string; + +export const ErrorMessageMap: Record = { // Date errors invalidDate: (err: { error: boolean; reason: string; index: number }) => `${err.reason}`, invalidOption: (err: boolean, label?: string) => `${label || DEFAULT_LABEL} is invalid`, diff --git a/src/app/services/technical-record-http/technical-record-http.service.ts b/src/app/services/technical-record-http/technical-record-http.service.ts index f764d1d2a9..cc3e32874e 100644 --- a/src/app/services/technical-record-http/technical-record-http.service.ts +++ b/src/app/services/technical-record-http/technical-record-http.service.ts @@ -106,11 +106,11 @@ export class TechnicalRecordHttpService { return this.http.patch>(url, body, { responseType: 'json' }); } - generatePlate$( + generatePlate$( vehicleRecord: TechRecordType<'get'>, reason: string, user: { name?: string; email?: string } - ): Observable { + ): Observable { const url = `${environment.VTM_API_URI}/v3/technical-records/plate/${vehicleRecord.systemNumber}/${vehicleRecord.createdTimestamp}`; const body = { @@ -119,7 +119,7 @@ export class TechnicalRecordHttpService { recipientEmailAddress: vehicleRecord?.techRecord_applicantDetails_emailAddress ?? user.email, }; - return this.http.post(url, body, { responseType: 'json' }); + return this.http.post(url, body, { responseType: 'json' }); } generateLetter$( From 301d643917c11291761fded6919bbcbc22ad27c4 Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Wed, 14 Aug 2024 14:22:42 +0100 Subject: [PATCH 16/21] fix(linting-1): revert api dir --- .../api/document-retrieval.service.ts | 374 +++--- .../api/document-retrieval/configuration.ts | 136 +-- .../document-retrieval-api.module.ts | 43 +- src/app/api/document-retrieval/encoder.ts | 19 +- src/app/api/reference-data/api.module.ts | 47 +- .../api/referenceData.service.ts | 1070 ++++++++--------- src/app/api/reference-data/configuration.ts | 136 +-- src/app/api/reference-data/encoder.ts | 28 +- src/app/api/reference-data/index.ts | 2 +- .../api/reference-data/model/deleteItem.ts | 6 +- .../api/reference-data/model/emptyObject.ts | 3 +- .../model/referenceDataApiResponse.ts | 4 +- .../referenceDataApiResponseWithPagination.ts | 7 +- ...ferenceDataApiResponseWithoutPagination.ts | 6 +- .../reference-data/model/referenceDataItem.ts | 10 +- .../model/referenceDataItemApiResponse.ts | 2 +- .../api/reference-data/model/resourceKey.ts | 2 +- src/app/api/reference-data/variables.ts | 10 +- src/app/api/test-results/api.module.ts | 50 +- .../api/archiveTestResults.service.ts | 216 ++-- .../api/test-results/api/default.service.ts | 187 ++- .../api/getTestResults.service.ts | 261 ++-- .../api/updateTestResults.service.ts | 214 ++-- src/app/api/test-results/configuration.ts | 136 +-- src/app/api/test-results/encoder.ts | 17 +- src/app/api/test-results/index.ts | 2 +- .../test-results/model/completeTestResults.ts | 411 +++---- .../model/completeTestResultsVehicleClass.ts | 75 +- .../api/test-results/model/customDefect.ts | 10 +- .../api/test-results/model/customDefects.ts | 3 +- src/app/api/test-results/model/defect.ts | 50 +- .../model/defectAdditionalInformation.ts | 8 +- .../defectAdditionalInformationLocation.ts | 60 +- src/app/api/test-results/model/defects.ts | 3 +- src/app/api/test-results/model/testResults.ts | 3 +- .../api/test-results/model/testTypeRecords.ts | 3 +- .../api/test-results/model/testTypeResults.ts | 257 ++-- .../model/testTypeResultsModType.ts | 32 +- src/app/api/test-results/model/testTypes.ts | 3 +- src/app/api/test-results/variables.ts | 10 +- src/app/api/test-types/api.module.ts | 47 +- .../api/test-types/api/testTypes.service.ts | 433 +++---- src/app/api/test-types/configuration.ts | 136 +-- src/app/api/test-types/encoder.ts | 28 +- src/app/api/test-types/index.ts | 2 +- src/app/api/test-types/model/testType.ts | 176 +-- .../api/test-types/model/testTypeCategory.ts | 158 +-- src/app/api/test-types/model/testTypeInfo.ts | 30 +- .../api/test-types/model/testTypesTaxonomy.ts | 3 +- src/app/api/test-types/variables.ts | 10 +- src/app/api/vehicle/api.module.ts | 57 +- .../api/addProvisionalTechRecord.service.ts | 214 ++-- src/app/api/vehicle/api/api.ts | 8 +- .../api/archiveTechRecordStatus.service.ts | 214 ++-- .../api/vehicle/api/getTechRecords.service.ts | 235 ++-- .../vehicle/api/postTechRecords.service.ts | 188 +-- .../vehicle/api/updateTechRecords.service.ts | 234 ++-- src/app/api/vehicle/configuration.ts | 136 +-- src/app/api/vehicle/encoder.ts | 19 +- src/app/api/vehicle/index.ts | 2 +- src/app/api/vehicle/model/adrDetails.ts | 106 +- .../model/adrDetailsAdditionalNotes.ts | 20 +- .../model/adrDetailsApplicantDetails.ts | 14 +- src/app/api/vehicle/model/adrDetailsTank.ts | 8 +- .../model/adrDetailsTankTankDetails.ts | 56 +- .../adrDetailsTankTankDetailsTc2Details.ts | 36 +- .../adrDetailsTankTankDetailsTc3Details.ts | 36 +- .../model/adrDetailsTankTankStatement.ts | 44 +- .../vehicle/model/adrDetailsVehicleDetails.ts | 20 +- .../model/applicantDetailsProperties.ts | 20 +- src/app/api/vehicle/model/authIntoService.ts | 44 +- .../api/vehicle/model/axleBrakeProperties.ts | 10 +- .../api/vehicle/model/axleTyreProperties.ts | 113 +- .../api/vehicle/model/axleWeightProperties.ts | 44 +- src/app/api/vehicle/model/axles.ts | 3 +- .../model/brakeForceWheelsNotLocked.ts | 28 +- .../model/brakeForceWheelsUpToHalfLocked.ts | 28 +- src/app/api/vehicle/model/brakes.ts | 124 +- .../api/vehicle/model/completeTechRecord.ts | 34 +- .../api/vehicle/model/completeTechRecordDB.ts | 36 +- .../vehicle/model/completeTechRecordPUT.ts | 32 +- .../api/vehicle/model/completeTechRecords.ts | 3 +- src/app/api/vehicle/model/dda.ts | 100 +- src/app/api/vehicle/model/lettersOfAuth.ts | 38 +- .../api/vehicle/model/manufacturerDetails.ts | 24 +- src/app/api/vehicle/model/metadata.ts | 16 +- .../api/vehicle/model/metadataAdrDetails.ts | 52 +- .../metadataAdrDetailsAdditionalNotes.ts | 34 +- .../vehicle/model/metadataAdrDetailsTank.ts | 6 +- .../metadataAdrDetailsTankTankStatement.ts | 20 +- .../model/metadataAdrDetailsVehicleDetails.ts | 75 +- src/app/api/vehicle/model/microfilm.ts | 199 ++- src/app/api/vehicle/model/plates.ts | 3 +- src/app/api/vehicle/model/platesInner.ts | 68 +- src/app/api/vehicle/model/purchaserDetails.ts | 24 +- src/app/api/vehicle/model/techRecord.ts | 933 +++++++------- .../techRecordArchiveAndProvisionalPayload.ts | 8 +- ...chiveAndProvisionalPayloadMsUserDetails.ts | 8 +- .../api/vehicle/model/techRecordBodyType.ts | 141 +-- .../api/vehicle/model/techRecordDimensions.ts | 36 +- .../model/techRecordDimensionsAxleSpacing.ts | 14 +- src/app/api/vehicle/model/techRecordPOST.ts | 40 +- src/app/api/vehicle/model/techRecordPUT.ts | 32 +- .../vehicle/model/techRecordVehicleClass.ts | 75 +- src/app/api/vehicle/model/techRecords.ts | 3 +- src/app/api/vehicle/model/vrm.ts | 8 +- src/app/api/vehicle/model/vrms.ts | 3 +- src/app/api/vehicle/model/weights.ts | 26 +- src/app/api/vehicle/variables.ts | 10 +- 109 files changed, 4313 insertions(+), 4788 deletions(-) diff --git a/src/app/api/document-retrieval/api/document-retrieval.service.ts b/src/app/api/document-retrieval/api/document-retrieval.service.ts index a35c44cae5..de1b06b570 100644 --- a/src/app/api/document-retrieval/api/document-retrieval.service.ts +++ b/src/app/api/document-retrieval/api/document-retrieval.service.ts @@ -7,208 +7,176 @@ import { DOCUMENT_RETRIEVAL_BASE_PATH } from '../variables'; @Injectable() export class DocumentRetrievalService { - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor( - protected httpClient: HttpClient, - @Optional() @Inject(DOCUMENT_RETRIEVAL_BASE_PATH) basePath: string, - @Optional() configuration: Configuration - ) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * Submitting a new test records - * - * @param body Post the test results - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public testCertificateGet( - testNumber?: string, - vin?: string, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public testCertificateGet( - testNumber?: string, - vin?: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public testCertificateGet( - testNumber?: string, - vin?: string, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public testCertificateGet( - testNumber?: string, - vin?: string, - observe: any = 'body', - reportProgress = false - ): Observable { - if (!vin) { - throw new Error('Required parameter vin was null or undefined when calling testCertificateGet.'); - } - if (!testNumber) { - throw new Error('Required parameter testNumber was null or undefined when calling testCertificateGet.'); - } - - // Set query parameters - let params = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); - if (testNumber) { - params = params.set('testNumber', testNumber); - } - if (vin) { - params = params.set('vinNumber', vin); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = - typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', `Bearer ${accessToken}`); - } - - // api keys - if (this.configuration.apiKeys) { - for (const key in this.configuration.apiKeys) { - headers = headers.set(key, this.configuration.apiKeys[key]); - } - } - - // to determine the Accept header - const httpHeaderAccepts: string[] = []; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = ['application/pdf; charset=utf-8']; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.get(`${this.basePath}/v1/document-retrieval`, { - headers, - params, - reportProgress, - observe, - responseType: 'text', - withCredentials: this.configuration.withCredentials, - }); - } - - public testPlateGet(serialNumber?: string, observe?: 'body', reportProgress?: boolean): Observable; - public testPlateGet( - serialNumber?: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public testPlateGet(serialNumber?: string, observe?: 'events', reportProgress?: boolean): Observable>; - public testPlateGet(serialNumber?: string, observe: any = 'body', reportProgress = false): Observable { - if (!serialNumber) { - throw new Error('Required parameter serialNumber was null or undefined when calling testCertificateGet.'); - } - - // Set query parameters - let params = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); - if (serialNumber) { - params = params.set('plateSerialNumber', serialNumber); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = - typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', `Bearer ${accessToken}`); - } - - // api keys - if (this.configuration.apiKeys) { - for (const key in this.configuration.apiKeys) { - headers = headers.set(key, this.configuration.apiKeys[key]); - } - } - - // to determine the Accept header - const httpHeaderAccepts: string[] = []; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = ['application/pdf; charset=utf-8']; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.get(`${this.basePath}/v1/document-retrieval`, { - headers, - params, - reportProgress, - observe, - responseType: 'text', - withCredentials: this.configuration.withCredentials, - }); - } - - getDocument(paramMap: Map): Observable> { - let headers = this.defaultHeaders; - - if (this.configuration.accessToken) { - const accessToken = - typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', `Bearer ${accessToken}`); - } - - if (this.configuration.apiKeys) { - for (const key in this.configuration.apiKeys) { - headers = headers.set(key, this.configuration.apiKeys[key]); - } - } - - const httpContentTypeSelected = this.configuration.selectHeaderContentType(['application/pdf; charset=utf-8']); - if (httpContentTypeSelected) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - let params = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); - - paramMap.forEach((value, key) => { - params = params.set(key, value); + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor( + protected httpClient: HttpClient, + @Optional() @Inject(DOCUMENT_RETRIEVAL_BASE_PATH) basePath: string, + @Optional() configuration: Configuration + ) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * Submitting a new test records + * + * @param body Post the test results + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public testCertificateGet(testNumber?: string, vin?: string, observe?: 'body', reportProgress?: boolean): Observable; + public testCertificateGet(testNumber?: string, vin?: string, observe?: 'response', reportProgress?: boolean): Observable>; + public testCertificateGet(testNumber?: string, vin?: string, observe?: 'events', reportProgress?: boolean): Observable>; + public testCertificateGet(testNumber?: string, vin?: string, observe: any = 'body', reportProgress = false): Observable { + if (!vin) { + throw new Error('Required parameter vin was null or undefined when calling testCertificateGet.'); + } + if (!testNumber) { + throw new Error('Required parameter testNumber was null or undefined when calling testCertificateGet.'); + } + + // Set query parameters + let params = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); + if (testNumber) { + params = params.set('testNumber', testNumber); + } + if (vin) { + params = params.set('vinNumber', vin); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // api keys + if (this.configuration.apiKeys) { + for (const key in this.configuration.apiKeys) { + headers = headers.set(key, this.configuration.apiKeys[key]); + } + } + + // to determine the Accept header + let httpHeaderAccepts: string[] = []; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = ['application/pdf; charset=utf-8']; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.get(`${this.basePath}/v1/document-retrieval`, { + headers, + params, + reportProgress, + observe, + responseType: 'text', + withCredentials: this.configuration.withCredentials }); - - return this.httpClient.get(`${this.basePath}/v1/document-retrieval`, { - headers, - observe: 'events', - params, - reportProgress: true, - responseType: 'text', - withCredentials: this.configuration.withCredentials, - }); - } + } + + public testPlateGet(serialNumber?: string, observe?: 'body', reportProgress?: boolean): Observable; + public testPlateGet(serialNumber?: string, observe?: 'response', reportProgress?: boolean): Observable>; + public testPlateGet(serialNumber?: string, observe?: 'events', reportProgress?: boolean): Observable>; + public testPlateGet(serialNumber?: string, observe: any = 'body', reportProgress = false): Observable { + if (!serialNumber) { + throw new Error('Required parameter serialNumber was null or undefined when calling testCertificateGet.'); + } + + // Set query parameters + let params = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); + if (serialNumber) { + params = params.set('plateSerialNumber', serialNumber); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // api keys + if (this.configuration.apiKeys) { + for (const key in this.configuration.apiKeys) { + headers = headers.set(key, this.configuration.apiKeys[key]); + } + } + + // to determine the Accept header + let httpHeaderAccepts: string[] = []; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = ['application/pdf; charset=utf-8']; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.get(`${this.basePath}/v1/document-retrieval`, { + headers, + params, + reportProgress, + observe, + responseType: 'text', + withCredentials: this.configuration.withCredentials + }); + } + + getDocument(paramMap: Map): Observable> { + let headers = this.defaultHeaders; + + if (this.configuration.accessToken) { + const accessToken = typeof this.configuration.accessToken === 'function' ? this.configuration.accessToken() : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + if (this.configuration.apiKeys) { + for (const key in this.configuration.apiKeys) { + headers = headers.set(key, this.configuration.apiKeys[key]); + } + } + + const httpContentTypeSelected = this.configuration.selectHeaderContentType(['application/pdf; charset=utf-8']); + if (httpContentTypeSelected) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + let params = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); + + paramMap.forEach((value, key) => params = params.set(key, value)); + + return this.httpClient.get( + `${this.basePath}/v1/document-retrieval`, + { + headers, + observe: 'events', + params, + reportProgress: true, + responseType: 'text', + withCredentials: this.configuration.withCredentials + } + ); + } } diff --git a/src/app/api/document-retrieval/configuration.ts b/src/app/api/document-retrieval/configuration.ts index 8a8c9a845e..82e8458f39 100644 --- a/src/app/api/document-retrieval/configuration.ts +++ b/src/app/api/document-retrieval/configuration.ts @@ -1,79 +1,79 @@ export interface ConfigurationParameters { - apiKeys?: { [key: string]: string }; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: {[ key: string ]: string}; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; } export class Configuration { - apiKeys?: { [key: string]: string }; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: {[ key: string ]: string}; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; - constructor(configurationParameters: ConfigurationParameters = {}) { - this.apiKeys = configurationParameters.apiKeys; - this.username = configurationParameters.username; - this.password = configurationParameters.password; - this.accessToken = configurationParameters.accessToken; - this.basePath = configurationParameters.basePath; - this.withCredentials = configurationParameters.withCredentials; - } + constructor(configurationParameters: ConfigurationParameters = {}) { + this.apiKeys = configurationParameters.apiKeys; + this.username = configurationParameters.username; + this.password = configurationParameters.password; + this.accessToken = configurationParameters.accessToken; + this.basePath = configurationParameters.basePath; + this.withCredentials = configurationParameters.withCredentials; + } - /** - * Select the correct content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param contentTypes - the array of content types that are available for selection - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderContentType(contentTypes: string[]): string | undefined { - if (contentTypes.length == 0) { - return undefined; - } + /** + * Select the correct content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param contentTypes - the array of content types that are available for selection + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderContentType (contentTypes: string[]): string | undefined { + if (contentTypes.length == 0) { + return undefined; + } - const type = contentTypes.find((x) => this.isJsonMime(x)); - if (type === undefined) { - return contentTypes[0]; - } - return type; - } + let type = contentTypes.find(x => this.isJsonMime(x)); + if (type === undefined) { + return contentTypes[0]; + } + return type; + } - /** - * Select the correct accept content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param accepts - the array of content types that are available for selection. - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderAccept(accepts: string[]): string | undefined { - if (accepts.length == 0) { - return undefined; - } + /** + * Select the correct accept content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param accepts - the array of content types that are available for selection. + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderAccept(accepts: string[]): string | undefined { + if (accepts.length == 0) { + return undefined; + } - const type = accepts.find((x) => this.isJsonMime(x)); - if (type === undefined) { - return accepts[0]; - } - return type; - } + let type = accepts.find(x => this.isJsonMime(x)); + if (type === undefined) { + return accepts[0]; + } + return type; + } - /** - * Check if the given MIME is a JSON MIME. - * JSON MIME examples: - * application/json - * application/json; charset=UTF8 - * APPLICATION/JSON - * application/vnd.company+json - * @param mime - MIME (Multipurpose Internet Mail Extensions) - * @return True if the given MIME is JSON, false otherwise. - */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); - return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } } diff --git a/src/app/api/document-retrieval/document-retrieval-api.module.ts b/src/app/api/document-retrieval/document-retrieval-api.module.ts index 1d5ab72f50..2056d2cd63 100644 --- a/src/app/api/document-retrieval/document-retrieval-api.module.ts +++ b/src/app/api/document-retrieval/document-retrieval-api.module.ts @@ -1,31 +1,28 @@ +import { NgModule, ModuleWithProviders, SkipSelf, Optional } from '@angular/core'; +import { Configuration } from './configuration'; import { HttpClient } from '@angular/common/http'; -import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; import { DocumentRetrievalService } from './api/document-retrieval.service'; -import { Configuration } from './configuration'; @NgModule({ - imports: [], - declarations: [], - exports: [], - providers: [DocumentRetrievalService], + imports: [], + declarations: [], + exports: [], + providers: [DocumentRetrievalService] }) export class DocumentRetrievalApiModule { - public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { - return { - ngModule: DocumentRetrievalApiModule, - providers: [{ provide: Configuration, useFactory: configurationFactory }], - }; - } + public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { + return { + ngModule: DocumentRetrievalApiModule, + providers: [{ provide: Configuration, useFactory: configurationFactory }] + }; + } - constructor(@Optional() @SkipSelf() parentModule: DocumentRetrievalApiModule, @Optional() http: HttpClient) { - if (parentModule) { - throw new Error('DocumentRetrievalApiModule is already loaded. Import in your base AppModule only.'); - } - if (!http) { - throw new Error( - 'You need to import the HttpClientModule in your AppModule! \n' + - 'See also https://github.com/angular/angular/issues/20575' - ); - } - } + constructor(@Optional() @SkipSelf() parentModule: DocumentRetrievalApiModule, @Optional() http: HttpClient) { + if (parentModule) { + throw new Error('DocumentRetrievalApiModule is already loaded. Import in your base AppModule only.'); + } + if (!http) { + throw new Error('You need to import the HttpClientModule in your AppModule! \n' + 'See also https://github.com/angular/angular/issues/20575'); + } + } } diff --git a/src/app/api/document-retrieval/encoder.ts b/src/app/api/document-retrieval/encoder.ts index 1d5c24dfd9..5d0fb0e90c 100644 --- a/src/app/api/document-retrieval/encoder.ts +++ b/src/app/api/document-retrieval/encoder.ts @@ -1,4 +1,4 @@ -import {HttpUrlEncodingCodec} from '@angular/common/http'; +import { HttpUrlEncodingCodec } from '@angular/common/http'; /** * CustomHttpUrlEncodingCodec @@ -6,13 +6,12 @@ import {HttpUrlEncodingCodec} from '@angular/common/http'; * See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 */ export class CustomHttpUrlEncodingCodec extends HttpUrlEncodingCodec { - override encodeKey(key: string): string { - const k = super.encodeKey(key); - return k.replace(/\+/gi, '%2B'); - } - - override encodeValue(value: string): string { - const v = super.encodeValue(value); - return v.replace(/\+/gi, '%2B'); - } + override encodeKey(k: string): string { + k = super.encodeKey(k); + return k.replace(/\+/gi, '%2B'); + } + override encodeValue(v: string): string { + v = super.encodeValue(v); + return v.replace(/\+/gi, '%2B'); + } } diff --git a/src/app/api/reference-data/api.module.ts b/src/app/api/reference-data/api.module.ts index aec62543e7..c368284e6e 100644 --- a/src/app/api/reference-data/api.module.ts +++ b/src/app/api/reference-data/api.module.ts @@ -1,32 +1,33 @@ -import { HttpClient } from '@angular/common/http'; -import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; +import { NgModule, ModuleWithProviders, SkipSelf, Optional } from '@angular/core'; import { Configuration } from './configuration'; +import { HttpClient } from '@angular/common/http'; + import { ReferenceDataService } from './api/referenceData.service'; @NgModule({ - imports: [], - declarations: [], - exports: [], - providers: [ReferenceDataService], + imports: [], + declarations: [], + exports: [], + providers: [ + ReferenceDataService ] }) export class ApiModule { - public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { - return { - ngModule: ApiModule, - providers: [{ provide: Configuration, useFactory: configurationFactory }], - }; - } + public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { + return { + ngModule: ApiModule, + providers: [ { provide: Configuration, useFactory: configurationFactory } ] + }; + } - constructor(@Optional() @SkipSelf() parentModule: ApiModule, @Optional() http: HttpClient) { - if (parentModule) { - throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); - } - if (!http) { - throw new Error( - 'You need to import the HttpClientModule in your AppModule! \n' + - 'See also https://github.com/angular/angular/issues/20575' - ); - } - } + constructor( @Optional() @SkipSelf() parentModule: ApiModule, + @Optional() http: HttpClient) { + if (parentModule) { + throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); + } + if (!http) { + throw new Error('You need to import the HttpClientModule in your AppModule! \n' + + 'See also https://github.com/angular/angular/issues/20575'); + } + } } diff --git a/src/app/api/reference-data/api/referenceData.service.ts b/src/app/api/reference-data/api/referenceData.service.ts index 92a638ec0e..573cd35d30 100644 --- a/src/app/api/reference-data/api/referenceData.service.ts +++ b/src/app/api/reference-data/api/referenceData.service.ts @@ -7,559 +7,549 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - */ /* tslint:disable:no-unused-variable member-ordering */ + *//* tslint:disable:no-unused-variable member-ordering */ -import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; import { Inject, Injectable, Optional } from '@angular/core'; +import { HttpClient, HttpHeaders, HttpParams, HttpResponse, HttpEvent } from '@angular/common/http'; import { CustomHttpUrlEncodingCodec } from '../encoder'; import { Observable } from 'rxjs'; -import { DeleteItem } from '../model/deleteItem'; -import { ReferenceDataApiResponse } from '../model/referenceDataApiResponse'; +import { DeleteItem } from '../model/deleteItem';import { ReferenceDataApiResponse } from '../model/referenceDataApiResponse'; import { ReferenceDataItem } from '../model/referenceDataItem'; import { ReferenceDataItemApiResponse } from '../model/referenceDataItemApiResponse'; import { ResourceKey } from '../model/resourceKey'; +import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; import { Configuration } from '../configuration'; -import { BASE_PATH } from '../variables'; + @Injectable() export class ReferenceDataService { - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor( - protected httpClient: HttpClient, - @Optional() @Inject(BASE_PATH) basePath: string, - @Optional() configuration: Configuration - ) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - /** - * Lookup any resourceType with its key, allows partials. - * - * @param resourceType - * @param resourceKey - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public referenceLookupResourceTypeResourceKeyGet( - resourceType: string, - resourceKey: ResourceKey, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public referenceLookupResourceTypeResourceKeyGet( - resourceType: string, - resourceKey: ResourceKey, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public referenceLookupResourceTypeResourceKeyGet( - resourceType: string, - resourceKey: ResourceKey, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public referenceLookupResourceTypeResourceKeyGet( - resourceType: string, - resourceKey: ResourceKey, - observe: any = 'body', - reportProgress = false - ): Observable { - if (resourceType === null || resourceType === undefined) { - throw new Error( - 'Required parameter resourceType was null or undefined when calling referenceLookupResourceTypeResourceKeyGet.' - ); - } - - if (resourceKey === null || resourceKey === undefined) { - throw new Error( - 'Required parameter resourceKey was null or undefined when calling referenceLookupResourceTypeResourceKeyGet.' - ); - } - - let headers = this.defaultHeaders; - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = []; - - return this.httpClient.request( - 'get', - `${this.basePath}/reference/lookup/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, - { - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - } - ); - } - - /** - * Search the tyres by plyRating, singleIndex and doubleIndex, allows partials. - * - * @param searchKey - * @param param - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public referenceLookupTyresSearchKeyParamGet( - searchKey: string, - param: string, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public referenceLookupTyresSearchKeyParamGet( - searchKey: string, - param: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public referenceLookupTyresSearchKeyParamGet( - searchKey: string, - param: string, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public referenceLookupTyresSearchKeyParamGet( - searchKey: string, - param: string, - observe: any = 'body', - reportProgress = false - ): Observable { - if (searchKey === null || searchKey === undefined) { - throw new Error( - 'Required parameter searchKey was null or undefined when calling referenceLookupTyresSearchKeyParamGet.' - ); - } - - if (param === null || param === undefined) { - throw new Error( - 'Required parameter param was null or undefined when calling referenceLookupTyresSearchKeyParamGet.' - ); - } - - let headers = this.defaultHeaders; - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = []; - - return this.httpClient.request( - 'get', - `${this.basePath}/reference/lookup/tyres/${encodeURIComponent(String(searchKey))}/${encodeURIComponent(String(param))}`, - { - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - } - ); - } - - /** - * Get reference data for a particular resourceType. - * - * @param resourceType - * @param paginationToken - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public referenceResourceTypeGet( - resourceType: string, - paginationToken?: string, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public referenceResourceTypeGet( - resourceType: string, - paginationToken?: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeGet( - resourceType: string, - paginationToken?: string, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeGet( - resourceType: string, - paginationToken?: string, - observe: any = 'body', - reportProgress = false - ): Observable { - if (resourceType === null || resourceType === undefined) { - throw new Error('Required parameter resourceType was null or undefined when calling referenceResourceTypeGet.'); - } - - let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); - if (paginationToken !== undefined && paginationToken !== null) { - queryParameters = queryParameters.set('paginationToken', paginationToken); - } - - let headers = this.defaultHeaders; - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = []; - - return this.httpClient.request( - 'get', - `${this.basePath}/reference/${encodeURIComponent(String(resourceType))}`, - { - params: queryParameters, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - } - ); - } - - /** - * Delete reference data for a particular resourceType and resourceKey. - * - * @param resourceType - * @param resourceKey - * @param body - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public referenceResourceTypeResourceKeyDelete( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public referenceResourceTypeResourceKeyDelete( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeResourceKeyDelete( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeResourceKeyDelete( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe: any = 'body', - reportProgress = false - ): Observable { - if (resourceType === null || resourceType === undefined) { - throw new Error( - 'Required parameter resourceType was null or undefined when calling referenceResourceTypeResourceKeyDelete.' - ); - } - - if (resourceKey === null || resourceKey === undefined) { - throw new Error( - 'Required parameter resourceKey was null or undefined when calling referenceResourceTypeResourceKeyDelete.' - ); - } - - let headers = this.defaultHeaders; - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = ['application/json']; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request( - 'delete', - `${this.basePath}/reference/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, - { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - } - ); - } - - /** - * Get reference data for a particular resourceType and resourceKey. - * - * @param resourceType - * @param resourceKey - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public referenceResourceTypeResourceKeyGet( - resourceType: string, - resourceKey: ResourceKey, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public referenceResourceTypeResourceKeyGet( - resourceType: string, - resourceKey: ResourceKey, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeResourceKeyGet( - resourceType: string, - resourceKey: ResourceKey, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeResourceKeyGet( - resourceType: string, - resourceKey: ResourceKey, - observe: any = 'body', - reportProgress = false - ): Observable { - if (resourceType === null || resourceType === undefined) { - throw new Error( - 'Required parameter resourceType was null or undefined when calling referenceResourceTypeResourceKeyGet.' - ); - } - - if (resourceKey === null || resourceKey === undefined) { - throw new Error( - 'Required parameter resourceKey was null or undefined when calling referenceResourceTypeResourceKeyGet.' - ); - } - - let headers = this.defaultHeaders; - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = []; - - return this.httpClient.request( - 'get', - `${this.basePath}/reference/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, - { - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - } - ); - } - - /** - * Create reference data for a particular resourceType and resourceKey. - * - * @param resourceType - * @param resourceKey - * @param body - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public referenceResourceTypeResourceKeyPost( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public referenceResourceTypeResourceKeyPost( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeResourceKeyPost( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeResourceKeyPost( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe: any = 'body', - reportProgress = false - ): Observable { - if (resourceType === null || resourceType === undefined) { - throw new Error( - 'Required parameter resourceType was null or undefined when calling referenceResourceTypeResourceKeyPost.' - ); - } - - if (resourceKey === null || resourceKey === undefined) { - throw new Error( - 'Required parameter resourceKey was null or undefined when calling referenceResourceTypeResourceKeyPost.' - ); - } - - let headers = this.defaultHeaders; - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = ['application/json']; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request( - 'post', - `${this.basePath}/reference/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, - { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - } - ); - } - - /** - * Update/Create reference data for a particular resourceType and resourceKey. - * - * @param resourceType - * @param resourceKey - * @param body - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public referenceResourceTypeResourceKeyPut( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public referenceResourceTypeResourceKeyPut( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeResourceKeyPut( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public referenceResourceTypeResourceKeyPut( - resourceType: string, - resourceKey: ResourceKey, - body?: any, - observe: any = 'body', - reportProgress = false - ): Observable { - if (resourceType === null || resourceType === undefined) { - throw new Error( - 'Required parameter resourceType was null or undefined when calling referenceResourceTypeResourceKeyPut.' - ); - } - - if (resourceKey === null || resourceKey === undefined) { - throw new Error( - 'Required parameter resourceKey was null or undefined when calling referenceResourceTypeResourceKeyPut.' - ); - } - - let headers = this.defaultHeaders; - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = ['application/json']; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request( - 'put', - `${this.basePath}/reference/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, - { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - } - ); - } + + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + + /** + * Lookup any resourceType with its key, allows partials. + * + * @param resourceType + * @param resourceKey + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public referenceLookupResourceTypeResourceKeyGet( + resourceType: string, + resourceKey: ResourceKey, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public referenceLookupResourceTypeResourceKeyGet( + resourceType: string, + resourceKey: ResourceKey, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public referenceLookupResourceTypeResourceKeyGet( + resourceType: string, + resourceKey: ResourceKey, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public referenceLookupResourceTypeResourceKeyGet( + resourceType: string, + resourceKey: ResourceKey, + observe: any = 'body', + reportProgress: boolean = false + ): Observable { + if (resourceType === null || resourceType === undefined) { + throw new Error('Required parameter resourceType was null or undefined when calling referenceLookupResourceTypeResourceKeyGet.'); + } + + if (resourceKey === null || resourceKey === undefined) { + throw new Error('Required parameter resourceKey was null or undefined when calling referenceLookupResourceTypeResourceKeyGet.'); + } + + let headers = this.defaultHeaders; + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/json' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + ]; + + return this.httpClient.request('get',`${this.basePath}/reference/lookup/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, + { + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + + /** + * Search the tyres by plyRating, singleIndex and doubleIndex, allows partials. + * + * @param searchKey + * @param param + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public referenceLookupTyresSearchKeyParamGet( + searchKey: string, + param: string, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public referenceLookupTyresSearchKeyParamGet( + searchKey: string, + param: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public referenceLookupTyresSearchKeyParamGet( + searchKey: string, + param: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public referenceLookupTyresSearchKeyParamGet( + searchKey: string, + param: string, + observe: any = 'body', + reportProgress: boolean = false + ): Observable { + if (searchKey === null || searchKey === undefined) { + throw new Error('Required parameter searchKey was null or undefined when calling referenceLookupTyresSearchKeyParamGet.'); + } + + if (param === null || param === undefined) { + throw new Error('Required parameter param was null or undefined when calling referenceLookupTyresSearchKeyParamGet.'); + } + + let headers = this.defaultHeaders; + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/json' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + ]; + + return this.httpClient.request('get',`${this.basePath}/reference/lookup/tyres/${encodeURIComponent(String(searchKey))}/${encodeURIComponent(String(param))}`, + { + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + + /** + * Get reference data for a particular resourceType. + * + * @param resourceType + * @param paginationToken + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public referenceResourceTypeGet( + resourceType: string, + paginationToken?: string, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public referenceResourceTypeGet( + resourceType: string, + paginationToken?: string, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeGet( + resourceType: string, + paginationToken?: string, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeGet( + resourceType: string, + paginationToken?: string, + observe: any = 'body', + reportProgress: boolean = false + ): Observable { + + if (resourceType === null || resourceType === undefined) { + throw new Error('Required parameter resourceType was null or undefined when calling referenceResourceTypeGet.'); + } + + let queryParameters = new HttpParams({encoder: new CustomHttpUrlEncodingCodec()}); + if (paginationToken !== undefined && paginationToken !== null) { + queryParameters = queryParameters.set('paginationToken', paginationToken); + } + + let headers = this.defaultHeaders; + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/json' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + ]; + + return this.httpClient.request('get',`${this.basePath}/reference/${encodeURIComponent(String(resourceType))}`, + { + params: queryParameters, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + + /** + * Delete reference data for a particular resourceType and resourceKey. + * + * @param resourceType + * @param resourceKey + * @param body + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public referenceResourceTypeResourceKeyDelete( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public referenceResourceTypeResourceKeyDelete( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeResourceKeyDelete( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeResourceKeyDelete( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe: any = 'body', + reportProgress: boolean = false + ): Observable { + + if (resourceType === null || resourceType === undefined) { + throw new Error('Required parameter resourceType was null or undefined when calling referenceResourceTypeResourceKeyDelete.'); + } + + if (resourceKey === null || resourceKey === undefined) { + throw new Error('Required parameter resourceKey was null or undefined when calling referenceResourceTypeResourceKeyDelete.'); + } + + let headers = this.defaultHeaders; + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/json' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + 'application/json' + ]; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request('delete',`${this.basePath}/reference/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, + { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + + /** + * Get reference data for a particular resourceType and resourceKey. + * + * @param resourceType + * @param resourceKey + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public referenceResourceTypeResourceKeyGet( + resourceType: string, + resourceKey: ResourceKey, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public referenceResourceTypeResourceKeyGet( + resourceType: string, + resourceKey: ResourceKey, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeResourceKeyGet( + resourceType: string, + resourceKey: ResourceKey, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeResourceKeyGet( + resourceType: string, + resourceKey: ResourceKey, + observe: any = 'body', + reportProgress: boolean = false + ): Observable { + + if (resourceType === null || resourceType === undefined) { + throw new Error('Required parameter resourceType was null or undefined when calling referenceResourceTypeResourceKeyGet.'); + } + + if (resourceKey === null || resourceKey === undefined) { + throw new Error('Required parameter resourceKey was null or undefined when calling referenceResourceTypeResourceKeyGet.'); + } + + let headers = this.defaultHeaders; + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/json' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + ]; + + return this.httpClient.request('get',`${this.basePath}/reference/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, + { + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + + /** + * Create reference data for a particular resourceType and resourceKey. + * + * @param resourceType + * @param resourceKey + * @param body + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public referenceResourceTypeResourceKeyPost( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public referenceResourceTypeResourceKeyPost( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeResourceKeyPost( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeResourceKeyPost( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe: any = 'body', + reportProgress: boolean = false + ): Observable { + + if (resourceType === null || resourceType === undefined) { + throw new Error('Required parameter resourceType was null or undefined when calling referenceResourceTypeResourceKeyPost.'); + } + + if (resourceKey === null || resourceKey === undefined) { + throw new Error('Required parameter resourceKey was null or undefined when calling referenceResourceTypeResourceKeyPost.'); + } + + let headers = this.defaultHeaders; + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/json' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + 'application/json' + ]; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request('post',`${this.basePath}/reference/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, + { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + + /** + * Update/Create reference data for a particular resourceType and resourceKey. + * + * @param resourceType + * @param resourceKey + * @param body + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public referenceResourceTypeResourceKeyPut( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'body', + reportProgress?: boolean + ): Observable; + public referenceResourceTypeResourceKeyPut( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'response', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeResourceKeyPut( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe?: 'events', + reportProgress?: boolean + ): Observable>; + public referenceResourceTypeResourceKeyPut( + resourceType: string, + resourceKey: ResourceKey, + body?: any, + observe: any = 'body', + reportProgress: boolean = false + ): Observable { + + if (resourceType === null || resourceType === undefined) { + throw new Error('Required parameter resourceType was null or undefined when calling referenceResourceTypeResourceKeyPut.'); + } + + if (resourceKey === null || resourceKey === undefined) { + throw new Error('Required parameter resourceKey was null or undefined when calling referenceResourceTypeResourceKeyPut.'); + } + + let headers = this.defaultHeaders; + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/json' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + 'application/json' + ]; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request('put',`${this.basePath}/reference/${encodeURIComponent(String(resourceType))}/${encodeURIComponent(String(resourceKey))}`, + { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + } diff --git a/src/app/api/reference-data/configuration.ts b/src/app/api/reference-data/configuration.ts index 8a8c9a845e..82e8458f39 100644 --- a/src/app/api/reference-data/configuration.ts +++ b/src/app/api/reference-data/configuration.ts @@ -1,79 +1,79 @@ export interface ConfigurationParameters { - apiKeys?: { [key: string]: string }; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: {[ key: string ]: string}; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; } export class Configuration { - apiKeys?: { [key: string]: string }; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: {[ key: string ]: string}; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; - constructor(configurationParameters: ConfigurationParameters = {}) { - this.apiKeys = configurationParameters.apiKeys; - this.username = configurationParameters.username; - this.password = configurationParameters.password; - this.accessToken = configurationParameters.accessToken; - this.basePath = configurationParameters.basePath; - this.withCredentials = configurationParameters.withCredentials; - } + constructor(configurationParameters: ConfigurationParameters = {}) { + this.apiKeys = configurationParameters.apiKeys; + this.username = configurationParameters.username; + this.password = configurationParameters.password; + this.accessToken = configurationParameters.accessToken; + this.basePath = configurationParameters.basePath; + this.withCredentials = configurationParameters.withCredentials; + } - /** - * Select the correct content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param contentTypes - the array of content types that are available for selection - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderContentType(contentTypes: string[]): string | undefined { - if (contentTypes.length == 0) { - return undefined; - } + /** + * Select the correct content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param contentTypes - the array of content types that are available for selection + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderContentType (contentTypes: string[]): string | undefined { + if (contentTypes.length == 0) { + return undefined; + } - const type = contentTypes.find((x) => this.isJsonMime(x)); - if (type === undefined) { - return contentTypes[0]; - } - return type; - } + let type = contentTypes.find(x => this.isJsonMime(x)); + if (type === undefined) { + return contentTypes[0]; + } + return type; + } - /** - * Select the correct accept content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param accepts - the array of content types that are available for selection. - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderAccept(accepts: string[]): string | undefined { - if (accepts.length == 0) { - return undefined; - } + /** + * Select the correct accept content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param accepts - the array of content types that are available for selection. + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderAccept(accepts: string[]): string | undefined { + if (accepts.length == 0) { + return undefined; + } - const type = accepts.find((x) => this.isJsonMime(x)); - if (type === undefined) { - return accepts[0]; - } - return type; - } + let type = accepts.find(x => this.isJsonMime(x)); + if (type === undefined) { + return accepts[0]; + } + return type; + } - /** - * Check if the given MIME is a JSON MIME. - * JSON MIME examples: - * application/json - * application/json; charset=UTF8 - * APPLICATION/JSON - * application/vnd.company+json - * @param mime - MIME (Multipurpose Internet Mail Extensions) - * @return True if the given MIME is JSON, false otherwise. - */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); - return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } } diff --git a/src/app/api/reference-data/encoder.ts b/src/app/api/reference-data/encoder.ts index 1d5c24dfd9..f506bfbea0 100644 --- a/src/app/api/reference-data/encoder.ts +++ b/src/app/api/reference-data/encoder.ts @@ -1,18 +1,18 @@ -import {HttpUrlEncodingCodec} from '@angular/common/http'; + import { HttpUrlEncodingCodec } from '@angular/common/http'; /** - * CustomHttpUrlEncodingCodec - * Fix plus sign (+) not encoding, so sent as blank space - * See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 - */ +* CustomHttpUrlEncodingCodec +* Fix plus sign (+) not encoding, so sent as blank space +* See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 +*/ export class CustomHttpUrlEncodingCodec extends HttpUrlEncodingCodec { - override encodeKey(key: string): string { - const k = super.encodeKey(key); - return k.replace(/\+/gi, '%2B'); - } - - override encodeValue(value: string): string { - const v = super.encodeValue(value); - return v.replace(/\+/gi, '%2B'); - } + override encodeKey(k: string): string { + k = super.encodeKey(k); + return k.replace(/\+/gi, '%2B'); + } + override encodeValue(v: string): string { + v = super.encodeValue(v); + return v.replace(/\+/gi, '%2B'); + } } + diff --git a/src/app/api/reference-data/index.ts b/src/app/api/reference-data/index.ts index 410623f1c9..c312b70fa3 100644 --- a/src/app/api/reference-data/index.ts +++ b/src/app/api/reference-data/index.ts @@ -2,4 +2,4 @@ export * from './api/api'; export * from './model/models'; export * from './variables'; export * from './configuration'; -export * from './api.module'; +export * from './api.module'; \ No newline at end of file diff --git a/src/app/api/reference-data/model/deleteItem.ts b/src/app/api/reference-data/model/deleteItem.ts index 1dfd362d83..52156da807 100644 --- a/src/app/api/reference-data/model/deleteItem.ts +++ b/src/app/api/reference-data/model/deleteItem.ts @@ -10,6 +10,6 @@ * Do not edit the class manually. */ -export interface DeleteItem { - success?: boolean; -} +export interface DeleteItem { + success?: boolean; +} \ No newline at end of file diff --git a/src/app/api/reference-data/model/emptyObject.ts b/src/app/api/reference-data/model/emptyObject.ts index a3c2dddc63..124b603c70 100644 --- a/src/app/api/reference-data/model/emptyObject.ts +++ b/src/app/api/reference-data/model/emptyObject.ts @@ -10,4 +10,5 @@ * Do not edit the class manually. */ -export type EmptyObject = {}; +export interface EmptyObject { +} \ No newline at end of file diff --git a/src/app/api/reference-data/model/referenceDataApiResponse.ts b/src/app/api/reference-data/model/referenceDataApiResponse.ts index 5704314bf4..1d35b26c6f 100644 --- a/src/app/api/reference-data/model/referenceDataApiResponse.ts +++ b/src/app/api/reference-data/model/referenceDataApiResponse.ts @@ -12,6 +12,4 @@ import { ReferenceDataApiResponseWithPagination } from './referenceDataApiResponseWithPagination'; import { ReferenceDataApiResponseWithoutPagination } from './referenceDataApiResponseWithoutPagination'; -export type ReferenceDataApiResponse = - | ReferenceDataApiResponseWithoutPagination - | ReferenceDataApiResponseWithPagination; +export type ReferenceDataApiResponse = ReferenceDataApiResponseWithoutPagination | ReferenceDataApiResponseWithPagination; \ No newline at end of file diff --git a/src/app/api/reference-data/model/referenceDataApiResponseWithPagination.ts b/src/app/api/reference-data/model/referenceDataApiResponseWithPagination.ts index c435d2427f..2465daa232 100644 --- a/src/app/api/reference-data/model/referenceDataApiResponseWithPagination.ts +++ b/src/app/api/reference-data/model/referenceDataApiResponseWithPagination.ts @@ -10,7 +10,8 @@ * Do not edit the class manually. */ import { ReferenceDataApiResponseWithoutPagination } from './referenceDataApiResponseWithoutPagination'; +import { ReferenceDataItem } from './referenceDataItem'; -export interface ReferenceDataApiResponseWithPagination extends ReferenceDataApiResponseWithoutPagination { - paginationToken: string; -} +export interface ReferenceDataApiResponseWithPagination extends ReferenceDataApiResponseWithoutPagination { + paginationToken: string; +} \ No newline at end of file diff --git a/src/app/api/reference-data/model/referenceDataApiResponseWithoutPagination.ts b/src/app/api/reference-data/model/referenceDataApiResponseWithoutPagination.ts index 93d2489a3c..c473133fd5 100644 --- a/src/app/api/reference-data/model/referenceDataApiResponseWithoutPagination.ts +++ b/src/app/api/reference-data/model/referenceDataApiResponseWithoutPagination.ts @@ -11,6 +11,6 @@ */ import { ReferenceDataItem } from './referenceDataItem'; -export interface ReferenceDataApiResponseWithoutPagination { - data: Array; -} +export interface ReferenceDataApiResponseWithoutPagination { + data: Array; +} \ No newline at end of file diff --git a/src/app/api/reference-data/model/referenceDataItem.ts b/src/app/api/reference-data/model/referenceDataItem.ts index 97ae42895c..55566b6435 100644 --- a/src/app/api/reference-data/model/referenceDataItem.ts +++ b/src/app/api/reference-data/model/referenceDataItem.ts @@ -11,8 +11,8 @@ */ import { ResourceKey } from './resourceKey'; -export interface ReferenceDataItem { - resourceType: string; - resourceKey: ResourceKey; - reason?: string; -} +export interface ReferenceDataItem { + resourceType: string; + resourceKey: ResourceKey; + reason?: string; +} \ No newline at end of file diff --git a/src/app/api/reference-data/model/referenceDataItemApiResponse.ts b/src/app/api/reference-data/model/referenceDataItemApiResponse.ts index 37c298fb77..97b7df9d77 100644 --- a/src/app/api/reference-data/model/referenceDataItemApiResponse.ts +++ b/src/app/api/reference-data/model/referenceDataItemApiResponse.ts @@ -12,4 +12,4 @@ import { EmptyObject } from './emptyObject'; import { ReferenceDataItem } from './referenceDataItem'; -export type ReferenceDataItemApiResponse = ReferenceDataItem | EmptyObject; +export type ReferenceDataItemApiResponse = ReferenceDataItem | EmptyObject; \ No newline at end of file diff --git a/src/app/api/reference-data/model/resourceKey.ts b/src/app/api/reference-data/model/resourceKey.ts index 7898a0344a..3f52dec65c 100644 --- a/src/app/api/reference-data/model/resourceKey.ts +++ b/src/app/api/reference-data/model/resourceKey.ts @@ -10,4 +10,4 @@ * Do not edit the class manually. */ -export type ResourceKey = string | number; +export type ResourceKey = string | number; \ No newline at end of file diff --git a/src/app/api/reference-data/variables.ts b/src/app/api/reference-data/variables.ts index 9bae45f800..6fe58549f3 100644 --- a/src/app/api/reference-data/variables.ts +++ b/src/app/api/reference-data/variables.ts @@ -2,8 +2,8 @@ import { InjectionToken } from '@angular/core'; export const BASE_PATH = new InjectionToken('basePath'); export const COLLECTION_FORMATS = { - csv: ',', - tsv: ' ', - ssv: ' ', - pipes: '|', -}; + 'csv': ',', + 'tsv': ' ', + 'ssv': ' ', + 'pipes': '|' +} diff --git a/src/app/api/test-results/api.module.ts b/src/app/api/test-results/api.module.ts index 8624d75994..0cfe105217 100644 --- a/src/app/api/test-results/api.module.ts +++ b/src/app/api/test-results/api.module.ts @@ -1,6 +1,7 @@ -import { HttpClient } from '@angular/common/http'; -import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; +import { NgModule, ModuleWithProviders, SkipSelf, Optional } from '@angular/core'; import { Configuration } from './configuration'; +import { HttpClient } from '@angular/common/http'; + import { ArchiveTestResultsService } from './api/archiveTestResults.service'; import { DefaultService } from './api/default.service'; @@ -8,28 +9,31 @@ import { GetTestResultsService } from './api/getTestResults.service'; import { UpdateTestResultsService } from './api/updateTestResults.service'; @NgModule({ - imports: [], - declarations: [], - exports: [], - providers: [ArchiveTestResultsService, DefaultService, GetTestResultsService, UpdateTestResultsService], + imports: [], + declarations: [], + exports: [], + providers: [ + ArchiveTestResultsService, + DefaultService, + GetTestResultsService, + UpdateTestResultsService ] }) export class ApiModule { - public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { - return { - ngModule: ApiModule, - providers: [{ provide: Configuration, useFactory: configurationFactory }], - }; - } + public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { + return { + ngModule: ApiModule, + providers: [ { provide: Configuration, useFactory: configurationFactory } ] + }; + } - constructor(@Optional() @SkipSelf() parentModule: ApiModule, @Optional() http: HttpClient) { - if (parentModule) { - throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); - } - if (!http) { - throw new Error( - 'You need to import the HttpClientModule in your AppModule! \n' + - 'See also https://github.com/angular/angular/issues/20575' - ); - } - } + constructor( @Optional() @SkipSelf() parentModule: ApiModule, + @Optional() http: HttpClient) { + if (parentModule) { + throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); + } + if (!http) { + throw new Error('You need to import the HttpClientModule in your AppModule! \n' + + 'See also https://github.com/angular/angular/issues/20575'); + } + } } diff --git a/src/app/api/test-results/api/archiveTestResults.service.ts b/src/app/api/test-results/api/archiveTestResults.service.ts index 515506d8fb..bb2afbf814 100644 --- a/src/app/api/test-results/api/archiveTestResults.service.ts +++ b/src/app/api/test-results/api/archiveTestResults.service.ts @@ -7,130 +7,112 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - */ /* tslint:disable:no-unused-variable member-ordering */ + *//* tslint:disable:no-unused-variable member-ordering */ -import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http'; -import { Inject, Injectable, Optional } from '@angular/core'; +import { Inject, Injectable, Optional } from '@angular/core'; +import { HttpClient, HttpHeaders, HttpParams, + HttpResponse, HttpEvent } from '@angular/common/http'; +import { CustomHttpUrlEncodingCodec } from '../encoder'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { CompleteTestResults } from '../model/completeTestResults'; import { TestResults } from '../model/testResults'; -import { Configuration } from '../configuration'; -import { BASE_PATH } from '../variables'; +import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; +import { Configuration } from '../configuration'; + @Injectable() export class ArchiveTestResultsService { - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor( - protected httpClient: HttpClient, - @Optional() @Inject(BASE_PATH) basePath: string, - @Optional() configuration: Configuration - ) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - /** - * Archive a specific test-type, for a particular testResultId - * - * @param body The test result containing the test-type to be archived (marked with statusUpdatedFlag set to true) - * @param testResultId - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public testResultsArchiveTestResultIdPut( - body: CompleteTestResults, - testResultId: string, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public testResultsArchiveTestResultIdPut( - body: CompleteTestResults, - testResultId: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public testResultsArchiveTestResultIdPut( - body: CompleteTestResults, - testResultId: string, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public testResultsArchiveTestResultIdPut( - body: CompleteTestResults, - testResultId: string, - observe: any = 'body', - reportProgress = false - ): Observable { - if (body === null || body === undefined) { - throw new Error('Required parameter body was null or undefined when calling testResultsArchiveTestResultIdPut.'); - } - - if (testResultId === null || testResultId === undefined) { - throw new Error( - 'Required parameter testResultId was null or undefined when calling testResultsArchiveTestResultIdPut.' - ); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = - typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', `Bearer ${accessToken}`); - } - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = ['application/json']; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request( - 'put', - `${this.basePath}/test-results/archive/${encodeURIComponent(String(testResultId))}`, - { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - } - ); - } + + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + + /** + * Archive a specific test-type, for a particular testResultId + * + * @param body The test result containing the test-type to be archived (marked with statusUpdatedFlag set to true) + * @param testResultId + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public testResultsArchiveTestResultIdPut(body: CompleteTestResults, testResultId: string, observe?: 'body', reportProgress?: boolean): Observable; + public testResultsArchiveTestResultIdPut(body: CompleteTestResults, testResultId: string, observe?: 'response', reportProgress?: boolean): Observable>; + public testResultsArchiveTestResultIdPut(body: CompleteTestResults, testResultId: string, observe?: 'events', reportProgress?: boolean): Observable>; + public testResultsArchiveTestResultIdPut(body: CompleteTestResults, testResultId: string, observe: any = 'body', reportProgress: boolean = false ): Observable { + + if (body === null || body === undefined) { + throw new Error('Required parameter body was null or undefined when calling testResultsArchiveTestResultIdPut.'); + } + + if (testResultId === null || testResultId === undefined) { + throw new Error('Required parameter testResultId was null or undefined when calling testResultsArchiveTestResultIdPut.'); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/json' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + 'application/json' + ]; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request('put',`${this.basePath}/test-results/archive/${encodeURIComponent(String(testResultId))}`, + { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + } diff --git a/src/app/api/test-results/api/default.service.ts b/src/app/api/test-results/api/default.service.ts index 99679e7b7e..51ab3c8930 100644 --- a/src/app/api/test-results/api/default.service.ts +++ b/src/app/api/test-results/api/default.service.ts @@ -7,106 +7,105 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - */ /* tslint:disable:no-unused-variable member-ordering */ + *//* tslint:disable:no-unused-variable member-ordering */ -import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http'; -import { Inject, Injectable, Optional } from '@angular/core'; +import { Inject, Injectable, Optional } from '@angular/core'; +import { HttpClient, HttpHeaders, HttpParams, + HttpResponse, HttpEvent } from '@angular/common/http'; +import { CustomHttpUrlEncodingCodec } from '../encoder'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { CompleteTestResults } from '../model/completeTestResults'; -import { Configuration } from '../configuration'; -import { BASE_PATH } from '../variables'; +import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; +import { Configuration } from '../configuration'; + @Injectable() export class DefaultService { - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor( - protected httpClient: HttpClient, - @Optional() @Inject(BASE_PATH) basePath: string, - @Optional() configuration: Configuration - ) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - /** - * Submitting a new test records - * - * @param body Post the test results - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public testResultsPost(body: CompleteTestResults, observe?: 'body', reportProgress?: boolean): Observable; - public testResultsPost( - body: CompleteTestResults, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public testResultsPost( - body: CompleteTestResults, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public testResultsPost(body: CompleteTestResults, observe: any = 'body', reportProgress = false): Observable { - if (body === null || body === undefined) { - throw new Error('Required parameter body was null or undefined when calling testResultsPost.'); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = - typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', `Bearer ${accessToken}`); - } - - // to determine the Accept header - const httpHeaderAccepts: string[] = []; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = ['application/json']; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request('post', `${this.basePath}/test-results`, { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - }); - } + + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + + /** + * Submitting a new test records + * + * @param body Post the test results + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public testResultsPost(body: CompleteTestResults, observe?: 'body', reportProgress?: boolean): Observable; + public testResultsPost(body: CompleteTestResults, observe?: 'response', reportProgress?: boolean): Observable>; + public testResultsPost(body: CompleteTestResults, observe?: 'events', reportProgress?: boolean): Observable>; + public testResultsPost(body: CompleteTestResults, observe: any = 'body', reportProgress: boolean = false ): Observable { + + if (body === null || body === undefined) { + throw new Error('Required parameter body was null or undefined when calling testResultsPost.'); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + 'application/json' + ]; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request('post',`${this.basePath}/test-results`, + { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + } diff --git a/src/app/api/test-results/api/getTestResults.service.ts b/src/app/api/test-results/api/getTestResults.service.ts index bff70116a5..98e13ed5af 100644 --- a/src/app/api/test-results/api/getTestResults.service.ts +++ b/src/app/api/test-results/api/getTestResults.service.ts @@ -7,157 +7,128 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - */ /* tslint:disable:no-unused-variable member-ordering */ + *//* tslint:disable:no-unused-variable member-ordering */ -import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; -import { Inject, Injectable, Optional } from '@angular/core'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { Inject, Injectable, Optional } from '@angular/core'; +import { HttpClient, HttpHeaders, HttpParams, + HttpResponse, HttpEvent } from '@angular/common/http'; +import { CustomHttpUrlEncodingCodec } from '../encoder'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { TestResults } from '../model/testResults'; -import { Configuration } from '../configuration'; -import { BASE_PATH } from '../variables'; +import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; +import { Configuration } from '../configuration'; + @Injectable() export class GetTestResultsService { - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor( - protected httpClient: HttpClient, - @Optional() @Inject(BASE_PATH) basePath: string, - @Optional() configuration: Configuration - ) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - /** - * Get a test results, for a particular Vin with status specified. - * - * @param systemNumber - * @param status The test result status - * @param fromDateTime The UTC ISO Date Time filter, if the fromDate and ToDate not specified by default to 2 years of data for now. - * @param toDateTime The UTC ISO DateTime filter. - * @param testResultId Query param to filter the test-results based on testResultId. - * @param version Query param to filter the test-results based on testVersion. If not present then GET will return the current test-result. Can be used only with testResultId query param, otherwise it is not taken into account. - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public testResultsSystemNumberGet( - systemNumber: string, - status?: string, - fromDateTime?: Date, - toDateTime?: Date, - testResultId?: string, - version?: string, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public testResultsSystemNumberGet( - systemNumber: string, - status?: string, - fromDateTime?: Date, - toDateTime?: Date, - testResultId?: string, - version?: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public testResultsSystemNumberGet( - systemNumber: string, - status?: string, - fromDateTime?: Date, - toDateTime?: Date, - testResultId?: string, - version?: string, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public testResultsSystemNumberGet( - systemNumber: string, - status?: string, - fromDateTime?: Date, - toDateTime?: Date, - testResultId?: string, - version?: string, - observe: any = 'body', - reportProgress = false - ): Observable { - if (systemNumber === null || systemNumber === undefined) { - throw new Error('Required parameter systemNumber was null or undefined when calling testResultsSystemNumberGet.'); - } - - let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); - if (status !== undefined && status !== null) { - queryParameters = queryParameters.set('status', status); - } - if (fromDateTime !== undefined && fromDateTime !== null) { - queryParameters = queryParameters.set('fromDateTime', fromDateTime.toISOString()); - } - if (toDateTime !== undefined && toDateTime !== null) { - queryParameters = queryParameters.set('toDateTime', toDateTime.toISOString()); - } - if (testResultId !== undefined && testResultId !== null) { - queryParameters = queryParameters.set('testResultId', testResultId); - } - if (version !== undefined && version !== null) { - queryParameters = queryParameters.set('version', version); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = - typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', `Bearer ${accessToken}`); - } - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = []; - - return this.httpClient.request( - 'get', - `${this.basePath}/test-results/${encodeURIComponent(String(systemNumber))}`, - { - params: queryParameters, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - } - ); - } + + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + + /** + * Get a test results, for a particular Vin with status specified. + * + * @param systemNumber + * @param status The test result status + * @param fromDateTime The UTC ISO Date Time filter, if the fromDate and ToDate not specified by default to 2 years of data for now. + * @param toDateTime The UTC ISO DateTime filter. + * @param testResultId Query param to filter the test-results based on testResultId. + * @param version Query param to filter the test-results based on testVersion. If not present then GET will return the current test-result. Can be used only with testResultId query param, otherwise it is not taken into account. + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public testResultsSystemNumberGet(systemNumber: string, status?: string, fromDateTime?: Date, toDateTime?: Date, testResultId?: string, version?: string, observe?: 'body', reportProgress?: boolean): Observable; + public testResultsSystemNumberGet(systemNumber: string, status?: string, fromDateTime?: Date, toDateTime?: Date, testResultId?: string, version?: string, observe?: 'response', reportProgress?: boolean): Observable>; + public testResultsSystemNumberGet(systemNumber: string, status?: string, fromDateTime?: Date, toDateTime?: Date, testResultId?: string, version?: string, observe?: 'events', reportProgress?: boolean): Observable>; + public testResultsSystemNumberGet(systemNumber: string, status?: string, fromDateTime?: Date, toDateTime?: Date, testResultId?: string, version?: string, observe: any = 'body', reportProgress: boolean = false ): Observable { + + if (systemNumber === null || systemNumber === undefined) { + throw new Error('Required parameter systemNumber was null or undefined when calling testResultsSystemNumberGet.'); + } + + + + + + + let queryParameters = new HttpParams({encoder: new CustomHttpUrlEncodingCodec()}); + if (status !== undefined && status !== null) { + queryParameters = queryParameters.set('status', status); + } + if (fromDateTime !== undefined && fromDateTime !== null) { + queryParameters = queryParameters.set('fromDateTime', fromDateTime.toISOString()); + } + if (toDateTime !== undefined && toDateTime !== null) { + queryParameters = queryParameters.set('toDateTime', toDateTime.toISOString()); + } + if (testResultId !== undefined && testResultId !== null) { + queryParameters = queryParameters.set('testResultId', testResultId); + } + if (version !== undefined && version !== null) { + queryParameters = queryParameters.set('version', version); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/json' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + ]; + + return this.httpClient.request('get',`${this.basePath}/test-results/${encodeURIComponent(String(systemNumber))}`, + { + params: queryParameters, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + } diff --git a/src/app/api/test-results/api/updateTestResults.service.ts b/src/app/api/test-results/api/updateTestResults.service.ts index c23a1edf93..a17a7e1bea 100644 --- a/src/app/api/test-results/api/updateTestResults.service.ts +++ b/src/app/api/test-results/api/updateTestResults.service.ts @@ -7,127 +7,111 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - */ /* tslint:disable:no-unused-variable member-ordering */ + *//* tslint:disable:no-unused-variable member-ordering */ -import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http'; -import { Inject, Injectable, Optional } from '@angular/core'; +import { Inject, Injectable, Optional } from '@angular/core'; +import { HttpClient, HttpHeaders, HttpParams, + HttpResponse, HttpEvent } from '@angular/common/http'; +import { CustomHttpUrlEncodingCodec } from '../encoder'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { CompleteTestResults } from '../model/completeTestResults'; -import { Configuration } from '../configuration'; -import { BASE_PATH } from '../variables'; +import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; +import { Configuration } from '../configuration'; + @Injectable() export class UpdateTestResultsService { - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor( - protected httpClient: HttpClient, - @Optional() @Inject(BASE_PATH) basePath: string, - @Optional() configuration: Configuration - ) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - /** - * Update a test result using the systemNumber and testResultId as unique identifiers. - * - * @param body The test result to be updated - * @param systemNumber - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public testResultsSystemNumberPut( - body: CompleteTestResults, - systemNumber: string, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public testResultsSystemNumberPut( - body: CompleteTestResults, - systemNumber: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public testResultsSystemNumberPut( - body: CompleteTestResults, - systemNumber: string, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public testResultsSystemNumberPut( - body: CompleteTestResults, - systemNumber: string, - observe: any = 'body', - reportProgress = false - ): Observable { - if (body === null || body === undefined) { - throw new Error('Required parameter body was null or undefined when calling testResultsSystemNumberPut.'); - } - - if (systemNumber === null || systemNumber === undefined) { - throw new Error('Required parameter systemNumber was null or undefined when calling testResultsSystemNumberPut.'); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = - typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', `Bearer ${accessToken}`); - } - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = ['application/json']; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request( - 'put', - `${this.basePath}/test-results/${encodeURIComponent(String(systemNumber))}`, - { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - } - ); - } + + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + + /** + * Update a test result using the systemNumber and testResultId as unique identifiers. + * + * @param body The test result to be updated + * @param systemNumber + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public testResultsSystemNumberPut(body: CompleteTestResults, systemNumber: string, observe?: 'body', reportProgress?: boolean): Observable; + public testResultsSystemNumberPut(body: CompleteTestResults, systemNumber: string, observe?: 'response', reportProgress?: boolean): Observable>; + public testResultsSystemNumberPut(body: CompleteTestResults, systemNumber: string, observe?: 'events', reportProgress?: boolean): Observable>; + public testResultsSystemNumberPut(body: CompleteTestResults, systemNumber: string, observe: any = 'body', reportProgress: boolean = false ): Observable { + + if (body === null || body === undefined) { + throw new Error('Required parameter body was null or undefined when calling testResultsSystemNumberPut.'); + } + + if (systemNumber === null || systemNumber === undefined) { + throw new Error('Required parameter systemNumber was null or undefined when calling testResultsSystemNumberPut.'); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/json' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + 'application/json' + ]; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request('put',`${this.basePath}/test-results/${encodeURIComponent(String(systemNumber))}`, + { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + } diff --git a/src/app/api/test-results/configuration.ts b/src/app/api/test-results/configuration.ts index 8a8c9a845e..82e8458f39 100644 --- a/src/app/api/test-results/configuration.ts +++ b/src/app/api/test-results/configuration.ts @@ -1,79 +1,79 @@ export interface ConfigurationParameters { - apiKeys?: { [key: string]: string }; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: {[ key: string ]: string}; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; } export class Configuration { - apiKeys?: { [key: string]: string }; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: {[ key: string ]: string}; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; - constructor(configurationParameters: ConfigurationParameters = {}) { - this.apiKeys = configurationParameters.apiKeys; - this.username = configurationParameters.username; - this.password = configurationParameters.password; - this.accessToken = configurationParameters.accessToken; - this.basePath = configurationParameters.basePath; - this.withCredentials = configurationParameters.withCredentials; - } + constructor(configurationParameters: ConfigurationParameters = {}) { + this.apiKeys = configurationParameters.apiKeys; + this.username = configurationParameters.username; + this.password = configurationParameters.password; + this.accessToken = configurationParameters.accessToken; + this.basePath = configurationParameters.basePath; + this.withCredentials = configurationParameters.withCredentials; + } - /** - * Select the correct content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param contentTypes - the array of content types that are available for selection - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderContentType(contentTypes: string[]): string | undefined { - if (contentTypes.length == 0) { - return undefined; - } + /** + * Select the correct content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param contentTypes - the array of content types that are available for selection + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderContentType (contentTypes: string[]): string | undefined { + if (contentTypes.length == 0) { + return undefined; + } - const type = contentTypes.find((x) => this.isJsonMime(x)); - if (type === undefined) { - return contentTypes[0]; - } - return type; - } + let type = contentTypes.find(x => this.isJsonMime(x)); + if (type === undefined) { + return contentTypes[0]; + } + return type; + } - /** - * Select the correct accept content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param accepts - the array of content types that are available for selection. - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderAccept(accepts: string[]): string | undefined { - if (accepts.length == 0) { - return undefined; - } + /** + * Select the correct accept content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param accepts - the array of content types that are available for selection. + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderAccept(accepts: string[]): string | undefined { + if (accepts.length == 0) { + return undefined; + } - const type = accepts.find((x) => this.isJsonMime(x)); - if (type === undefined) { - return accepts[0]; - } - return type; - } + let type = accepts.find(x => this.isJsonMime(x)); + if (type === undefined) { + return accepts[0]; + } + return type; + } - /** - * Check if the given MIME is a JSON MIME. - * JSON MIME examples: - * application/json - * application/json; charset=UTF8 - * APPLICATION/JSON - * application/vnd.company+json - * @param mime - MIME (Multipurpose Internet Mail Extensions) - * @return True if the given MIME is JSON, false otherwise. - */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); - return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } } diff --git a/src/app/api/test-results/encoder.ts b/src/app/api/test-results/encoder.ts index b80138427a..5d0fb0e90c 100644 --- a/src/app/api/test-results/encoder.ts +++ b/src/app/api/test-results/encoder.ts @@ -6,13 +6,12 @@ import { HttpUrlEncodingCodec } from '@angular/common/http'; * See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 */ export class CustomHttpUrlEncodingCodec extends HttpUrlEncodingCodec { - override encodeKey(key: string): string { - const k = super.encodeKey(key); - return k.replace(/\+/gi, '%2B'); - } - - override encodeValue(value: string): string { - const v = super.encodeValue(value); - return v.replace(/\+/gi, '%2B'); - } + override encodeKey(k: string): string { + k = super.encodeKey(k); + return k.replace(/\+/gi, '%2B'); + } + override encodeValue(v: string): string { + v = super.encodeValue(v); + return v.replace(/\+/gi, '%2B'); + } } diff --git a/src/app/api/test-results/index.ts b/src/app/api/test-results/index.ts index 410623f1c9..c312b70fa3 100644 --- a/src/app/api/test-results/index.ts +++ b/src/app/api/test-results/index.ts @@ -2,4 +2,4 @@ export * from './api/api'; export * from './model/models'; export * from './variables'; export * from './configuration'; -export * from './api.module'; +export * from './api.module'; \ No newline at end of file diff --git a/src/app/api/test-results/model/completeTestResults.ts b/src/app/api/test-results/model/completeTestResults.ts index f788cb0513..903399b351 100644 --- a/src/app/api/test-results/model/completeTestResults.ts +++ b/src/app/api/test-results/model/completeTestResults.ts @@ -11,225 +11,196 @@ import { CompleteTestResultsVehicleClass } from './completeTestResultsVehicleClass'; import { TestTypes } from './testTypes'; -export interface CompleteTestResults { - /** - * It defines the link between a test and the vehicle, by uniqeuly identifing the vehicle. - */ - systemNumber?: string; - /** - * Mandatory for PSV and HGV, not applicable to TRL - */ - vrm?: string; - /** - * Mandatory for TRL, not applicable to PSV and HGV - */ - trailerId?: string; - vin?: string; - /** - * Not sent from FE, calculated in the BE. When the test result is submitted, in BE, the VRM of the vehicle will be copied into vehicleId also. - */ - vehicleId?: string; - /** - * Not sent from FE, calculated in the BE. - */ - deletionFlag?: boolean; - /** - * Array of archived test-results. The test-results in this array won't have the testHistory attribute and testVersion will always be archived. Should not be sent when performing an update - */ - testHistory?: Array; - /** - * Tests submitted from the mobile app won't have this attribute. Tests updated/created by VTM will do. - */ - testVersion?: CompleteTestResults.TestVersionEnum; - /** - * Applicable only when updating/creating a test from VTM - */ - reasonForCreation?: string; - /** - * Not sent from FE, calculated in the BE. - */ - createdAt?: Date; - /** - * Applicable only when updating/creating a test from VTM - */ - createdByName?: string; - /** - * Applicable only when updating/creating a test from VTM - */ - createdById?: string; - /** - * Not sent from FE, calculated in the BE. - */ - lastUpdatedAt?: Date; - /** - * Applicable only when updating/creating a test from VTM - */ - lastUpdatedByName?: string; - /** - * Applicable only when updating/creating a test from VTM - */ - lastUpdatedById?: string; - /** - * Not sent from FE, calculated in BE. Applicable only when updating a test from VTM. Used to determine if a certificate should be emailed or not after an update. - */ - shouldEmailCertificate?: string; - testStationName?: string; - testStationPNumber?: string; - testStationType?: CompleteTestResults.TestStationTypeEnum; - testerName?: string; - testerStaffId?: string; - testResultId?: string; - testerEmailAddress?: string; - testStartTimestamp?: Date; - testEndTimestamp?: Date; - testStatus?: CompleteTestResults.TestStatusEnum; - /** - * Required for Cancelled tests. Nullable only for Submitted and Abandoned tests. - */ - reasonForCancellation?: string; - vehicleClass?: CompleteTestResultsVehicleClass; - /** - * Used for car and lgv. - */ - vehicleSubclass?: Array; - vehicleType?: CompleteTestResults.VehicleTypeEnum; - /** - * mandatory for PSV only, not applicable for HGV and TRL - */ - numberOfSeats?: number; - vehicleConfiguration?: CompleteTestResults.VehicleConfigurationEnum; - /** - * Nullable only for Cancelled tests & not applicable to TRL - */ - odometerReading?: number; - /** - * Nullable only for Cancelled tests & not applicable to TRL - */ - odometerReadingUnits?: CompleteTestResults.OdometerReadingUnitsEnum; - preparerId?: string; - preparerName?: string; - numberOfWheelsDriven?: number; - /** - * Nullable only for Cancelled tests. - */ - euVehicleCategory?: CompleteTestResults.EuVehicleCategoryEnum; - /** - * Nullable only for Cancelled tests. - */ - countryOfRegistration?: string; - /** - * Mandatory for PSV only & not applicable to HGV and TRL - */ - vehicleSize?: CompleteTestResults.VehicleSizeEnum; - noOfAxles?: number; - /** - * Used only for PSV and HGV - */ - regnDate?: string; - /** - * Used only for TRL - */ - firstUseDate?: string; - testTypes?: TestTypes; +export interface CompleteTestResults { + /** + * It defines the link between a test and the vehicle, by uniqeuly identifing the vehicle. + */ + systemNumber?: string; + /** + * Mandatory for PSV and HGV, not applicable to TRL + */ + vrm?: string; + /** + * Mandatory for TRL, not applicable to PSV and HGV + */ + trailerId?: string; + vin?: string; + /** + * Not sent from FE, calculated in the BE. When the test result is submitted, in BE, the VRM of the vehicle will be copied into vehicleId also. + */ + vehicleId?: string; + /** + * Not sent from FE, calculated in the BE. + */ + deletionFlag?: boolean; + /** + * Array of archived test-results. The test-results in this array won't have the testHistory attribute and testVersion will always be archived. Should not be sent when performing an update + */ + testHistory?: Array; + /** + * Tests submitted from the mobile app won't have this attribute. Tests updated/created by VTM will do. + */ + testVersion?: CompleteTestResults.TestVersionEnum; + /** + * Applicable only when updating/creating a test from VTM + */ + reasonForCreation?: string; + /** + * Not sent from FE, calculated in the BE. + */ + createdAt?: Date; + /** + * Applicable only when updating/creating a test from VTM + */ + createdByName?: string; + /** + * Applicable only when updating/creating a test from VTM + */ + createdById?: string; + /** + * Not sent from FE, calculated in the BE. + */ + lastUpdatedAt?: Date; + /** + * Applicable only when updating/creating a test from VTM + */ + lastUpdatedByName?: string; + /** + * Applicable only when updating/creating a test from VTM + */ + lastUpdatedById?: string; + /** + * Not sent from FE, calculated in BE. Applicable only when updating a test from VTM. Used to determine if a certificate should be emailed or not after an update. + */ + shouldEmailCertificate?: string; + testStationName?: string; + testStationPNumber?: string; + testStationType?: CompleteTestResults.TestStationTypeEnum; + testerName?: string; + testerStaffId?: string; + testResultId?: string; + testerEmailAddress?: string; + testStartTimestamp?: Date; + testEndTimestamp?: Date; + testStatus?: CompleteTestResults.TestStatusEnum; + /** + * Required for Cancelled tests. Nullable only for Submitted and Abandoned tests. + */ + reasonForCancellation?: string; + vehicleClass?: CompleteTestResultsVehicleClass; + /** + * Used for car and lgv. + */ + vehicleSubclass?: Array; + vehicleType?: CompleteTestResults.VehicleTypeEnum; + /** + * mandatory for PSV only, not applicable for HGV and TRL + */ + numberOfSeats?: number; + vehicleConfiguration?: CompleteTestResults.VehicleConfigurationEnum; + /** + * Nullable only for Cancelled tests & not applicable to TRL + */ + odometerReading?: number; + /** + * Nullable only for Cancelled tests & not applicable to TRL + */ + odometerReadingUnits?: CompleteTestResults.OdometerReadingUnitsEnum; + preparerId?: string; + preparerName?: string; + numberOfWheelsDriven?: number; + /** + * Nullable only for Cancelled tests. + */ + euVehicleCategory?: CompleteTestResults.EuVehicleCategoryEnum; + /** + * Nullable only for Cancelled tests. + */ + countryOfRegistration?: string; + /** + * Mandatory for PSV only & not applicable to HGV and TRL + */ + vehicleSize?: CompleteTestResults.VehicleSizeEnum; + noOfAxles?: number; + /** + * Used only for PSV and HGV + */ + regnDate?: string; + /** + * Used only for TRL + */ + firstUseDate?: string; + testTypes?: TestTypes; } export namespace CompleteTestResults { - export type TestVersionEnum = 'current' | 'archived'; - export const TestVersionEnum = { - Current: 'current' as TestVersionEnum, - Archived: 'archived' as TestVersionEnum, - }; - export type TestStationTypeEnum = 'atf' | 'gvts' | 'hq'; - export const TestStationTypeEnum = { - Atf: 'atf' as TestStationTypeEnum, - Gvts: 'gvts' as TestStationTypeEnum, - Hq: 'hq' as TestStationTypeEnum, - }; - export type TestStatusEnum = 'submitted' | 'cancelled'; - export const TestStatusEnum = { - Submitted: 'submitted' as TestStatusEnum, - Cancelled: 'cancelled' as TestStatusEnum, - }; - export type VehicleTypeEnum = 'psv' | 'hgv' | 'trl' | 'car' | 'lgv' | 'motorcycle'; - export const VehicleTypeEnum = { - Psv: 'psv' as VehicleTypeEnum, - Hgv: 'hgv' as VehicleTypeEnum, - Trl: 'trl' as VehicleTypeEnum, - Car: 'car' as VehicleTypeEnum, - Lgv: 'lgv' as VehicleTypeEnum, - Motorcycle: 'motorcycle' as VehicleTypeEnum, - }; - export type VehicleConfigurationEnum = - | 'rigid' - | 'articulated' - | 'centre axle drawbar' - | 'semi-car transporter' - | 'semi-trailer' - | 'low loader' - | 'other' - | 'drawbar' - | 'four-in-line' - | 'dolly' - | 'full drawbar'; - export const VehicleConfigurationEnum = { - Rigid: 'rigid' as VehicleConfigurationEnum, - Articulated: 'articulated' as VehicleConfigurationEnum, - CentreAxleDrawbar: 'centre axle drawbar' as VehicleConfigurationEnum, - SemiCarTransporter: 'semi-car transporter' as VehicleConfigurationEnum, - SemiTrailer: 'semi-trailer' as VehicleConfigurationEnum, - LowLoader: 'low loader' as VehicleConfigurationEnum, - Other: 'other' as VehicleConfigurationEnum, - Drawbar: 'drawbar' as VehicleConfigurationEnum, - FourInLine: 'four-in-line' as VehicleConfigurationEnum, - Dolly: 'dolly' as VehicleConfigurationEnum, - FullDrawbar: 'full drawbar' as VehicleConfigurationEnum, - }; - export type OdometerReadingUnitsEnum = 'kilometres' | 'miles'; - export const OdometerReadingUnitsEnum = { - Kilometres: 'kilometres' as OdometerReadingUnitsEnum, - Miles: 'miles' as OdometerReadingUnitsEnum, - }; - export type EuVehicleCategoryEnum = - | 'm1' - | 'm2' - | 'm3' - | 'n1' - | 'n2' - | 'n3' - | 'o1' - | 'o2' - | 'o3' - | 'o4' - | 'l1e-a' - | 'l1e' - | 'l2e' - | 'l3e' - | 'l4e' - | 'l5e' - | 'l6e' - | 'l7e'; - export const EuVehicleCategoryEnum = { - M1: 'm1' as EuVehicleCategoryEnum, - M2: 'm2' as EuVehicleCategoryEnum, - M3: 'm3' as EuVehicleCategoryEnum, - N1: 'n1' as EuVehicleCategoryEnum, - N2: 'n2' as EuVehicleCategoryEnum, - N3: 'n3' as EuVehicleCategoryEnum, - O1: 'o1' as EuVehicleCategoryEnum, - O2: 'o2' as EuVehicleCategoryEnum, - O3: 'o3' as EuVehicleCategoryEnum, - O4: 'o4' as EuVehicleCategoryEnum, - L1eA: 'l1e-a' as EuVehicleCategoryEnum, - L1e: 'l1e' as EuVehicleCategoryEnum, - L2e: 'l2e' as EuVehicleCategoryEnum, - L3e: 'l3e' as EuVehicleCategoryEnum, - L4e: 'l4e' as EuVehicleCategoryEnum, - L5e: 'l5e' as EuVehicleCategoryEnum, - L6e: 'l6e' as EuVehicleCategoryEnum, - L7e: 'l7e' as EuVehicleCategoryEnum, - }; - export type VehicleSizeEnum = 'large' | 'small'; - export const VehicleSizeEnum = { - Large: 'large' as VehicleSizeEnum, - Small: 'small' as VehicleSizeEnum, - }; -} + export type TestVersionEnum = 'current' | 'archived'; + export const TestVersionEnum = { + Current: 'current' as TestVersionEnum, + Archived: 'archived' as TestVersionEnum + }; + export type TestStationTypeEnum = 'atf' | 'gvts' | 'hq'; + export const TestStationTypeEnum = { + Atf: 'atf' as TestStationTypeEnum, + Gvts: 'gvts' as TestStationTypeEnum, + Hq: 'hq' as TestStationTypeEnum + }; + export type TestStatusEnum = 'submitted' | 'cancelled'; + export const TestStatusEnum = { + Submitted: 'submitted' as TestStatusEnum, + Cancelled: 'cancelled' as TestStatusEnum + }; + export type VehicleTypeEnum = 'psv' | 'hgv' | 'trl' | 'car' | 'lgv' | 'motorcycle'; + export const VehicleTypeEnum = { + Psv: 'psv' as VehicleTypeEnum, + Hgv: 'hgv' as VehicleTypeEnum, + Trl: 'trl' as VehicleTypeEnum, + Car: 'car' as VehicleTypeEnum, + Lgv: 'lgv' as VehicleTypeEnum, + Motorcycle: 'motorcycle' as VehicleTypeEnum + }; + export type VehicleConfigurationEnum = 'rigid' | 'articulated' | 'centre axle drawbar' | 'semi-car transporter' | 'semi-trailer' | 'low loader' | 'other' | 'drawbar' | 'four-in-line' | 'dolly' | 'full drawbar'; + export const VehicleConfigurationEnum = { + Rigid: 'rigid' as VehicleConfigurationEnum, + Articulated: 'articulated' as VehicleConfigurationEnum, + CentreAxleDrawbar: 'centre axle drawbar' as VehicleConfigurationEnum, + SemiCarTransporter: 'semi-car transporter' as VehicleConfigurationEnum, + SemiTrailer: 'semi-trailer' as VehicleConfigurationEnum, + LowLoader: 'low loader' as VehicleConfigurationEnum, + Other: 'other' as VehicleConfigurationEnum, + Drawbar: 'drawbar' as VehicleConfigurationEnum, + FourInLine: 'four-in-line' as VehicleConfigurationEnum, + Dolly: 'dolly' as VehicleConfigurationEnum, + FullDrawbar: 'full drawbar' as VehicleConfigurationEnum + }; + export type OdometerReadingUnitsEnum = 'kilometres' | 'miles'; + export const OdometerReadingUnitsEnum = { + Kilometres: 'kilometres' as OdometerReadingUnitsEnum, + Miles: 'miles' as OdometerReadingUnitsEnum + }; + export type EuVehicleCategoryEnum = 'm1' | 'm2' | 'm3' | 'n1' | 'n2' | 'n3' | 'o1' | 'o2' | 'o3' | 'o4' | 'l1e-a' | 'l1e' | 'l2e' | 'l3e' | 'l4e' | 'l5e' | 'l6e' | 'l7e'; + export const EuVehicleCategoryEnum = { + M1: 'm1' as EuVehicleCategoryEnum, + M2: 'm2' as EuVehicleCategoryEnum, + M3: 'm3' as EuVehicleCategoryEnum, + N1: 'n1' as EuVehicleCategoryEnum, + N2: 'n2' as EuVehicleCategoryEnum, + N3: 'n3' as EuVehicleCategoryEnum, + O1: 'o1' as EuVehicleCategoryEnum, + O2: 'o2' as EuVehicleCategoryEnum, + O3: 'o3' as EuVehicleCategoryEnum, + O4: 'o4' as EuVehicleCategoryEnum, + L1eA: 'l1e-a' as EuVehicleCategoryEnum, + L1e: 'l1e' as EuVehicleCategoryEnum, + L2e: 'l2e' as EuVehicleCategoryEnum, + L3e: 'l3e' as EuVehicleCategoryEnum, + L4e: 'l4e' as EuVehicleCategoryEnum, + L5e: 'l5e' as EuVehicleCategoryEnum, + L6e: 'l6e' as EuVehicleCategoryEnum, + L7e: 'l7e' as EuVehicleCategoryEnum + }; + export type VehicleSizeEnum = 'large' | 'small'; + export const VehicleSizeEnum = { + Large: 'large' as VehicleSizeEnum, + Small: 'small' as VehicleSizeEnum + }; +} \ No newline at end of file diff --git a/src/app/api/test-results/model/completeTestResultsVehicleClass.ts b/src/app/api/test-results/model/completeTestResultsVehicleClass.ts index f9efbd425b..fa049e3663 100644 --- a/src/app/api/test-results/model/completeTestResultsVehicleClass.ts +++ b/src/app/api/test-results/model/completeTestResultsVehicleClass.ts @@ -12,48 +12,37 @@ /** * Mandatory only for motorcycles. 2 = MotorBikes over 200cc or with a sidecar, N = Not Applicable, S = Small PSV i.e less than or equal to 22 seats, 1 = Motorbikes upto 200cc, T = Trailer, L = LARGE PSV (ie. greater than 23 seats), 3 = 3 wheelers, V = Heavy Goods Vehicle */ -export interface CompleteTestResultsVehicleClass { - code?: CompleteTestResultsVehicleClass.CodeEnum; - description?: CompleteTestResultsVehicleClass.DescriptionEnum; +export interface CompleteTestResultsVehicleClass { + code?: CompleteTestResultsVehicleClass.CodeEnum; + description?: CompleteTestResultsVehicleClass.DescriptionEnum; } export namespace CompleteTestResultsVehicleClass { - export type CodeEnum = '2' | 'n' | 's' | '1' | 't' | 'l' | '3' | 'v' | '4' | '7' | '5'; - export const CodeEnum = { - _2: '2' as CodeEnum, - N: 'n' as CodeEnum, - S: 's' as CodeEnum, - _1: '1' as CodeEnum, - T: 't' as CodeEnum, - L: 'l' as CodeEnum, - _3: '3' as CodeEnum, - V: 'v' as CodeEnum, - _4: '4' as CodeEnum, - _7: '7' as CodeEnum, - _5: '5' as CodeEnum, - }; - export type DescriptionEnum = - | 'motorbikes over 200cc or with a sidecar' - | 'not applicable' - | 'small psv (ie: less than or equal to 22 seats)' - | 'motorbikes up to 200cc' - | 'trailer' - | 'large psv(ie: greater than 23 seats)' - | '3 wheelers' - | 'heavy goods vehicle' - | 'MOT class 4' - | 'MOT class 7' - | 'MOT class 5'; - export const DescriptionEnum = { - MotorbikesOver200ccOrWithASidecar: 'motorbikes over 200cc or with a sidecar' as DescriptionEnum, - NotApplicable: 'not applicable' as DescriptionEnum, - SmallPsvIeLessThanOrEqualTo22Seats: 'small psv (ie: less than or equal to 22 seats)' as DescriptionEnum, - MotorbikesUpTo200cc: 'motorbikes up to 200cc' as DescriptionEnum, - Trailer: 'trailer' as DescriptionEnum, - LargePsvIeGreaterThan23Seats: 'large psv(ie: greater than 23 seats)' as DescriptionEnum, - _3Wheelers: '3 wheelers' as DescriptionEnum, - HeavyGoodsVehicle: 'heavy goods vehicle' as DescriptionEnum, - MOTClass4: 'MOT class 4' as DescriptionEnum, - MOTClass7: 'MOT class 7' as DescriptionEnum, - MOTClass5: 'MOT class 5' as DescriptionEnum, - }; -} + export type CodeEnum = '2' | 'n' | 's' | '1' | 't' | 'l' | '3' | 'v' | '4' | '7' | '5'; + export const CodeEnum = { + _2: '2' as CodeEnum, + N: 'n' as CodeEnum, + S: 's' as CodeEnum, + _1: '1' as CodeEnum, + T: 't' as CodeEnum, + L: 'l' as CodeEnum, + _3: '3' as CodeEnum, + V: 'v' as CodeEnum, + _4: '4' as CodeEnum, + _7: '7' as CodeEnum, + _5: '5' as CodeEnum, + }; + export type DescriptionEnum = 'motorbikes over 200cc or with a sidecar' | 'not applicable' | 'small psv (ie: less than or equal to 22 seats)' | 'motorbikes up to 200cc' | 'trailer' | 'large psv(ie: greater than 23 seats)' | '3 wheelers' | 'heavy goods vehicle' | 'MOT class 4' | 'MOT class 7' | 'MOT class 5'; + export const DescriptionEnum = { + MotorbikesOver200ccOrWithASidecar: 'motorbikes over 200cc or with a sidecar' as DescriptionEnum, + NotApplicable: 'not applicable' as DescriptionEnum, + SmallPsvIeLessThanOrEqualTo22Seats: 'small psv (ie: less than or equal to 22 seats)' as DescriptionEnum, + MotorbikesUpTo200cc: 'motorbikes up to 200cc' as DescriptionEnum, + Trailer: 'trailer' as DescriptionEnum, + LargePsvIeGreaterThan23Seats: 'large psv(ie: greater than 23 seats)' as DescriptionEnum, + _3Wheelers: '3 wheelers' as DescriptionEnum, + HeavyGoodsVehicle: 'heavy goods vehicle' as DescriptionEnum, + MOTClass4: 'MOT class 4' as DescriptionEnum, + MOTClass7: 'MOT class 7' as DescriptionEnum, + MOTClass5: 'MOT class 5' as DescriptionEnum, + }; +} \ No newline at end of file diff --git a/src/app/api/test-results/model/customDefect.ts b/src/app/api/test-results/model/customDefect.ts index 4e6823c024..aab28f500a 100644 --- a/src/app/api/test-results/model/customDefect.ts +++ b/src/app/api/test-results/model/customDefect.ts @@ -9,8 +9,8 @@ * Do not edit the class manually. */ -export interface CustomDefect { - referenceNumber?: string; - defectName?: string; - defectNotes?: string; -} +export interface CustomDefect { + referenceNumber?: string; + defectName?: string; + defectNotes?: string; +} \ No newline at end of file diff --git a/src/app/api/test-results/model/customDefects.ts b/src/app/api/test-results/model/customDefects.ts index a306d4e1a1..65b545a8aa 100644 --- a/src/app/api/test-results/model/customDefects.ts +++ b/src/app/api/test-results/model/customDefects.ts @@ -10,4 +10,5 @@ */ import { CustomDefect } from './customDefect'; -export interface CustomDefects extends Array {} +export interface CustomDefects extends Array { +} \ No newline at end of file diff --git a/src/app/api/test-results/model/defect.ts b/src/app/api/test-results/model/defect.ts index 78918ffdf0..f7c2885e2a 100644 --- a/src/app/api/test-results/model/defect.ts +++ b/src/app/api/test-results/model/defect.ts @@ -10,30 +10,30 @@ */ import { DefectAdditionalInformation } from './defectAdditionalInformation'; -export interface Defect { - imNumber?: number; - imDescription?: string; - additionalInformation?: DefectAdditionalInformation; - itemNumber?: number; - itemDescription?: string; - deficiencyRef?: string; - deficiencyId?: string; - deficiencySubId?: string; - /** - * It is mandatory for both Submitted or Cancelled tests. It is only nullable in the DB for the migration purposes. - */ - deficiencyCategory?: Defect.DeficiencyCategoryEnum; - deficiencyText?: string; - stdForProhibition?: boolean; - prs?: boolean; - prohibitionIssued?: boolean; +export interface Defect { + imNumber?: number; + imDescription?: string; + additionalInformation?: DefectAdditionalInformation; + itemNumber?: number; + itemDescription?: string; + deficiencyRef?: string; + deficiencyId?: string; + deficiencySubId?: string; + /** + * It is mandatory for both Submitted or Cancelled tests. It is only nullable in the DB for the migration purposes. + */ + deficiencyCategory?: Defect.DeficiencyCategoryEnum; + deficiencyText?: string; + stdForProhibition?: boolean; + prs?: boolean; + prohibitionIssued?: boolean; } export namespace Defect { - export type DeficiencyCategoryEnum = 'advisory' | 'dangerous' | 'major' | 'minor'; - export const DeficiencyCategoryEnum = { - Advisory: 'advisory' as DeficiencyCategoryEnum, - Dangerous: 'dangerous' as DeficiencyCategoryEnum, - Major: 'major' as DeficiencyCategoryEnum, - Minor: 'minor' as DeficiencyCategoryEnum, - }; -} + export type DeficiencyCategoryEnum = 'advisory' | 'dangerous' | 'major' | 'minor'; + export const DeficiencyCategoryEnum = { + Advisory: 'advisory' as DeficiencyCategoryEnum, + Dangerous: 'dangerous' as DeficiencyCategoryEnum, + Major: 'major' as DeficiencyCategoryEnum, + Minor: 'minor' as DeficiencyCategoryEnum + }; +} \ No newline at end of file diff --git a/src/app/api/test-results/model/defectAdditionalInformation.ts b/src/app/api/test-results/model/defectAdditionalInformation.ts index a94ee2b6b8..27ffd34e13 100644 --- a/src/app/api/test-results/model/defectAdditionalInformation.ts +++ b/src/app/api/test-results/model/defectAdditionalInformation.ts @@ -10,7 +10,7 @@ */ import { DefectAdditionalInformationLocation } from './defectAdditionalInformationLocation'; -export interface DefectAdditionalInformation { - location?: DefectAdditionalInformationLocation; - notes?: string; -} +export interface DefectAdditionalInformation { + location?: DefectAdditionalInformationLocation; + notes?: string; +} \ No newline at end of file diff --git a/src/app/api/test-results/model/defectAdditionalInformationLocation.ts b/src/app/api/test-results/model/defectAdditionalInformationLocation.ts index 6cb1472202..1c4104f52d 100644 --- a/src/app/api/test-results/model/defectAdditionalInformationLocation.ts +++ b/src/app/api/test-results/model/defectAdditionalInformationLocation.ts @@ -9,35 +9,35 @@ * Do not edit the class manually. */ -export interface DefectAdditionalInformationLocation { - vertical?: DefectAdditionalInformationLocation.VerticalEnum; - horizontal?: DefectAdditionalInformationLocation.HorizontalEnum; - lateral?: DefectAdditionalInformationLocation.LateralEnum; - longitudinal?: DefectAdditionalInformationLocation.LongitudinalEnum; - rowNumber?: number; - seatNumber?: number; - axleNumber?: number; +export interface DefectAdditionalInformationLocation { + vertical?: DefectAdditionalInformationLocation.VerticalEnum; + horizontal?: DefectAdditionalInformationLocation.HorizontalEnum; + lateral?: DefectAdditionalInformationLocation.LateralEnum; + longitudinal?: DefectAdditionalInformationLocation.LongitudinalEnum; + rowNumber?: number; + seatNumber?: number; + axleNumber?: number; } export namespace DefectAdditionalInformationLocation { - export type VerticalEnum = 'upper' | 'lower'; - export const VerticalEnum = { - Upper: 'upper' as VerticalEnum, - Lower: 'lower' as VerticalEnum, - }; - export type HorizontalEnum = 'inner' | 'outer'; - export const HorizontalEnum = { - Inner: 'inner' as HorizontalEnum, - Outer: 'outer' as HorizontalEnum, - }; - export type LateralEnum = 'nearside' | 'centre' | 'offside'; - export const LateralEnum = { - Nearside: 'nearside' as LateralEnum, - Centre: 'centre' as LateralEnum, - Offside: 'offside' as LateralEnum, - }; - export type LongitudinalEnum = 'front' | 'rear'; - export const LongitudinalEnum = { - Front: 'front' as LongitudinalEnum, - Rear: 'rear' as LongitudinalEnum, - }; -} + export type VerticalEnum = 'upper' | 'lower'; + export const VerticalEnum = { + Upper: 'upper' as VerticalEnum, + Lower: 'lower' as VerticalEnum + }; + export type HorizontalEnum = 'inner' | 'outer'; + export const HorizontalEnum = { + Inner: 'inner' as HorizontalEnum, + Outer: 'outer' as HorizontalEnum + }; + export type LateralEnum = 'nearside' | 'centre' | 'offside'; + export const LateralEnum = { + Nearside: 'nearside' as LateralEnum, + Centre: 'centre' as LateralEnum, + Offside: 'offside' as LateralEnum + }; + export type LongitudinalEnum = 'front' | 'rear'; + export const LongitudinalEnum = { + Front: 'front' as LongitudinalEnum, + Rear: 'rear' as LongitudinalEnum + }; +} \ No newline at end of file diff --git a/src/app/api/test-results/model/defects.ts b/src/app/api/test-results/model/defects.ts index f7423b4d7b..bf6bfd9a68 100644 --- a/src/app/api/test-results/model/defects.ts +++ b/src/app/api/test-results/model/defects.ts @@ -10,4 +10,5 @@ */ import { Defect } from './defect'; -export interface Defects extends Array {} +export interface Defects extends Array { +} \ No newline at end of file diff --git a/src/app/api/test-results/model/testResults.ts b/src/app/api/test-results/model/testResults.ts index 30169ac46a..8d16693b18 100644 --- a/src/app/api/test-results/model/testResults.ts +++ b/src/app/api/test-results/model/testResults.ts @@ -10,4 +10,5 @@ */ import { CompleteTestResults } from './completeTestResults'; -export interface TestResults extends Array {} +export interface TestResults extends Array { +} \ No newline at end of file diff --git a/src/app/api/test-results/model/testTypeRecords.ts b/src/app/api/test-results/model/testTypeRecords.ts index dc1a3c4736..f9f6ae0670 100644 --- a/src/app/api/test-results/model/testTypeRecords.ts +++ b/src/app/api/test-results/model/testTypeRecords.ts @@ -9,4 +9,5 @@ * Do not edit the class manually. */ -export type TestTypeRecords = {}; +export interface TestTypeRecords { +} \ No newline at end of file diff --git a/src/app/api/test-results/model/testTypeResults.ts b/src/app/api/test-results/model/testTypeResults.ts index b5be1b5b43..bcd8933add 100644 --- a/src/app/api/test-results/model/testTypeResults.ts +++ b/src/app/api/test-results/model/testTypeResults.ts @@ -12,137 +12,130 @@ import { CustomDefects } from './customDefects'; import { Defects } from './defects'; import { TestTypeResultsModType } from './testTypeResultsModType'; -export interface TestTypeResults { - /** - * Not sent from FE, calculated in the BE. - */ - createdAt?: Date; - /** - * Not sent from FE, calculated in the BE. - */ - lastUpdatedAt?: Date; - /** - * Not sent from FE, calculated in the BE. - */ - deletionFlag?: boolean; - /** - * Not sent from FE, calculated in the BE. - */ - testCode?: string; - testTypeName?: string; - name?: string; - testTypeId?: string; - /** - * Not sent from FE, calculated in the BE. - */ - testNumber?: string; - certificateNumber?: string; - secondaryCertificateNumber?: string; - /** - * Not sent from FE, calculated in the BE. - */ - certificateLink?: string; - /** - * Sent form FE only for LEC tests. For the rest of the test types it is not sent from FE, and calculated in the BE. - */ - testExpiryDate?: Date; - /** - * Not sent from FE, calculated in the BE. - */ - testAnniversaryDate?: Date; - testTypeStartTimestamp?: Date; - /** - * Nullable only for Cancelled tests. - */ - testTypeEndTimestamp?: Date; - /** - * Sent from FE. Used to determine which test-type was updated/archived - */ - statusUpdatedFlag?: boolean; - /** - * mandatory for PSV only, not applicable for HGV and TRL - */ - numberOfSeatbeltsFitted?: number; - /** - * mandatory for PSV only, not applicable for HGV and TRL - */ - lastSeatbeltInstallationCheckDate?: string; - /** - * mandatory for PSV only, not applicable for HGV and TRL - */ - seatbeltInstallationCheckDate?: boolean; - /** - * Nullable only for Cancelled tests. - */ - testResult?: TestTypeResults.TestResultEnum; - prohibitionIssued?: boolean; - /** - * Required for Abandoned tests. - */ - reasonForAbandoning?: string; - additionalNotesRecorded?: string; - additionalCommentsForAbandon?: string; - modType?: TestTypeResultsModType; - /** - * Used only for LEC tests. - */ - emissionStandard?: TestTypeResults.EmissionStandardEnum; - /** - * Used only for LEC tests. - */ - fuelType?: TestTypeResults.FuelTypeEnum; - /** - * Used only for LEC tests. - */ - particulateTrapFitted?: string; - /** - * Used only for LEC tests. - */ - particulateTrapSerialNumber?: string; - /** - * Used only for LEC tests. - */ - modificationTypeUsed?: string; - /** - * Used only for LEC tests. - */ - smokeTestKLimitApplied?: string; - defects?: Defects; - customDefects?: CustomDefects; +export interface TestTypeResults { + /** + * Not sent from FE, calculated in the BE. + */ + createdAt?: Date; + /** + * Not sent from FE, calculated in the BE. + */ + lastUpdatedAt?: Date; + /** + * Not sent from FE, calculated in the BE. + */ + deletionFlag?: boolean; + /** + * Not sent from FE, calculated in the BE. + */ + testCode?: string; + testTypeName?: string; + name?: string; + testTypeId?: string; + /** + * Not sent from FE, calculated in the BE. + */ + testNumber?: string; + certificateNumber?: string; + secondaryCertificateNumber?: string; + /** + * Not sent from FE, calculated in the BE. + */ + certificateLink?: string; + /** + * Sent form FE only for LEC tests. For the rest of the test types it is not sent from FE, and calculated in the BE. + */ + testExpiryDate?: Date; + /** + * Not sent from FE, calculated in the BE. + */ + testAnniversaryDate?: Date; + testTypeStartTimestamp?: Date; + /** + * Nullable only for Cancelled tests. + */ + testTypeEndTimestamp?: Date; + /** + * Sent from FE. Used to determine which test-type was updated/archived + */ + statusUpdatedFlag?: boolean; + /** + * mandatory for PSV only, not applicable for HGV and TRL + */ + numberOfSeatbeltsFitted?: number; + /** + * mandatory for PSV only, not applicable for HGV and TRL + */ + lastSeatbeltInstallationCheckDate?: string; + /** + * mandatory for PSV only, not applicable for HGV and TRL + */ + seatbeltInstallationCheckDate?: boolean; + /** + * Nullable only for Cancelled tests. + */ + testResult?: TestTypeResults.TestResultEnum; + prohibitionIssued?: boolean; + /** + * Required for Abandoned tests. + */ + reasonForAbandoning?: string; + additionalNotesRecorded?: string; + additionalCommentsForAbandon?: string; + modType?: TestTypeResultsModType; + /** + * Used only for LEC tests. + */ + emissionStandard?: TestTypeResults.EmissionStandardEnum; + /** + * Used only for LEC tests. + */ + fuelType?: TestTypeResults.FuelTypeEnum; + /** + * Used only for LEC tests. + */ + particulateTrapFitted?: string; + /** + * Used only for LEC tests. + */ + particulateTrapSerialNumber?: string; + /** + * Used only for LEC tests. + */ + modificationTypeUsed?: string; + /** + * Used only for LEC tests. + */ + smokeTestKLimitApplied?: string; + defects?: Defects; + customDefects?: CustomDefects; } export namespace TestTypeResults { - export type TestResultEnum = 'fail' | 'pass' | 'prs' | 'abandoned'; - export const TestResultEnum = { - Fail: 'fail' as TestResultEnum, - Pass: 'pass' as TestResultEnum, - Prs: 'prs' as TestResultEnum, - Abandoned: 'abandoned' as TestResultEnum, - }; - export type EmissionStandardEnum = - | '0.10 g/kWh Euro 3 PM' - | '0.03 g/kWh Euro IV PM' - | 'Euro 3' - | 'Euro 4' - | 'Euro 6' - | 'Euro VI' - | 'Full Electric'; - export const EmissionStandardEnum = { - _010GkWhEuro3PM: '0.10 g/kWh Euro 3 PM' as EmissionStandardEnum, - _003GkWhEuroIVPM: '0.03 g/kWh Euro IV PM' as EmissionStandardEnum, - Euro3: 'Euro 3' as EmissionStandardEnum, - Euro4: 'Euro 4' as EmissionStandardEnum, - Euro6: 'Euro 6' as EmissionStandardEnum, - EuroVI: 'Euro VI' as EmissionStandardEnum, - FullElectric: 'Full Electric' as EmissionStandardEnum, - }; - export type FuelTypeEnum = 'diesel' | 'gas-cng' | 'gas-lng' | 'gas-lpg' | 'fuel cell' | 'petrol' | 'full electric'; - export const FuelTypeEnum = { - Diesel: 'diesel' as FuelTypeEnum, - GasCng: 'gas-cng' as FuelTypeEnum, - GasLng: 'gas-lng' as FuelTypeEnum, - GasLpg: 'gas-lpg' as FuelTypeEnum, - FuelCell: 'fuel cell' as FuelTypeEnum, - Petrol: 'petrol' as FuelTypeEnum, - FullElectric: 'full electric' as FuelTypeEnum, - }; -} + export type TestResultEnum = 'fail' | 'pass' | 'prs' | 'abandoned'; + export const TestResultEnum = { + Fail: 'fail' as TestResultEnum, + Pass: 'pass' as TestResultEnum, + Prs: 'prs' as TestResultEnum, + Abandoned: 'abandoned' as TestResultEnum + }; + export type EmissionStandardEnum = '0.10 g/kWh Euro 3 PM' | '0.03 g/kWh Euro IV PM' | 'Euro 3' | 'Euro 4' | 'Euro 6' | 'Euro VI' | 'Full Electric'; + export const EmissionStandardEnum = { + _010GkWhEuro3PM: '0.10 g/kWh Euro 3 PM' as EmissionStandardEnum, + _003GkWhEuroIVPM: '0.03 g/kWh Euro IV PM' as EmissionStandardEnum, + Euro3: 'Euro 3' as EmissionStandardEnum, + Euro4: 'Euro 4' as EmissionStandardEnum, + Euro6: 'Euro 6' as EmissionStandardEnum, + EuroVI: 'Euro VI' as EmissionStandardEnum, + FullElectric: 'Full Electric' as EmissionStandardEnum + }; + export type FuelTypeEnum = 'diesel' | 'gas-cng' | 'gas-lng' | 'gas-lpg' | 'fuel cell' | 'petrol' | 'full electric'; + export const FuelTypeEnum = { + Diesel: 'diesel' as FuelTypeEnum, + GasCng: 'gas-cng' as FuelTypeEnum, + GasLng: 'gas-lng' as FuelTypeEnum, + GasLpg: 'gas-lpg' as FuelTypeEnum, + FuelCell: 'fuel cell' as FuelTypeEnum, + Petrol: 'petrol' as FuelTypeEnum, + FullElectric: 'full electric' as FuelTypeEnum + }; +} \ No newline at end of file diff --git a/src/app/api/test-results/model/testTypeResultsModType.ts b/src/app/api/test-results/model/testTypeResultsModType.ts index 553a0bdcb0..9044919191 100644 --- a/src/app/api/test-results/model/testTypeResultsModType.ts +++ b/src/app/api/test-results/model/testTypeResultsModType.ts @@ -12,21 +12,21 @@ /** * Used only for LEC tests. p = particulate trap, m = modification or change of engine, g = gas engine. */ -export interface TestTypeResultsModType { - code?: TestTypeResultsModType.CodeEnum; - description?: TestTypeResultsModType.DescriptionEnum; +export interface TestTypeResultsModType { + code?: TestTypeResultsModType.CodeEnum; + description?: TestTypeResultsModType.DescriptionEnum; } export namespace TestTypeResultsModType { - export type CodeEnum = 'p' | 'm' | 'g'; - export const CodeEnum = { - P: 'p' as CodeEnum, - M: 'm' as CodeEnum, - G: 'g' as CodeEnum, - }; - export type DescriptionEnum = 'particulate trap' | 'modification or change of engine' | 'gas engine'; - export const DescriptionEnum = { - ParticulateTrap: 'particulate trap' as DescriptionEnum, - ModificationOrChangeOfEngine: 'modification or change of engine' as DescriptionEnum, - GasEngine: 'gas engine' as DescriptionEnum, - }; -} + export type CodeEnum = 'p' | 'm' | 'g'; + export const CodeEnum = { + P: 'p' as CodeEnum, + M: 'm' as CodeEnum, + G: 'g' as CodeEnum + }; + export type DescriptionEnum = 'particulate trap' | 'modification or change of engine' | 'gas engine'; + export const DescriptionEnum = { + ParticulateTrap: 'particulate trap' as DescriptionEnum, + ModificationOrChangeOfEngine: 'modification or change of engine' as DescriptionEnum, + GasEngine: 'gas engine' as DescriptionEnum + }; +} \ No newline at end of file diff --git a/src/app/api/test-results/model/testTypes.ts b/src/app/api/test-results/model/testTypes.ts index 75a4b202b7..a10aae64b9 100644 --- a/src/app/api/test-results/model/testTypes.ts +++ b/src/app/api/test-results/model/testTypes.ts @@ -13,4 +13,5 @@ import { TestTypeRecords } from './testTypeRecords'; /** * Nullable only for Cancelled tests. */ -export interface TestTypes extends Array {} +export interface TestTypes extends Array { +} \ No newline at end of file diff --git a/src/app/api/test-results/variables.ts b/src/app/api/test-results/variables.ts index 9bae45f800..6fe58549f3 100644 --- a/src/app/api/test-results/variables.ts +++ b/src/app/api/test-results/variables.ts @@ -2,8 +2,8 @@ import { InjectionToken } from '@angular/core'; export const BASE_PATH = new InjectionToken('basePath'); export const COLLECTION_FORMATS = { - csv: ',', - tsv: ' ', - ssv: ' ', - pipes: '|', -}; + 'csv': ',', + 'tsv': ' ', + 'ssv': ' ', + 'pipes': '|' +} diff --git a/src/app/api/test-types/api.module.ts b/src/app/api/test-types/api.module.ts index 44bae5c609..a93ef1975d 100644 --- a/src/app/api/test-types/api.module.ts +++ b/src/app/api/test-types/api.module.ts @@ -1,32 +1,33 @@ -import { HttpClient } from '@angular/common/http'; -import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; +import { NgModule, ModuleWithProviders, SkipSelf, Optional } from '@angular/core'; import { Configuration } from './configuration'; +import { HttpClient } from '@angular/common/http'; + import { TestTypesService } from './api/testTypes.service'; @NgModule({ - imports: [], - declarations: [], - exports: [], - providers: [TestTypesService], + imports: [], + declarations: [], + exports: [], + providers: [ + TestTypesService ] }) export class ApiModule { - public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { - return { - ngModule: ApiModule, - providers: [{ provide: Configuration, useFactory: configurationFactory }], - }; - } + public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { + return { + ngModule: ApiModule, + providers: [ { provide: Configuration, useFactory: configurationFactory } ] + }; + } - constructor(@Optional() @SkipSelf() parentModule: ApiModule, @Optional() http: HttpClient) { - if (parentModule) { - throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); - } - if (!http) { - throw new Error( - 'You need to import the HttpClientModule in your AppModule! \n' + - 'See also https://github.com/angular/angular/issues/20575' - ); - } - } + constructor( @Optional() @SkipSelf() parentModule: ApiModule, + @Optional() http: HttpClient) { + if (parentModule) { + throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); + } + if (!http) { + throw new Error('You need to import the HttpClientModule in your AppModule! \n' + + 'See also https://github.com/angular/angular/issues/20575'); + } + } } diff --git a/src/app/api/test-types/api/testTypes.service.ts b/src/app/api/test-types/api/testTypes.service.ts index 8741ea5c4e..8e1b6eeb04 100644 --- a/src/app/api/test-types/api/testTypes.service.ts +++ b/src/app/api/test-types/api/testTypes.service.ts @@ -7,252 +7,207 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - */ /* tslint:disable:no-unused-variable member-ordering */ + *//* tslint:disable:no-unused-variable member-ordering */ -import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; -import { Inject, Injectable, Optional } from '@angular/core'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { Inject, Injectable, Optional } from '@angular/core'; +import { HttpClient, HttpHeaders, HttpParams, + HttpResponse, HttpEvent } from '@angular/common/http'; +import { CustomHttpUrlEncodingCodec } from '../encoder'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { TestTypeInfo } from '../model/testTypeInfo'; import { TestTypesTaxonomy } from '../model/testTypesTaxonomy'; -import { Configuration } from '../configuration'; -import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; +import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; +import { Configuration } from '../configuration'; + @Injectable() export class TestTypesService { - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor( - protected httpClient: HttpClient, - @Optional() @Inject(BASE_PATH) basePath: string, - @Optional() configuration: Configuration - ) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - /** - * Return test types - * This endpoint will return all the data for test types based on filters provided. By default it will return all testTypes which don't have a typeOfTest field. - * @param typeOfTest It is used to filter test types based on the given typeOfTest. Note that sending the query parameter will also return the test types without a tag. - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public getTestTypes(typeOfTest?: string, observe?: 'body', reportProgress?: boolean): Observable; - public getTestTypes( - typeOfTest?: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public getTestTypes( - typeOfTest?: string, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public getTestTypes(typeOfTest?: string, observe: any = 'body', reportProgress = false): Observable { - let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); - if (typeOfTest !== undefined && typeOfTest !== null) { - queryParameters = queryParameters.set('typeOfTest', typeOfTest); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = - typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', `Bearer ${accessToken}`); - } - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = []; - - return this.httpClient.request('get', `${this.basePath}/test-types`, { - params: queryParameters, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - }); - } - - /** - * Return test type information by ID - * This endpoint will return data of the test types needed to be saved agains the test results. - * @param id - * @param fields - * @param vehicleType - * @param vehicleSize - * @param vehicleConfiguration - * @param vehicleAxles - * @param euVehicleCategory - * @param vehicleClass - * @param vehicleSubclass - * @param vehicleWheels - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public getTestTypesid( - id: string, - fields: Array, - vehicleType: string, - vehicleSize?: string, - vehicleConfiguration?: string, - vehicleAxles?: number, - euVehicleCategory?: string, - vehicleClass?: string, - vehicleSubclass?: string, - vehicleWheels?: number, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public getTestTypesid( - id: string, - fields: Array, - vehicleType: string, - vehicleSize?: string, - vehicleConfiguration?: string, - vehicleAxles?: number, - euVehicleCategory?: string, - vehicleClass?: string, - vehicleSubclass?: string, - vehicleWheels?: number, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public getTestTypesid( - id: string, - fields: Array, - vehicleType: string, - vehicleSize?: string, - vehicleConfiguration?: string, - vehicleAxles?: number, - euVehicleCategory?: string, - vehicleClass?: string, - vehicleSubclass?: string, - vehicleWheels?: number, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public getTestTypesid( - id: string, - fields: Array, - vehicleType: string, - vehicleSize?: string, - vehicleConfiguration?: string, - vehicleAxles?: number, - euVehicleCategory?: string, - vehicleClass?: string, - vehicleSubclass?: string, - vehicleWheels?: number, - observe: any = 'body', - reportProgress = false - ): Observable { - if (id === null || id === undefined) { - throw new Error('Required parameter id was null or undefined when calling getTestTypesid.'); - } - - if (fields === null || fields === undefined) { - throw new Error('Required parameter fields was null or undefined when calling getTestTypesid.'); - } - - if (vehicleType === null || vehicleType === undefined) { - throw new Error('Required parameter vehicleType was null or undefined when calling getTestTypesid.'); - } - - let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); - if (fields) { - queryParameters = queryParameters.set('fields', fields.join(COLLECTION_FORMATS['csv'])); - } - if (vehicleType !== undefined && vehicleType !== null) { - queryParameters = queryParameters.set('vehicleType', vehicleType); - } - if (vehicleSize !== undefined && vehicleSize !== null) { - queryParameters = queryParameters.set('vehicleSize', vehicleSize); - } - if (vehicleConfiguration !== undefined && vehicleConfiguration !== null) { - queryParameters = queryParameters.set('vehicleConfiguration', vehicleConfiguration); - } - if (vehicleAxles !== undefined && vehicleAxles !== null) { - queryParameters = queryParameters.set('vehicleAxles', vehicleAxles); - } - if (euVehicleCategory !== undefined && euVehicleCategory !== null) { - queryParameters = queryParameters.set('euVehicleCategory', euVehicleCategory); - } - if (vehicleClass !== undefined && vehicleClass !== null) { - queryParameters = queryParameters.set('vehicleClass', vehicleClass); - } - if (vehicleSubclass !== undefined && vehicleSubclass !== null) { - queryParameters = queryParameters.set('vehicleSubclass', vehicleSubclass); - } - if (vehicleWheels !== undefined && vehicleWheels !== null) { - queryParameters = queryParameters.set('vehicleWheels', vehicleWheels); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = - typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', `Bearer ${accessToken}`); - } - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = []; - - return this.httpClient.request( - 'get', - `${this.basePath}/test-types/${encodeURIComponent(String(id))}`, - { - params: queryParameters, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - } - ); - } + + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + + /** + * Return test types + * This endpoint will return all the data for test types based on filters provided. By default it will return all testTypes which don't have a typeOfTest field. + * @param typeOfTest It is used to filter test types based on the given typeOfTest. Note that sending the query parameter will also return the test types without a tag. + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public getTestTypes(typeOfTest?: string, observe?: 'body', reportProgress?: boolean): Observable; + public getTestTypes(typeOfTest?: string, observe?: 'response', reportProgress?: boolean): Observable>; + public getTestTypes(typeOfTest?: string, observe?: 'events', reportProgress?: boolean): Observable>; + public getTestTypes(typeOfTest?: string, observe: any = 'body', reportProgress: boolean = false ): Observable { + + + let queryParameters = new HttpParams({encoder: new CustomHttpUrlEncodingCodec()}); + if (typeOfTest !== undefined && typeOfTest !== null) { + queryParameters = queryParameters.set('typeOfTest', typeOfTest); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/json' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + ]; + + return this.httpClient.request('get',`${this.basePath}/test-types`, + { + params: queryParameters, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + + /** + * Return test type information by ID + * This endpoint will return data of the test types needed to be saved agains the test results. + * @param id + * @param fields + * @param vehicleType + * @param vehicleSize + * @param vehicleConfiguration + * @param vehicleAxles + * @param euVehicleCategory + * @param vehicleClass + * @param vehicleSubclass + * @param vehicleWheels + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public getTestTypesid(id: string, fields: Array, vehicleType: string, vehicleSize?: string, vehicleConfiguration?: string, vehicleAxles?: number, euVehicleCategory?: string, vehicleClass?: string, vehicleSubclass?: string, vehicleWheels?: number, observe?: 'body', reportProgress?: boolean): Observable; + public getTestTypesid(id: string, fields: Array, vehicleType: string, vehicleSize?: string, vehicleConfiguration?: string, vehicleAxles?: number, euVehicleCategory?: string, vehicleClass?: string, vehicleSubclass?: string, vehicleWheels?: number, observe?: 'response', reportProgress?: boolean): Observable>; + public getTestTypesid(id: string, fields: Array, vehicleType: string, vehicleSize?: string, vehicleConfiguration?: string, vehicleAxles?: number, euVehicleCategory?: string, vehicleClass?: string, vehicleSubclass?: string, vehicleWheels?: number, observe?: 'events', reportProgress?: boolean): Observable>; + public getTestTypesid(id: string, fields: Array, vehicleType: string, vehicleSize?: string, vehicleConfiguration?: string, vehicleAxles?: number, euVehicleCategory?: string, vehicleClass?: string, vehicleSubclass?: string, vehicleWheels?: number, observe: any = 'body', reportProgress: boolean = false ): Observable { + + if (id === null || id === undefined) { + throw new Error('Required parameter id was null or undefined when calling getTestTypesid.'); + } + + if (fields === null || fields === undefined) { + throw new Error('Required parameter fields was null or undefined when calling getTestTypesid.'); + } + + if (vehicleType === null || vehicleType === undefined) { + throw new Error('Required parameter vehicleType was null or undefined when calling getTestTypesid.'); + } + + + + + + + + + let queryParameters = new HttpParams({encoder: new CustomHttpUrlEncodingCodec()}); + if (fields) { + queryParameters = queryParameters.set('fields', fields.join(COLLECTION_FORMATS['csv'])); + } + if (vehicleType !== undefined && vehicleType !== null) { + queryParameters = queryParameters.set('vehicleType', vehicleType); + } + if (vehicleSize !== undefined && vehicleSize !== null) { + queryParameters = queryParameters.set('vehicleSize', vehicleSize); + } + if (vehicleConfiguration !== undefined && vehicleConfiguration !== null) { + queryParameters = queryParameters.set('vehicleConfiguration', vehicleConfiguration); + } + if (vehicleAxles !== undefined && vehicleAxles !== null) { + queryParameters = queryParameters.set('vehicleAxles', vehicleAxles); + } + if (euVehicleCategory !== undefined && euVehicleCategory !== null) { + queryParameters = queryParameters.set('euVehicleCategory', euVehicleCategory); + } + if (vehicleClass !== undefined && vehicleClass !== null) { + queryParameters = queryParameters.set('vehicleClass', vehicleClass); + } + if (vehicleSubclass !== undefined && vehicleSubclass !== null) { + queryParameters = queryParameters.set('vehicleSubclass', vehicleSubclass); + } + if (vehicleWheels !== undefined && vehicleWheels !== null) { + queryParameters = queryParameters.set('vehicleWheels', vehicleWheels); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/json' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + ]; + + return this.httpClient.request('get',`${this.basePath}/test-types/${encodeURIComponent(String(id))}`, + { + params: queryParameters, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + } diff --git a/src/app/api/test-types/configuration.ts b/src/app/api/test-types/configuration.ts index 8a8c9a845e..82e8458f39 100644 --- a/src/app/api/test-types/configuration.ts +++ b/src/app/api/test-types/configuration.ts @@ -1,79 +1,79 @@ export interface ConfigurationParameters { - apiKeys?: { [key: string]: string }; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: {[ key: string ]: string}; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; } export class Configuration { - apiKeys?: { [key: string]: string }; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: {[ key: string ]: string}; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; - constructor(configurationParameters: ConfigurationParameters = {}) { - this.apiKeys = configurationParameters.apiKeys; - this.username = configurationParameters.username; - this.password = configurationParameters.password; - this.accessToken = configurationParameters.accessToken; - this.basePath = configurationParameters.basePath; - this.withCredentials = configurationParameters.withCredentials; - } + constructor(configurationParameters: ConfigurationParameters = {}) { + this.apiKeys = configurationParameters.apiKeys; + this.username = configurationParameters.username; + this.password = configurationParameters.password; + this.accessToken = configurationParameters.accessToken; + this.basePath = configurationParameters.basePath; + this.withCredentials = configurationParameters.withCredentials; + } - /** - * Select the correct content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param contentTypes - the array of content types that are available for selection - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderContentType(contentTypes: string[]): string | undefined { - if (contentTypes.length == 0) { - return undefined; - } + /** + * Select the correct content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param contentTypes - the array of content types that are available for selection + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderContentType (contentTypes: string[]): string | undefined { + if (contentTypes.length == 0) { + return undefined; + } - const type = contentTypes.find((x) => this.isJsonMime(x)); - if (type === undefined) { - return contentTypes[0]; - } - return type; - } + let type = contentTypes.find(x => this.isJsonMime(x)); + if (type === undefined) { + return contentTypes[0]; + } + return type; + } - /** - * Select the correct accept content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param accepts - the array of content types that are available for selection. - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderAccept(accepts: string[]): string | undefined { - if (accepts.length == 0) { - return undefined; - } + /** + * Select the correct accept content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param accepts - the array of content types that are available for selection. + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderAccept(accepts: string[]): string | undefined { + if (accepts.length == 0) { + return undefined; + } - const type = accepts.find((x) => this.isJsonMime(x)); - if (type === undefined) { - return accepts[0]; - } - return type; - } + let type = accepts.find(x => this.isJsonMime(x)); + if (type === undefined) { + return accepts[0]; + } + return type; + } - /** - * Check if the given MIME is a JSON MIME. - * JSON MIME examples: - * application/json - * application/json; charset=UTF8 - * APPLICATION/JSON - * application/vnd.company+json - * @param mime - MIME (Multipurpose Internet Mail Extensions) - * @return True if the given MIME is JSON, false otherwise. - */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); - return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } } diff --git a/src/app/api/test-types/encoder.ts b/src/app/api/test-types/encoder.ts index b80138427a..f506bfbea0 100644 --- a/src/app/api/test-types/encoder.ts +++ b/src/app/api/test-types/encoder.ts @@ -1,18 +1,18 @@ -import { HttpUrlEncodingCodec } from '@angular/common/http'; + import { HttpUrlEncodingCodec } from '@angular/common/http'; /** - * CustomHttpUrlEncodingCodec - * Fix plus sign (+) not encoding, so sent as blank space - * See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 - */ +* CustomHttpUrlEncodingCodec +* Fix plus sign (+) not encoding, so sent as blank space +* See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 +*/ export class CustomHttpUrlEncodingCodec extends HttpUrlEncodingCodec { - override encodeKey(key: string): string { - const k = super.encodeKey(key); - return k.replace(/\+/gi, '%2B'); - } - - override encodeValue(value: string): string { - const v = super.encodeValue(value); - return v.replace(/\+/gi, '%2B'); - } + override encodeKey(k: string): string { + k = super.encodeKey(k); + return k.replace(/\+/gi, '%2B'); + } + override encodeValue(v: string): string { + v = super.encodeValue(v); + return v.replace(/\+/gi, '%2B'); + } } + diff --git a/src/app/api/test-types/index.ts b/src/app/api/test-types/index.ts index 410623f1c9..c312b70fa3 100644 --- a/src/app/api/test-types/index.ts +++ b/src/app/api/test-types/index.ts @@ -2,4 +2,4 @@ export * from './api/api'; export * from './model/models'; export * from './variables'; export * from './configuration'; -export * from './api.module'; +export * from './api.module'; \ No newline at end of file diff --git a/src/app/api/test-types/model/testType.ts b/src/app/api/test-types/model/testType.ts index e29182543a..fb68cbc345 100644 --- a/src/app/api/test-types/model/testType.ts +++ b/src/app/api/test-types/model/testType.ts @@ -13,94 +13,94 @@ * Test type */ export interface TestType { - /** - * Unique identifier - */ - id: string; - /** - * The list of test type IDs or categories IDs, used to determine if two test types can be added as linked within the same test. - */ - linkedIds?: Array; - /** - * The list of suggested test types, used to determine suggested test types for psv, trl and hgv. - */ - suggestedTestTypeIds?: Array; - /** - * Name of the test type - */ - name: string; - /** - * Full name of the test type containing the entire path, having a business value - */ - testTypeName?: string; - /** - * Name to be displayed in the mobile app suggested next test type popup - */ - suggestedTestTypeDisplayName?: string; - /** - * Order in which this test type is displayed in the mobile app suggested next test type popup - */ - suggestedTestTypeDisplayOrder?: string; - /** - * Used to filter in test types with a specific typeOfTest, send as a query param in the request - */ - typeOfTest?: string; - /** - * This category is applying only to these vehicle types. The vehicle types should descend from its parent, but should not be necessarily the same - */ - forVehicleType: Array; - /** - * Used to filter test types that allow creating tests on Provisional Records - */ - forProvisionalStatus?: boolean; - /** - * Used to filter test types that allow creating tests on Provisional Records and not current - */ - forProvisionalStatusOnly?: boolean; - /** - * - * This category is applying only to these vehicle sizes. The vehicle sizes should descend from its parent, but should not be necessarily the same - */ - forVehicleSize?: Array; - /** - * This category is applying only to these vehicle configurations. The vehicle configurations should descend from its parent, but should not be necessarily the same - */ - forVehicleConfiguration?: Array; - /** - * This category is applying only to the vehicles with those number of axles. The vehicle number of axles should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any number of axles. - */ - forVehicleAxles?: Array; - /** - * This category is applying only to the vehicles with that eu category. The eu vehicle category should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any eu vehicle category. - */ - forEuVehicleCategory?: Array; - /** - * This category is applying only to the vehicles with that vehicle class. The vehicle class should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any vehicle class. - */ - forVehicleClass?: Array; - /** - * This category is applying only to the vehicles with that vehicle subclass. The vehicle subclass should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any vehicle subclass. - */ - forVehicleSubclass?: Array; - /** - * This category is applying only to the vehicles with those number of wheels. The vehicle number of wheels should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any number of wheels. - */ - forVehicleWheels?: Array; + /** + * Unique identifier + */ + id: string; + /** + * The list of test type IDs or categories IDs, used to determine if two test types can be added as linked within the same test. + */ + linkedIds?: Array; + /** + * The list of suggested test types, used to determine suggested test types for psv, trl and hgv. + */ + suggestedTestTypeIds?: Array; + /** + * Name of the test type + */ + name: string; + /** + * Full name of the test type containing the entire path, having a business value + */ + testTypeName?: string; + /** + * Name to be displayed in the mobile app suggested next test type popup + */ + suggestedTestTypeDisplayName?: string; + /** + * Order in which this test type is displayed in the mobile app suggested next test type popup + */ + suggestedTestTypeDisplayOrder?: string; + /** + * Used to filter in test types with a specific typeOfTest, send as a query param in the request + */ + typeOfTest?: string; + /** + * This category is applying only to these vehicle types. The vehicle types should descend from its parent, but should not be necessarily the same + */ + forVehicleType: Array; + /** + * Used to filter test types that allow creating tests on Provisional Records + */ + forProvisionalStatus?: boolean; + /** + * Used to filter test types that allow creating tests on Provisional Records and not current + */ + forProvisionalStatusOnly?: boolean; + /** + * + * This category is applying only to these vehicle sizes. The vehicle sizes should descend from its parent, but should not be necessarily the same + */ + forVehicleSize?: Array; + /** + * This category is applying only to these vehicle configurations. The vehicle configurations should descend from its parent, but should not be necessarily the same + */ + forVehicleConfiguration?: Array; + /** + * This category is applying only to the vehicles with those number of axles. The vehicle number of axles should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any number of axles. + */ + forVehicleAxles?: Array; + /** + * This category is applying only to the vehicles with that eu category. The eu vehicle category should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any eu vehicle category. + */ + forEuVehicleCategory?: Array; + /** + * This category is applying only to the vehicles with that vehicle class. The vehicle class should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any vehicle class. + */ + forVehicleClass?: Array; + /** + * This category is applying only to the vehicles with that vehicle subclass. The vehicle subclass should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any vehicle subclass. + */ + forVehicleSubclass?: Array; + /** + * This category is applying only to the vehicles with those number of wheels. The vehicle number of wheels should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any number of wheels. + */ + forVehicleWheels?: Array; } export namespace TestType { - export type ForVehicleTypeEnum = 'psv' | 'hgv' | 'trl' | 'lgv' | 'car' | 'small trl' | 'motorcycle'; - export const ForVehicleTypeEnum = { - Psv: 'psv' as ForVehicleTypeEnum, - Hgv: 'hgv' as ForVehicleTypeEnum, - Trl: 'trl' as ForVehicleTypeEnum, - Lgv: 'lgv' as ForVehicleTypeEnum, - Car: 'car' as ForVehicleTypeEnum, - SmallTrl: 'small trl' as ForVehicleTypeEnum, - Motorcycle: 'motorcycle' as ForVehicleTypeEnum, - }; - export type ForVehicleSizeEnum = 'small' | 'large'; - export const ForVehicleSizeEnum = { - Small: 'small' as ForVehicleSizeEnum, - Large: 'large' as ForVehicleSizeEnum, - }; + export type ForVehicleTypeEnum = 'psv' | 'hgv' | 'trl' | 'lgv' | 'car' | 'small trl' | 'motorcycle'; + export const ForVehicleTypeEnum = { + Psv: 'psv' as ForVehicleTypeEnum, + Hgv: 'hgv' as ForVehicleTypeEnum, + Trl: 'trl' as ForVehicleTypeEnum, + Lgv: 'lgv' as ForVehicleTypeEnum, + Car: 'car' as ForVehicleTypeEnum, + SmallTrl: 'small trl' as ForVehicleTypeEnum, + Motorcycle: 'motorcycle' as ForVehicleTypeEnum, + }; + export type ForVehicleSizeEnum = 'small' | 'large'; + export const ForVehicleSizeEnum = { + Small: 'small' as ForVehicleSizeEnum, + Large: 'large' as ForVehicleSizeEnum + }; } diff --git a/src/app/api/test-types/model/testTypeCategory.ts b/src/app/api/test-types/model/testTypeCategory.ts index ed0a1c95c3..53475fd057 100644 --- a/src/app/api/test-types/model/testTypeCategory.ts +++ b/src/app/api/test-types/model/testTypeCategory.ts @@ -14,85 +14,85 @@ import { TestType } from './testType'; * A category that can be composed of zero/more categories + one/more test types */ export interface TestTypeCategory { - /** - * Unique identifier - */ - id: string; - /** - * used in helping to sort test types - */ - sortId?: string; - /** - * The lsit of test type IDs or categories IDs, used to determine if two test types can be added as linked within the same test. - */ - linkedIds?: Array; - /** - * Name of the category - */ - name: string; - /** - * This category is applying only to these vehicle types. - */ - forVehicleType: Array; - /** - * Used to filter test types that allow creating tests on Provisional Records - */ - forProvisionalStatus?: boolean; - /** - * Used to filter test types that allow creating tests on Provisional Records and not current - */ - forProvisionalStatusOnly?: boolean; - /** - * Used to filter in test types with a specific typeOfTest, send as a query param in the request - */ - typeOfTest?: string; - /** - * This category is applying only to these vehicle sizes. - */ - forVehicleSize?: Array; - /** - * This category is applying only to these vehicle configurations. - */ - forVehicleConfiguration?: Array; - /** - * This category is applying only to the vehicles with those number of axles. If the value is null then it means the category or test type is applicable to any number of axles. - */ - forVehicleAxles?: Array; - /** - * This category is applying only to the vehicles with that eu category. The eu vehicle category should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any eu vehicle category. - */ - forEuVehicleCategory?: Array; - /** - * This category is applying only to the vehicles with that vehicle class. The vehicle class should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any vehicle class. - */ - forVehicleClass?: Array; - /** - * This category is applying only to the vehicles with that vehicle subclass. The vehicle subclass should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any vehicle subclass. - */ - forVehicleSubclass?: Array; - /** - * This category is applying only to the vehicles with those number of wheels. The vehicle number of wheels should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any number of wheels. - */ - forVehicleWheels?: Array; - /** - * This is an array composed of TestTypeCategories and/or TestTypes - */ - nextTestTypesOrCategories?: Array; + /** + * Unique identifier + */ + id: string; + /** + * used in helping to sort test types + */ + sortId?: string; + /** + * The lsit of test type IDs or categories IDs, used to determine if two test types can be added as linked within the same test. + */ + linkedIds?: Array; + /** + * Name of the category + */ + name: string; + /** + * This category is applying only to these vehicle types. + */ + forVehicleType: Array; + /** + * Used to filter test types that allow creating tests on Provisional Records + */ + forProvisionalStatus?: boolean; + /** + * Used to filter test types that allow creating tests on Provisional Records and not current + */ + forProvisionalStatusOnly?: boolean; + /** + * Used to filter in test types with a specific typeOfTest, send as a query param in the request + */ + typeOfTest?: string; + /** + * This category is applying only to these vehicle sizes. + */ + forVehicleSize?: Array; + /** + * This category is applying only to these vehicle configurations. + */ + forVehicleConfiguration?: Array; + /** + * This category is applying only to the vehicles with those number of axles. If the value is null then it means the category or test type is applicable to any number of axles. + */ + forVehicleAxles?: Array; + /** + * This category is applying only to the vehicles with that eu category. The eu vehicle category should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any eu vehicle category. + */ + forEuVehicleCategory?: Array; + /** + * This category is applying only to the vehicles with that vehicle class. The vehicle class should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any vehicle class. + */ + forVehicleClass?: Array; + /** + * This category is applying only to the vehicles with that vehicle subclass. The vehicle subclass should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any vehicle subclass. + */ + forVehicleSubclass?: Array; + /** + * This category is applying only to the vehicles with those number of wheels. The vehicle number of wheels should descend from its parent, but should not be necessarily the same. If the value is null then it means the category or test type is applicable to any number of wheels. + */ + forVehicleWheels?: Array; + /** + * This is an array composed of TestTypeCategories and/or TestTypes + */ + nextTestTypesOrCategories?: Array; } export namespace TestTypeCategory { - export type ForVehicleTypeEnum = 'psv' | 'hgv' | 'trl' | 'lgv' | 'car' | 'small trl' | 'motorcycle'; - export const ForVehicleTypeEnum = { - Psv: 'psv' as ForVehicleTypeEnum, - Hgv: 'hgv' as ForVehicleTypeEnum, - Trl: 'trl' as ForVehicleTypeEnum, - Car: 'car' as ForVehicleTypeEnum, - Lgv: 'lgv' as ForVehicleTypeEnum, - SmallTrl: 'small trl' as ForVehicleTypeEnum, - Motorcycle: 'motorcycle' as ForVehicleTypeEnum, - }; - export type ForVehicleSizeEnum = 'small' | 'large'; - export const ForVehicleSizeEnum = { - Small: 'small' as ForVehicleSizeEnum, - Large: 'large' as ForVehicleSizeEnum, - }; + export type ForVehicleTypeEnum = 'psv' | 'hgv' | 'trl' | 'lgv' | 'car' | 'small trl' | 'motorcycle'; + export const ForVehicleTypeEnum = { + Psv: 'psv' as ForVehicleTypeEnum, + Hgv: 'hgv' as ForVehicleTypeEnum, + Trl: 'trl' as ForVehicleTypeEnum, + Car: 'car' as ForVehicleTypeEnum, + Lgv: 'lgv' as ForVehicleTypeEnum, + SmallTrl: 'small trl' as ForVehicleTypeEnum, + Motorcycle: 'motorcycle' as ForVehicleTypeEnum, + }; + export type ForVehicleSizeEnum = 'small' | 'large'; + export const ForVehicleSizeEnum = { + Small: 'small' as ForVehicleSizeEnum, + Large: 'large' as ForVehicleSizeEnum + }; } diff --git a/src/app/api/test-types/model/testTypeInfo.ts b/src/app/api/test-types/model/testTypeInfo.ts index 699575003b..d8b2db15fd 100644 --- a/src/app/api/test-types/model/testTypeInfo.ts +++ b/src/app/api/test-types/model/testTypeInfo.ts @@ -12,20 +12,20 @@ /** * Test type */ -export interface TestTypeInfo { - /** - * Unique identifier - */ - id?: string; - testTypeClassification?: TestTypeInfo.TestTypeClassificationEnum; - defaultTestCode?: string; - linkedTestCode?: string; +export interface TestTypeInfo { + /** + * Unique identifier + */ + id?: string; + testTypeClassification?: TestTypeInfo.TestTypeClassificationEnum; + defaultTestCode?: string; + linkedTestCode?: string; } export namespace TestTypeInfo { - export type TestTypeClassificationEnum = 'Annual With Certificate' | 'Annual No Certificate' | 'Non Annual'; - export const TestTypeClassificationEnum = { - AnnualWithCertificate: 'Annual With Certificate' as TestTypeClassificationEnum, - AnnualNoCertificate: 'Annual No Certificate' as TestTypeClassificationEnum, - NonAnnual: 'Non Annual' as TestTypeClassificationEnum, - }; -} + export type TestTypeClassificationEnum = 'Annual With Certificate' | 'Annual No Certificate' | 'Non Annual'; + export const TestTypeClassificationEnum = { + AnnualWithCertificate: 'Annual With Certificate' as TestTypeClassificationEnum, + AnnualNoCertificate: 'Annual No Certificate' as TestTypeClassificationEnum, + NonAnnual: 'Non Annual' as TestTypeClassificationEnum + }; +} \ No newline at end of file diff --git a/src/app/api/test-types/model/testTypesTaxonomy.ts b/src/app/api/test-types/model/testTypesTaxonomy.ts index ad4389ee3c..9a4e53702c 100644 --- a/src/app/api/test-types/model/testTypesTaxonomy.ts +++ b/src/app/api/test-types/model/testTypesTaxonomy.ts @@ -11,4 +11,5 @@ import { TestType } from './testType'; import { TestTypeCategory } from './testTypeCategory'; -export interface TestTypesTaxonomy extends Array {} +export interface TestTypesTaxonomy extends Array { +} \ No newline at end of file diff --git a/src/app/api/test-types/variables.ts b/src/app/api/test-types/variables.ts index 9bae45f800..6fe58549f3 100644 --- a/src/app/api/test-types/variables.ts +++ b/src/app/api/test-types/variables.ts @@ -2,8 +2,8 @@ import { InjectionToken } from '@angular/core'; export const BASE_PATH = new InjectionToken('basePath'); export const COLLECTION_FORMATS = { - csv: ',', - tsv: ' ', - ssv: ' ', - pipes: '|', -}; + 'csv': ',', + 'tsv': ' ', + 'ssv': ' ', + 'pipes': '|' +} diff --git a/src/app/api/vehicle/api.module.ts b/src/app/api/vehicle/api.module.ts index 526092d029..878117c339 100644 --- a/src/app/api/vehicle/api.module.ts +++ b/src/app/api/vehicle/api.module.ts @@ -1,6 +1,7 @@ -import { HttpClient } from '@angular/common/http'; -import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core'; +import { NgModule, ModuleWithProviders, SkipSelf, Optional } from '@angular/core'; import { Configuration } from './configuration'; +import { HttpClient } from '@angular/common/http'; + import { AddProvisionalTechRecordService } from './api/addProvisionalTechRecord.service'; import { ArchiveTechRecordStatusService } from './api/archiveTechRecordStatus.service'; @@ -9,34 +10,32 @@ import { PostTechRecordsService } from './api/postTechRecords.service'; import { UpdateTechRecordsService } from './api/updateTechRecords.service'; @NgModule({ - imports: [], - declarations: [], - exports: [], - providers: [ - AddProvisionalTechRecordService, - ArchiveTechRecordStatusService, - GetTechRecordsService, - PostTechRecordsService, - UpdateTechRecordsService, - ], + imports: [], + declarations: [], + exports: [], + providers: [ + AddProvisionalTechRecordService, + ArchiveTechRecordStatusService, + GetTechRecordsService, + PostTechRecordsService, + UpdateTechRecordsService ] }) export class ApiModule { - public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { - return { - ngModule: ApiModule, - providers: [{ provide: Configuration, useFactory: configurationFactory }], - }; - } + public static forRoot(configurationFactory: () => Configuration): ModuleWithProviders { + return { + ngModule: ApiModule, + providers: [ { provide: Configuration, useFactory: configurationFactory } ] + }; + } - constructor(@Optional() @SkipSelf() parentModule: ApiModule, @Optional() http: HttpClient) { - if (parentModule) { - throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); - } - if (!http) { - throw new Error( - 'You need to import the HttpClientModule in your AppModule! \n' + - 'See also https://github.com/angular/angular/issues/20575' - ); - } - } + constructor( @Optional() @SkipSelf() parentModule: ApiModule, + @Optional() http: HttpClient) { + if (parentModule) { + throw new Error('ApiModule is already loaded. Import in your base AppModule only.'); + } + if (!http) { + throw new Error('You need to import the HttpClientModule in your AppModule! \n' + + 'See also https://github.com/angular/angular/issues/20575'); + } + } } diff --git a/src/app/api/vehicle/api/addProvisionalTechRecord.service.ts b/src/app/api/vehicle/api/addProvisionalTechRecord.service.ts index 68d5a9bd09..abd4fe2904 100644 --- a/src/app/api/vehicle/api/addProvisionalTechRecord.service.ts +++ b/src/app/api/vehicle/api/addProvisionalTechRecord.service.ts @@ -7,128 +7,112 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - */ /* tslint:disable:no-unused-variable member-ordering */ + *//* tslint:disable:no-unused-variable member-ordering */ -import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http'; -import { Inject, Injectable, Optional } from '@angular/core'; +import { Inject, Injectable, Optional } from '@angular/core'; +import { HttpClient, HttpHeaders, HttpParams, + HttpResponse, HttpEvent } from '@angular/common/http'; +import { CustomHttpUrlEncodingCodec } from '../encoder'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { CompleteTechRecordPUT } from '../model/completeTechRecordPUT'; import { TechRecordArchiveAndProvisionalPayload } from '../model/techRecordArchiveAndProvisionalPayload'; -import { Configuration } from '../configuration'; -import { BASE_PATH } from '../variables'; +import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; +import { Configuration } from '../configuration'; + @Injectable() export class AddProvisionalTechRecordService { - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor( - protected httpClient: HttpClient, - @Optional() @Inject(BASE_PATH) basePath: string, - @Optional() configuration: Configuration - ) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - /** - * Creates a new tech-record with status provisional for that vehicle and appends it to the techRecords array - * - * @param body The tech record to be created and added into the techRecords array - * @param systemNumber This represents the systemNumber of the vehicle - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public addProvisionalTechRecord( - body: TechRecordArchiveAndProvisionalPayload, - systemNumber: string, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public addProvisionalTechRecord( - body: TechRecordArchiveAndProvisionalPayload, - systemNumber: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public addProvisionalTechRecord( - body: TechRecordArchiveAndProvisionalPayload, - systemNumber: string, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public addProvisionalTechRecord( - body: TechRecordArchiveAndProvisionalPayload, - systemNumber: string, - observe: any = 'body', - reportProgress = false - ): Observable { - if (body === null || body === undefined) { - throw new Error('Required parameter body was null or undefined when calling addProvisionalTechRecord.'); - } - - if (systemNumber === null || systemNumber === undefined) { - throw new Error('Required parameter systemNumber was null or undefined when calling addProvisionalTechRecord.'); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = - typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', `Bearer ${accessToken}`); - } - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = ['application/json']; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request( - 'post', - `${this.basePath}/vehicles/add-provisional/${encodeURIComponent(String(systemNumber))}`, - { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - } - ); - } + + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + + /** + * Creates a new tech-record with status provisional for that vehicle and appends it to the techRecords array + * + * @param body The tech record to be created and added into the techRecords array + * @param systemNumber This represents the systemNumber of the vehicle + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public addProvisionalTechRecord(body: TechRecordArchiveAndProvisionalPayload, systemNumber: string, observe?: 'body', reportProgress?: boolean): Observable; + public addProvisionalTechRecord(body: TechRecordArchiveAndProvisionalPayload, systemNumber: string, observe?: 'response', reportProgress?: boolean): Observable>; + public addProvisionalTechRecord(body: TechRecordArchiveAndProvisionalPayload, systemNumber: string, observe?: 'events', reportProgress?: boolean): Observable>; + public addProvisionalTechRecord(body: TechRecordArchiveAndProvisionalPayload, systemNumber: string, observe: any = 'body', reportProgress: boolean = false ): Observable { + + if (body === null || body === undefined) { + throw new Error('Required parameter body was null or undefined when calling addProvisionalTechRecord.'); + } + + if (systemNumber === null || systemNumber === undefined) { + throw new Error('Required parameter systemNumber was null or undefined when calling addProvisionalTechRecord.'); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/json' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + 'application/json' + ]; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request('post',`${this.basePath}/vehicles/add-provisional/${encodeURIComponent(String(systemNumber))}`, + { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + } diff --git a/src/app/api/vehicle/api/api.ts b/src/app/api/vehicle/api/api.ts index 241f54088f..c561b91cc7 100644 --- a/src/app/api/vehicle/api/api.ts +++ b/src/app/api/vehicle/api/api.ts @@ -8,10 +8,4 @@ export * from './postTechRecords.service'; import { PostTechRecordsService } from './postTechRecords.service'; export * from './updateTechRecords.service'; import { UpdateTechRecordsService } from './updateTechRecords.service'; -export const APIS = [ - AddProvisionalTechRecordService, - ArchiveTechRecordStatusService, - GetTechRecordsService, - PostTechRecordsService, - UpdateTechRecordsService, -]; +export const APIS = [AddProvisionalTechRecordService, ArchiveTechRecordStatusService, GetTechRecordsService, PostTechRecordsService, UpdateTechRecordsService]; diff --git a/src/app/api/vehicle/api/archiveTechRecordStatus.service.ts b/src/app/api/vehicle/api/archiveTechRecordStatus.service.ts index a173683d17..61c1610de0 100644 --- a/src/app/api/vehicle/api/archiveTechRecordStatus.service.ts +++ b/src/app/api/vehicle/api/archiveTechRecordStatus.service.ts @@ -7,128 +7,112 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - */ /* tslint:disable:no-unused-variable member-ordering */ + *//* tslint:disable:no-unused-variable member-ordering */ -import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http'; -import { Inject, Injectable, Optional } from '@angular/core'; +import { Inject, Injectable, Optional } from '@angular/core'; +import { HttpClient, HttpHeaders, HttpParams, + HttpResponse, HttpEvent } from '@angular/common/http'; +import { CustomHttpUrlEncodingCodec } from '../encoder'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { CompleteTechRecordPUT } from '../model/completeTechRecordPUT'; import { TechRecordArchiveAndProvisionalPayload } from '../model/techRecordArchiveAndProvisionalPayload'; -import { Configuration } from '../configuration'; -import { BASE_PATH } from '../variables'; +import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; +import { Configuration } from '../configuration'; + @Injectable() export class ArchiveTechRecordStatusService { - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor( - protected httpClient: HttpClient, - @Optional() @Inject(BASE_PATH) basePath: string, - @Optional() configuration: Configuration - ) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - /** - * Archive an existing current or provisional tech record - * - * @param body The tech record to be archived - * @param systemNumber This represents the systemNumber of the vehicle - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public archiveTechRecordStatus( - body: TechRecordArchiveAndProvisionalPayload, - systemNumber: string, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public archiveTechRecordStatus( - body: TechRecordArchiveAndProvisionalPayload, - systemNumber: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public archiveTechRecordStatus( - body: TechRecordArchiveAndProvisionalPayload, - systemNumber: string, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public archiveTechRecordStatus( - body: TechRecordArchiveAndProvisionalPayload, - systemNumber: string, - observe: any = 'body', - reportProgress = false - ): Observable { - if (body === null || body === undefined) { - throw new Error('Required parameter body was null or undefined when calling archiveTechRecordStatus.'); - } - - if (systemNumber === null || systemNumber === undefined) { - throw new Error('Required parameter systemNumber was null or undefined when calling archiveTechRecordStatus.'); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = - typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', `Bearer ${accessToken}`); - } - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = ['application/json']; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request( - 'post', - `${this.basePath}/vehicles/archive/${encodeURIComponent(String(systemNumber))}`, - { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - } - ); - } + + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + + /** + * Archive an existing current or provisional tech record + * + * @param body The tech record to be archived + * @param systemNumber This represents the systemNumber of the vehicle + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public archiveTechRecordStatus(body: TechRecordArchiveAndProvisionalPayload, systemNumber: string, observe?: 'body', reportProgress?: boolean): Observable; + public archiveTechRecordStatus(body: TechRecordArchiveAndProvisionalPayload, systemNumber: string, observe?: 'response', reportProgress?: boolean): Observable>; + public archiveTechRecordStatus(body: TechRecordArchiveAndProvisionalPayload, systemNumber: string, observe?: 'events', reportProgress?: boolean): Observable>; + public archiveTechRecordStatus(body: TechRecordArchiveAndProvisionalPayload, systemNumber: string, observe: any = 'body', reportProgress: boolean = false ): Observable { + + if (body === null || body === undefined) { + throw new Error('Required parameter body was null or undefined when calling archiveTechRecordStatus.'); + } + + if (systemNumber === null || systemNumber === undefined) { + throw new Error('Required parameter systemNumber was null or undefined when calling archiveTechRecordStatus.'); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/json' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + 'application/json' + ]; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request('post',`${this.basePath}/vehicles/archive/${encodeURIComponent(String(systemNumber))}`, + { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + } diff --git a/src/app/api/vehicle/api/getTechRecords.service.ts b/src/app/api/vehicle/api/getTechRecords.service.ts index 41a73c3ae0..3d8e50a5eb 100644 --- a/src/app/api/vehicle/api/getTechRecords.service.ts +++ b/src/app/api/vehicle/api/getTechRecords.service.ts @@ -7,141 +7,118 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - */ /* tslint:disable:no-unused-variable member-ordering */ + *//* tslint:disable:no-unused-variable member-ordering */ -import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; -import { Inject, Injectable, Optional } from '@angular/core'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { Inject, Injectable, Optional } from '@angular/core'; +import { HttpClient, HttpHeaders, HttpParams, + HttpResponse, HttpEvent } from '@angular/common/http'; +import { CustomHttpUrlEncodingCodec } from '../encoder'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { CompleteTechRecords } from '../model/completeTechRecords'; -import { Configuration } from '../configuration'; -import { BASE_PATH } from '../variables'; +import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; +import { Configuration } from '../configuration'; + @Injectable() export class GetTechRecordsService { - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor( - protected httpClient: HttpClient, - @Optional() @Inject(BASE_PATH) basePath: string, - @Optional() configuration: Configuration - ) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - /** - * Get a tech record, for a particular Vin with status specified. - * - * @param searchIdentifier If the searchCriteria query parameter is not used or it has the \"all\" value then the searchIdentifier can be VRM, VIN, last six digits of the VIN or trailerId. VRM = between 3 and 8 characters, VIN = >8 characters, partial VIN = exactly 6 digits and trailerId = exactly 8 digits / 1 letter followed by exactly 6 digits. - * @param metadata - * @param status The tech record's status, the default value is provisional_over_current. If \"status\" = \"provisional_over_current\" or not provided when the GET call is done, then the current tech record will be retrieved only if, for the \"searchIdentifier\" that was provided, there is no \"provisional\" tech record, in which case the provisional tech record will be retrieved instead. If \"status\" = \"all\", then the backend will translate this into returning ALL technical records for that particular VIN/VRM, not just specific statuses - * @param searchCriteria The parameter is used to specify which search criteria should be used. \"ALL\" = search identifier can be VRM, VIN, last six digits of the VIN or trailerId. VRM = between 3 and 8 characters, VIN = >8 characters, partial VIN = exactly 6 digits and trailerId = exactly 8 digits / 1 letter followed by exactly 6 digits. If any other value than \"ALL\" is used then the search will be done using the specified search criteria, without taking into account the format of the saerch identifier. - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public getTechRecords( - searchIdentifier: string, - metadata?: boolean, - status?: string, - searchCriteria?: string, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public getTechRecords( - searchIdentifier: string, - metadata?: boolean, - status?: string, - searchCriteria?: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public getTechRecords( - searchIdentifier: string, - metadata?: boolean, - status?: string, - searchCriteria?: string, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public getTechRecords( - searchIdentifier: string, - metadata?: boolean, - status?: string, - searchCriteria?: string, - observe: any = 'body', - reportProgress = false - ): Observable { - if (searchIdentifier === null || searchIdentifier === undefined) { - throw new Error('Required parameter searchIdentifier was null or undefined when calling getTechRecords.'); - } - - let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); - if (metadata !== undefined && metadata !== null) { - queryParameters = queryParameters.set('metadata', metadata); - } - if (status !== undefined && status !== null) { - queryParameters = queryParameters.set('status', status); - } - if (searchCriteria !== undefined && searchCriteria !== null) { - queryParameters = queryParameters.set('searchCriteria', searchCriteria); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = - typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', `Bearer ${accessToken}`); - } - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = []; - - return this.httpClient.request( - 'get', - `${this.basePath}/vehicles/${encodeURIComponent(String(searchIdentifier))}/tech-records`, - { - params: queryParameters, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - } - ); - } + + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + + /** + * Get a tech record, for a particular Vin with status specified. + * + * @param searchIdentifier If the searchCriteria query parameter is not used or it has the \"all\" value then the searchIdentifier can be VRM, VIN, last six digits of the VIN or trailerId. VRM = between 3 and 8 characters, VIN = >8 characters, partial VIN = exactly 6 digits and trailerId = exactly 8 digits / 1 letter followed by exactly 6 digits. + * @param metadata + * @param status The tech record's status, the default value is provisional_over_current. If \"status\" = \"provisional_over_current\" or not provided when the GET call is done, then the current tech record will be retrieved only if, for the \"searchIdentifier\" that was provided, there is no \"provisional\" tech record, in which case the provisional tech record will be retrieved instead. If \"status\" = \"all\", then the backend will translate this into returning ALL technical records for that particular VIN/VRM, not just specific statuses + * @param searchCriteria The parameter is used to specify which search criteria should be used. \"ALL\" = search identifier can be VRM, VIN, last six digits of the VIN or trailerId. VRM = between 3 and 8 characters, VIN = >8 characters, partial VIN = exactly 6 digits and trailerId = exactly 8 digits / 1 letter followed by exactly 6 digits. If any other value than \"ALL\" is used then the search will be done using the specified search criteria, without taking into account the format of the saerch identifier. + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public getTechRecords(searchIdentifier: string, metadata?: boolean, status?: string, searchCriteria?: string, observe?: 'body', reportProgress?: boolean): Observable; + public getTechRecords(searchIdentifier: string, metadata?: boolean, status?: string, searchCriteria?: string, observe?: 'response', reportProgress?: boolean): Observable>; + public getTechRecords(searchIdentifier: string, metadata?: boolean, status?: string, searchCriteria?: string, observe?: 'events', reportProgress?: boolean): Observable>; + public getTechRecords(searchIdentifier: string, metadata?: boolean, status?: string, searchCriteria?: string, observe: any = 'body', reportProgress: boolean = false ): Observable { + + if (searchIdentifier === null || searchIdentifier === undefined) { + throw new Error('Required parameter searchIdentifier was null or undefined when calling getTechRecords.'); + } + + + + + let queryParameters = new HttpParams({encoder: new CustomHttpUrlEncodingCodec()}); + if (metadata !== undefined && metadata !== null) { + queryParameters = queryParameters.set('metadata', metadata); + } + if (status !== undefined && status !== null) { + queryParameters = queryParameters.set('status', status); + } + if (searchCriteria !== undefined && searchCriteria !== null) { + queryParameters = queryParameters.set('searchCriteria', searchCriteria); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/json' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + ]; + + return this.httpClient.request('get',`${this.basePath}/vehicles/${encodeURIComponent(String(searchIdentifier))}/tech-records`, + { + params: queryParameters, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + } diff --git a/src/app/api/vehicle/api/postTechRecords.service.ts b/src/app/api/vehicle/api/postTechRecords.service.ts index f3215ca8c5..352391a9ea 100644 --- a/src/app/api/vehicle/api/postTechRecords.service.ts +++ b/src/app/api/vehicle/api/postTechRecords.service.ts @@ -7,106 +7,106 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - */ /* tslint:disable:no-unused-variable member-ordering */ + *//* tslint:disable:no-unused-variable member-ordering */ -import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http'; -import { Inject, Injectable, Optional } from '@angular/core'; +import { Inject, Injectable, Optional } from '@angular/core'; +import { HttpClient, HttpHeaders, HttpParams, + HttpResponse, HttpEvent } from '@angular/common/http'; +import { CustomHttpUrlEncodingCodec } from '../encoder'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { TechRecordPOST } from '../model/techRecordPOST'; -import { Configuration } from '../configuration'; -import { BASE_PATH } from '../variables'; +import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; +import { Configuration } from '../configuration'; + @Injectable() export class PostTechRecordsService { - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor( - protected httpClient: HttpClient, - @Optional() @Inject(BASE_PATH) basePath: string, - @Optional() configuration: Configuration - ) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - /** - * Create a tech record - * - * @param body The tech record to create - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public postTechRecords(body: TechRecordPOST, observe?: 'body', reportProgress?: boolean): Observable; - public postTechRecords( - body: TechRecordPOST, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public postTechRecords( - body: TechRecordPOST, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public postTechRecords(body: TechRecordPOST, observe: any = 'body', reportProgress = false): Observable { - if (body === null || body === undefined) { - throw new Error('Required parameter body was null or undefined when calling postTechRecords.'); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = - typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', `Bearer ${accessToken}`); - } - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/text']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = ['application/json']; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request('post', `${this.basePath}/vehicles`, { - body: body, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - }); - } + + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + + /** + * Create a tech record + * + * @param body The tech record to create + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public postTechRecords(body: TechRecordPOST, observe?: 'body', reportProgress?: boolean): Observable; + public postTechRecords(body: TechRecordPOST, observe?: 'response', reportProgress?: boolean): Observable>; + public postTechRecords(body: TechRecordPOST, observe?: 'events', reportProgress?: boolean): Observable>; + public postTechRecords(body: TechRecordPOST, observe: any = 'body', reportProgress: boolean = false ): Observable { + + if (body === null || body === undefined) { + throw new Error('Required parameter body was null or undefined when calling postTechRecords.'); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/text' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + 'application/json' + ]; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request('post',`${this.basePath}/vehicles`, + { + body: body, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + } diff --git a/src/app/api/vehicle/api/updateTechRecords.service.ts b/src/app/api/vehicle/api/updateTechRecords.service.ts index ab1f7841a5..b5d1e53c67 100644 --- a/src/app/api/vehicle/api/updateTechRecords.service.ts +++ b/src/app/api/vehicle/api/updateTechRecords.service.ts @@ -7,140 +7,120 @@ * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. - */ /* tslint:disable:no-unused-variable member-ordering */ + *//* tslint:disable:no-unused-variable member-ordering */ -import { HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpResponse } from '@angular/common/http'; -import { Inject, Injectable, Optional } from '@angular/core'; -import { CustomHttpUrlEncodingCodec } from '../encoder'; +import { Inject, Injectable, Optional } from '@angular/core'; +import { HttpClient, HttpHeaders, HttpParams, + HttpResponse, HttpEvent } from '@angular/common/http'; +import { CustomHttpUrlEncodingCodec } from '../encoder'; -import { Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { CompleteTechRecordPUT } from '../model/completeTechRecordPUT'; import { TechRecordPUT } from '../model/techRecordPUT'; -import { Configuration } from '../configuration'; -import { BASE_PATH } from '../variables'; +import { BASE_PATH, COLLECTION_FORMATS } from '../variables'; +import { Configuration } from '../configuration'; + @Injectable() export class UpdateTechRecordsService { - protected basePath = 'https://url/api/v1'; - public defaultHeaders = new HttpHeaders(); - public configuration = new Configuration(); - - constructor( - protected httpClient: HttpClient, - @Optional() @Inject(BASE_PATH) basePath: string, - @Optional() configuration: Configuration - ) { - if (basePath) { - this.basePath = basePath; - } - if (configuration) { - this.configuration = configuration; - this.basePath = basePath || configuration.basePath || this.basePath; - } - } - - /** - * @param consumes string[] mime-types - * @return true: consumes contains 'multipart/form-data', false: otherwise - */ - private canConsumeForm(consumes: string[]): boolean { - const form = 'multipart/form-data'; - for (const consume of consumes) { - if (form === consume) { - return true; - } - } - return false; - } - - /** - * Update a tech record, for a particular systemNumber - * - * @param body The tech record to update - * @param systemNumber This represents the systemNumber of the vehicle - * @param oldStatusCode This represents the old statusCode of a techRecord. Should be passed only if the statusCode was changed. - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public updateTechRecords( - body: TechRecordPUT, - systemNumber: string, - oldStatusCode?: string, - observe?: 'body', - reportProgress?: boolean - ): Observable; - public updateTechRecords( - body: TechRecordPUT, - systemNumber: string, - oldStatusCode?: string, - observe?: 'response', - reportProgress?: boolean - ): Observable>; - public updateTechRecords( - body: TechRecordPUT, - systemNumber: string, - oldStatusCode?: string, - observe?: 'events', - reportProgress?: boolean - ): Observable>; - public updateTechRecords( - body: TechRecordPUT, - systemNumber: string, - oldStatusCode?: string, - observe: any = 'body', - reportProgress = false - ): Observable { - if (body === null || body === undefined) { - throw new Error('Required parameter body was null or undefined when calling updateTechRecords.'); - } - - if (systemNumber === null || systemNumber === undefined) { - throw new Error('Required parameter systemNumber was null or undefined when calling updateTechRecords.'); - } - - let queryParameters = new HttpParams({ encoder: new CustomHttpUrlEncodingCodec() }); - if (oldStatusCode !== undefined && oldStatusCode !== null) { - queryParameters = queryParameters.set('oldStatusCode', oldStatusCode); - } - - let headers = this.defaultHeaders; - - // authentication (OAuth2) required - if (this.configuration.accessToken) { - const accessToken = - typeof this.configuration.accessToken === 'function' - ? this.configuration.accessToken() - : this.configuration.accessToken; - headers = headers.set('Authorization', `Bearer ${accessToken}`); - } - - // to determine the Accept header - const httpHeaderAccepts: string[] = ['application/json']; - const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); - if (httpHeaderAcceptSelected != undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - // to determine the Content-Type header - const consumes: string[] = ['application/json']; - const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); - if (httpContentTypeSelected != undefined) { - headers = headers.set('Content-Type', httpContentTypeSelected); - } - - return this.httpClient.request( - 'put', - `${this.basePath}/vehicles/${encodeURIComponent(String(systemNumber))}`, - { - body: body, - params: queryParameters, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress, - } - ); - } + + protected basePath = 'https://url/api/v1'; + public defaultHeaders = new HttpHeaders(); + public configuration = new Configuration(); + + constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { + if (basePath) { + this.basePath = basePath; + } + if (configuration) { + this.configuration = configuration; + this.basePath = basePath || configuration.basePath || this.basePath; + } + } + + /** + * @param consumes string[] mime-types + * @return true: consumes contains 'multipart/form-data', false: otherwise + */ + private canConsumeForm(consumes: string[]): boolean { + const form = 'multipart/form-data'; + for (const consume of consumes) { + if (form === consume) { + return true; + } + } + return false; + } + + + /** + * Update a tech record, for a particular systemNumber + * + * @param body The tech record to update + * @param systemNumber This represents the systemNumber of the vehicle + * @param oldStatusCode This represents the old statusCode of a techRecord. Should be passed only if the statusCode was changed. + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public updateTechRecords(body: TechRecordPUT, systemNumber: string, oldStatusCode?: string, observe?: 'body', reportProgress?: boolean): Observable; + public updateTechRecords(body: TechRecordPUT, systemNumber: string, oldStatusCode?: string, observe?: 'response', reportProgress?: boolean): Observable>; + public updateTechRecords(body: TechRecordPUT, systemNumber: string, oldStatusCode?: string, observe?: 'events', reportProgress?: boolean): Observable>; + public updateTechRecords(body: TechRecordPUT, systemNumber: string, oldStatusCode?: string, observe: any = 'body', reportProgress: boolean = false ): Observable { + + if (body === null || body === undefined) { + throw new Error('Required parameter body was null or undefined when calling updateTechRecords.'); + } + + if (systemNumber === null || systemNumber === undefined) { + throw new Error('Required parameter systemNumber was null or undefined when calling updateTechRecords.'); + } + + + let queryParameters = new HttpParams({encoder: new CustomHttpUrlEncodingCodec()}); + if (oldStatusCode !== undefined && oldStatusCode !== null) { + queryParameters = queryParameters.set('oldStatusCode', oldStatusCode); + } + + let headers = this.defaultHeaders; + + // authentication (OAuth2) required + if (this.configuration.accessToken) { + const accessToken = typeof this.configuration.accessToken === 'function' + ? this.configuration.accessToken() + : this.configuration.accessToken; + headers = headers.set('Authorization', 'Bearer ' + accessToken); + } + + // to determine the Accept header + let httpHeaderAccepts: string[] = [ + 'application/json' + ]; + const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts); + if (httpHeaderAcceptSelected != undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + // to determine the Content-Type header + const consumes: string[] = [ + 'application/json' + ]; + const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes); + if (httpContentTypeSelected != undefined) { + headers = headers.set('Content-Type', httpContentTypeSelected); + } + + return this.httpClient.request('put',`${this.basePath}/vehicles/${encodeURIComponent(String(systemNumber))}`, + { + body: body, + params: queryParameters, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + } diff --git a/src/app/api/vehicle/configuration.ts b/src/app/api/vehicle/configuration.ts index 8a8c9a845e..82e8458f39 100644 --- a/src/app/api/vehicle/configuration.ts +++ b/src/app/api/vehicle/configuration.ts @@ -1,79 +1,79 @@ export interface ConfigurationParameters { - apiKeys?: { [key: string]: string }; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: {[ key: string ]: string}; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; } export class Configuration { - apiKeys?: { [key: string]: string }; - username?: string; - password?: string; - accessToken?: string | (() => string); - basePath?: string; - withCredentials?: boolean; + apiKeys?: {[ key: string ]: string}; + username?: string; + password?: string; + accessToken?: string | (() => string); + basePath?: string; + withCredentials?: boolean; - constructor(configurationParameters: ConfigurationParameters = {}) { - this.apiKeys = configurationParameters.apiKeys; - this.username = configurationParameters.username; - this.password = configurationParameters.password; - this.accessToken = configurationParameters.accessToken; - this.basePath = configurationParameters.basePath; - this.withCredentials = configurationParameters.withCredentials; - } + constructor(configurationParameters: ConfigurationParameters = {}) { + this.apiKeys = configurationParameters.apiKeys; + this.username = configurationParameters.username; + this.password = configurationParameters.password; + this.accessToken = configurationParameters.accessToken; + this.basePath = configurationParameters.basePath; + this.withCredentials = configurationParameters.withCredentials; + } - /** - * Select the correct content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param contentTypes - the array of content types that are available for selection - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderContentType(contentTypes: string[]): string | undefined { - if (contentTypes.length == 0) { - return undefined; - } + /** + * Select the correct content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param contentTypes - the array of content types that are available for selection + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderContentType (contentTypes: string[]): string | undefined { + if (contentTypes.length == 0) { + return undefined; + } - const type = contentTypes.find((x) => this.isJsonMime(x)); - if (type === undefined) { - return contentTypes[0]; - } - return type; - } + let type = contentTypes.find(x => this.isJsonMime(x)); + if (type === undefined) { + return contentTypes[0]; + } + return type; + } - /** - * Select the correct accept content-type to use for a request. - * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. - * If no content type is found return the first found type if the contentTypes is not empty - * @param accepts - the array of content types that are available for selection. - * @returns the selected content-type or undefined if no selection could be made. - */ - public selectHeaderAccept(accepts: string[]): string | undefined { - if (accepts.length == 0) { - return undefined; - } + /** + * Select the correct accept content-type to use for a request. + * Uses {@link Configuration#isJsonMime} to determine the correct accept content-type. + * If no content type is found return the first found type if the contentTypes is not empty + * @param accepts - the array of content types that are available for selection. + * @returns the selected content-type or undefined if no selection could be made. + */ + public selectHeaderAccept(accepts: string[]): string | undefined { + if (accepts.length == 0) { + return undefined; + } - const type = accepts.find((x) => this.isJsonMime(x)); - if (type === undefined) { - return accepts[0]; - } - return type; - } + let type = accepts.find(x => this.isJsonMime(x)); + if (type === undefined) { + return accepts[0]; + } + return type; + } - /** - * Check if the given MIME is a JSON MIME. - * JSON MIME examples: - * application/json - * application/json; charset=UTF8 - * APPLICATION/JSON - * application/vnd.company+json - * @param mime - MIME (Multipurpose Internet Mail Extensions) - * @return True if the given MIME is JSON, false otherwise. - */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); - return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } } diff --git a/src/app/api/vehicle/encoder.ts b/src/app/api/vehicle/encoder.ts index 1d5c24dfd9..5d0fb0e90c 100644 --- a/src/app/api/vehicle/encoder.ts +++ b/src/app/api/vehicle/encoder.ts @@ -1,4 +1,4 @@ -import {HttpUrlEncodingCodec} from '@angular/common/http'; +import { HttpUrlEncodingCodec } from '@angular/common/http'; /** * CustomHttpUrlEncodingCodec @@ -6,13 +6,12 @@ import {HttpUrlEncodingCodec} from '@angular/common/http'; * See: https://github.com/angular/angular/issues/11058#issuecomment-247367318 */ export class CustomHttpUrlEncodingCodec extends HttpUrlEncodingCodec { - override encodeKey(key: string): string { - const k = super.encodeKey(key); - return k.replace(/\+/gi, '%2B'); - } - - override encodeValue(value: string): string { - const v = super.encodeValue(value); - return v.replace(/\+/gi, '%2B'); - } + override encodeKey(k: string): string { + k = super.encodeKey(k); + return k.replace(/\+/gi, '%2B'); + } + override encodeValue(v: string): string { + v = super.encodeValue(v); + return v.replace(/\+/gi, '%2B'); + } } diff --git a/src/app/api/vehicle/index.ts b/src/app/api/vehicle/index.ts index 410623f1c9..c312b70fa3 100644 --- a/src/app/api/vehicle/index.ts +++ b/src/app/api/vehicle/index.ts @@ -2,4 +2,4 @@ export * from './api/api'; export * from './model/models'; export * from './variables'; export * from './configuration'; -export * from './api.module'; +export * from './api.module'; \ No newline at end of file diff --git a/src/app/api/vehicle/model/adrDetails.ts b/src/app/api/vehicle/model/adrDetails.ts index 290aab8780..4a2192c11d 100644 --- a/src/app/api/vehicle/model/adrDetails.ts +++ b/src/app/api/vehicle/model/adrDetails.ts @@ -16,56 +16,56 @@ import { AdrDetailsVehicleDetails } from './adrDetailsVehicleDetails'; /** * Used only for HGV and TRL */ -export interface AdrDetails { - vehicleDetails?: AdrDetailsVehicleDetails; - /** - * Optional. Applicable only if vehicleDetails.type contains the word ‘battery’. - */ - listStatementApplicable?: boolean; - /** - * Mandatory if listStatementApplicable is true, therefore applicable only if vehicleDetails.type contains the word ‘battery’. Else N/A - */ - batteryListNumber?: string; - /** - * Optional for all vehicle types - */ - declarationsSeen?: boolean; - /** - * Optional for all vehicle types - */ - brakeDeclarationsSeen?: boolean; - /** - * Optional for all vehicle types - */ - brakeDeclarationIssuer?: string; - /** - * Optional for all vehicle types - */ - brakeEndurance?: boolean; - /** - * Mandatory if brakeEndurance = true, else N/A - */ - weight?: string; - /** - * Optional for all vehicle types - */ - compatibilityGroupJ?: boolean; - /** - * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - documents?: Array; - /** - * Mandatory. Users must select, AT LEAST ONE of these. However, users CAN select more than one - */ - permittedDangerousGoods?: Array; - /** - * Optional for all vehicle types - */ - additionalExaminerNotes?: string; - applicantDetails?: AdrDetailsApplicantDetails; - memosApply?: Array; - additionalNotes?: AdrDetailsAdditionalNotes; - adrTypeApprovalNo?: string; - adrCertificateNotes?: string; - tank?: AdrDetailsTank; -} +export interface AdrDetails { + vehicleDetails?: AdrDetailsVehicleDetails; + /** + * Optional. Applicable only if vehicleDetails.type contains the word ‘battery’. + */ + listStatementApplicable?: boolean; + /** + * Mandatory if listStatementApplicable is true, therefore applicable only if vehicleDetails.type contains the word ‘battery’. Else N/A + */ + batteryListNumber?: string; + /** + * Optional for all vehicle types + */ + declarationsSeen?: boolean; + /** + * Optional for all vehicle types + */ + brakeDeclarationsSeen?: boolean; + /** + * Optional for all vehicle types + */ + brakeDeclarationIssuer?: string; + /** + * Optional for all vehicle types + */ + brakeEndurance?: boolean; + /** + * Mandatory if brakeEndurance = true, else N/A + */ + weight?: string; + /** + * Optional for all vehicle types + */ + compatibilityGroupJ?: boolean; + /** + * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + documents?: Array; + /** + * Mandatory. Users must select, AT LEAST ONE of these. However, users CAN select more than one + */ + permittedDangerousGoods?: Array; + /** + * Optional for all vehicle types + */ + additionalExaminerNotes?: string; + applicantDetails?: AdrDetailsApplicantDetails; + memosApply?: Array; + additionalNotes?: AdrDetailsAdditionalNotes; + adrTypeApprovalNo?: string; + adrCertificateNotes?: string; + tank?: AdrDetailsTank; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/adrDetailsAdditionalNotes.ts b/src/app/api/vehicle/model/adrDetailsAdditionalNotes.ts index 83bfc89334..36c3484486 100644 --- a/src/app/api/vehicle/model/adrDetailsAdditionalNotes.ts +++ b/src/app/api/vehicle/model/adrDetailsAdditionalNotes.ts @@ -9,13 +9,13 @@ * Do not edit the class manually. */ -export interface AdrDetailsAdditionalNotes { - /** - * Optional for all vehicle types - */ - number?: Array; - /** - * Optional for all vehicle types - */ - guidanceNotes?: Array; -} +export interface AdrDetailsAdditionalNotes { + /** + * Optional for all vehicle types + */ + number?: Array; + /** + * Optional for all vehicle types + */ + guidanceNotes?: Array; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/adrDetailsApplicantDetails.ts b/src/app/api/vehicle/model/adrDetailsApplicantDetails.ts index db19406345..16277b4715 100644 --- a/src/app/api/vehicle/model/adrDetailsApplicantDetails.ts +++ b/src/app/api/vehicle/model/adrDetailsApplicantDetails.ts @@ -9,10 +9,10 @@ * Do not edit the class manually. */ -export interface AdrDetailsApplicantDetails { - name?: string; - street?: string; - town?: string; - city?: string; - postcode?: string; -} +export interface AdrDetailsApplicantDetails { + name?: string; + street?: string; + town?: string; + city?: string; + postcode?: string; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/adrDetailsTank.ts b/src/app/api/vehicle/model/adrDetailsTank.ts index 1c283e18cf..49d6ec0050 100644 --- a/src/app/api/vehicle/model/adrDetailsTank.ts +++ b/src/app/api/vehicle/model/adrDetailsTank.ts @@ -11,7 +11,7 @@ import { AdrDetailsTankTankDetails } from './adrDetailsTankTankDetails'; import { AdrDetailsTankTankStatement } from './adrDetailsTankTankStatement'; -export interface AdrDetailsTank { - tankDetails?: AdrDetailsTankTankDetails; - tankStatement?: AdrDetailsTankTankStatement; -} +export interface AdrDetailsTank { + tankDetails?: AdrDetailsTankTankDetails; + tankStatement?: AdrDetailsTankTankStatement; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/adrDetailsTankTankDetails.ts b/src/app/api/vehicle/model/adrDetailsTankTankDetails.ts index b946f931ea..4e0dc8993f 100644 --- a/src/app/api/vehicle/model/adrDetailsTankTankDetails.ts +++ b/src/app/api/vehicle/model/adrDetailsTankTankDetails.ts @@ -11,31 +11,31 @@ import { AdrDetailsTankTankDetailsTc2Details } from './adrDetailsTankTankDetailsTc2Details'; import { AdrDetailsTankTankDetailsTc3Details } from './adrDetailsTankTankDetailsTc3Details'; -export interface AdrDetailsTankTankDetails { - /** - * Mandatory. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tankManufacturer?: string; - /** - * Mandatory. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - yearOfManufacture?: number; - /** - * Mandatory. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tankCode?: string; - /** - * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - specialProvisions?: string; - /** - * Mandatory. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tankManufacturerSerialNo?: string; - /** - * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tankTypeAppNo?: string; - tc2Details?: AdrDetailsTankTankDetailsTc2Details; - tc3Details?: Array; -} +export interface AdrDetailsTankTankDetails { + /** + * Mandatory. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tankManufacturer?: string; + /** + * Mandatory. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + yearOfManufacture?: number; + /** + * Mandatory. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tankCode?: string; + /** + * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + specialProvisions?: string; + /** + * Mandatory. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tankManufacturerSerialNo?: string; + /** + * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tankTypeAppNo?: string; + tc2Details?: AdrDetailsTankTankDetailsTc2Details; + tc3Details?: Array; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/adrDetailsTankTankDetailsTc2Details.ts b/src/app/api/vehicle/model/adrDetailsTankTankDetailsTc2Details.ts index acf7d9ad29..ee1d2d8090 100644 --- a/src/app/api/vehicle/model/adrDetailsTankTankDetailsTc2Details.ts +++ b/src/app/api/vehicle/model/adrDetailsTankTankDetailsTc2Details.ts @@ -9,23 +9,23 @@ * Do not edit the class manually. */ -export interface AdrDetailsTankTankDetailsTc2Details { - /** - * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tc2Type?: AdrDetailsTankTankDetailsTc2Details.Tc2TypeEnum; - /** - * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tc2IntermediateApprovalNo?: string; - /** - * Optional. Date(YYYY-MM-DD). Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tc2IntermediateExpiryDate?: string; +export interface AdrDetailsTankTankDetailsTc2Details { + /** + * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tc2Type?: AdrDetailsTankTankDetailsTc2Details.Tc2TypeEnum; + /** + * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tc2IntermediateApprovalNo?: string; + /** + * Optional. Date(YYYY-MM-DD). Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tc2IntermediateExpiryDate?: string; } export namespace AdrDetailsTankTankDetailsTc2Details { - export type Tc2TypeEnum = 'initial'; - export const Tc2TypeEnum = { - Initial: 'initial' as Tc2TypeEnum, - }; -} + export type Tc2TypeEnum = 'initial'; + export const Tc2TypeEnum = { + Initial: 'initial' as Tc2TypeEnum + }; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/adrDetailsTankTankDetailsTc3Details.ts b/src/app/api/vehicle/model/adrDetailsTankTankDetailsTc3Details.ts index 7d935c90b7..c36f8c1c0a 100644 --- a/src/app/api/vehicle/model/adrDetailsTankTankDetailsTc3Details.ts +++ b/src/app/api/vehicle/model/adrDetailsTankTankDetailsTc3Details.ts @@ -10,24 +10,24 @@ */ export interface AdrDetailsTankTankDetailsTc3Details { - /** - * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tc3Type?: AdrDetailsTankTankDetailsTc3Details.Tc3TypeEnum; - /** - * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tc3PeriodicNumber?: string; - /** - * Optional. Date(YYYY-MM-DD). Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. - */ - tc3PeriodicExpiryDate?: string; + /** + * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tc3Type?: AdrDetailsTankTankDetailsTc3Details.Tc3TypeEnum; + /** + * Optional. Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tc3PeriodicNumber?: string; + /** + * Optional. Date(YYYY-MM-DD). Applicable only if vehicleDetails.type contains the word ‘tank’ or ‘battery’. + */ + tc3PeriodicExpiryDate?: string; } export namespace AdrDetailsTankTankDetailsTc3Details { - export type Tc3TypeEnum = 'intermediate' | 'periodic' | 'exceptional'; - export const Tc3TypeEnum = { - Intermediate: 'intermediate' as Tc3TypeEnum, - Periodic: 'periodic' as Tc3TypeEnum, - Exceptional: 'exceptional' as Tc3TypeEnum, - }; + export type Tc3TypeEnum = 'intermediate' | 'periodic' | 'exceptional'; + export const Tc3TypeEnum = { + Intermediate: 'intermediate' as Tc3TypeEnum, + Periodic: 'periodic' as Tc3TypeEnum, + Exceptional: 'exceptional' as Tc3TypeEnum + }; } diff --git a/src/app/api/vehicle/model/adrDetailsTankTankStatement.ts b/src/app/api/vehicle/model/adrDetailsTankTankStatement.ts index 27d37327f9..4ce7b52ddb 100644 --- a/src/app/api/vehicle/model/adrDetailsTankTankStatement.ts +++ b/src/app/api/vehicle/model/adrDetailsTankTankStatement.ts @@ -9,25 +9,25 @@ * Do not edit the class manually. */ -export interface AdrDetailsTankTankStatement { - /** - * Mandatory IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ ELSE, optional. If mandatory, users must select ONE of these. Users cannot select less/more than one - */ - substancesPermitted?: string; - /** - * Optional. Applicable only IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ - */ - statement?: string; - /** - * Optional. Applicable only IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ - */ - productListRefNo?: string; - /** - * Optional. Applicable only IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ - */ - productListUnNo?: Array; - /** - * Optional. Applicable only IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ - */ - productList?: string; -} +export interface AdrDetailsTankTankStatement { + /** + * Mandatory IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ ELSE, optional. If mandatory, users must select ONE of these. Users cannot select less/more than one + */ + substancesPermitted?: string; + /** + * Optional. Applicable only IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ + */ + statement?: string; + /** + * Optional. Applicable only IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ + */ + productListRefNo?: string; + /** + * Optional. Applicable only IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ + */ + productListUnNo?: Array; + /** + * Optional. Applicable only IF vehicleDetails.type contains the word ‘tank’ or ‘battery’ + */ + productList?: string; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/adrDetailsVehicleDetails.ts b/src/app/api/vehicle/model/adrDetailsVehicleDetails.ts index 62346e9b3d..426af68ac1 100644 --- a/src/app/api/vehicle/model/adrDetailsVehicleDetails.ts +++ b/src/app/api/vehicle/model/adrDetailsVehicleDetails.ts @@ -9,13 +9,13 @@ * Do not edit the class manually. */ -export interface AdrDetailsVehicleDetails { - /** - * Mandatory. Users must select ONE of these. Users cannot select less/more - */ - type?: string; - /** - * Date (YYYY-MM-DD) - */ - approvalDate?: string; -} +export interface AdrDetailsVehicleDetails { + /** + * Mandatory. Users must select ONE of these. Users cannot select less/more + */ + type?: string; + /** + * Date (YYYY-MM-DD) + */ + approvalDate?: string; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/applicantDetailsProperties.ts b/src/app/api/vehicle/model/applicantDetailsProperties.ts index 0f6443b1f7..a2c7b8922e 100644 --- a/src/app/api/vehicle/model/applicantDetailsProperties.ts +++ b/src/app/api/vehicle/model/applicantDetailsProperties.ts @@ -12,13 +12,13 @@ /** * Used for all vehicle types */ -export interface ApplicantDetailsProperties { - name?: string; - address1?: string; - address2?: string; - postTown?: string; - address3?: string; - postCode?: string; - emailAddress?: string; - telephoneNumber?: string; -} +export interface ApplicantDetailsProperties { + name?: string; + address1?: string; + address2?: string; + postTown?: string; + address3?: string; + postCode?: string; + emailAddress?: string; + telephoneNumber?: string; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/authIntoService.ts b/src/app/api/vehicle/model/authIntoService.ts index 6aeaf4598d..4aee7abb64 100644 --- a/src/app/api/vehicle/model/authIntoService.ts +++ b/src/app/api/vehicle/model/authIntoService.ts @@ -12,25 +12,25 @@ /** * Authorization into service */ -export interface AuthIntoService { - /** - * Used only for TRL - */ - cocIssueDate?: string; - /** - * Used only for TRL - */ - dateReceived?: string; - /** - * Used only for TRL - */ - datePending?: string; - /** - * Used only for TRL - */ - dateAuthorised?: string; - /** - * Used only for TRL - */ - dateRejected?: string; -} +export interface AuthIntoService { + /** + * Used only for TRL + */ + cocIssueDate?: string; + /** + * Used only for TRL + */ + dateReceived?: string; + /** + * Used only for TRL + */ + datePending?: string; + /** + * Used only for TRL + */ + dateAuthorised?: string; + /** + * Used only for TRL + */ + dateRejected?: string; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/axleBrakeProperties.ts b/src/app/api/vehicle/model/axleBrakeProperties.ts index c0b9c41db0..98f174d6bd 100644 --- a/src/app/api/vehicle/model/axleBrakeProperties.ts +++ b/src/app/api/vehicle/model/axleBrakeProperties.ts @@ -12,8 +12,8 @@ /** * Used only for TRL */ -export interface AxleBrakeProperties { - brakeActuator?: number; - leverLength?: number; - springBrakeParking?: boolean; -} +export interface AxleBrakeProperties { + brakeActuator?: number; + leverLength?: number; + springBrakeParking?: boolean; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/axleTyreProperties.ts b/src/app/api/vehicle/model/axleTyreProperties.ts index cf2ca08122..b710ca19ce 100644 --- a/src/app/api/vehicle/model/axleTyreProperties.ts +++ b/src/app/api/vehicle/model/axleTyreProperties.ts @@ -9,69 +9,54 @@ * Do not edit the class manually. */ -export interface AxleTyreProperties { - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - tyreSize?: string; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - plyRating?: string; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - fitmentCode?: AxleTyreProperties.FitmentCodeEnum; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - dataTrAxles?: number; - /** - * Used only for PSV - */ - speedCategorySymbol?: AxleTyreProperties.SpeedCategorySymbolEnum; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - tyreCode?: number; +export interface AxleTyreProperties { + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + tyreSize?: string; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + plyRating?: string; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + fitmentCode?: AxleTyreProperties.FitmentCodeEnum; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + dataTrAxles?: number; + /** + * Used only for PSV + */ + speedCategorySymbol?: AxleTyreProperties.SpeedCategorySymbolEnum; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + tyreCode?: number; } export namespace AxleTyreProperties { - export type FitmentCodeEnum = 'double' | 'single'; - export const FitmentCodeEnum = { - Double: 'double' as FitmentCodeEnum, - Single: 'single' as FitmentCodeEnum, - }; - export type SpeedCategorySymbolEnum = - | 'a7' - | 'a8' - | 'b' - | 'c' - | 'd' - | 'e' - | 'f' - | 'g' - | 'j' - | 'k' - | 'l' - | 'm' - | 'n' - | 'p' - | 'q'; - export const SpeedCategorySymbolEnum = { - A7: 'a7' as SpeedCategorySymbolEnum, - A8: 'a8' as SpeedCategorySymbolEnum, - B: 'b' as SpeedCategorySymbolEnum, - C: 'c' as SpeedCategorySymbolEnum, - D: 'd' as SpeedCategorySymbolEnum, - E: 'e' as SpeedCategorySymbolEnum, - F: 'f' as SpeedCategorySymbolEnum, - G: 'g' as SpeedCategorySymbolEnum, - J: 'j' as SpeedCategorySymbolEnum, - K: 'k' as SpeedCategorySymbolEnum, - L: 'l' as SpeedCategorySymbolEnum, - M: 'm' as SpeedCategorySymbolEnum, - N: 'n' as SpeedCategorySymbolEnum, - P: 'p' as SpeedCategorySymbolEnum, - Q: 'q' as SpeedCategorySymbolEnum, - }; -} + export type FitmentCodeEnum = 'double' | 'single'; + export const FitmentCodeEnum = { + Double: 'double' as FitmentCodeEnum, + Single: 'single' as FitmentCodeEnum + }; + export type SpeedCategorySymbolEnum = 'a7' | 'a8' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'j' | 'k' | 'l' | 'm' | 'n' | 'p' | 'q'; + export const SpeedCategorySymbolEnum = { + A7: 'a7' as SpeedCategorySymbolEnum, + A8: 'a8' as SpeedCategorySymbolEnum, + B: 'b' as SpeedCategorySymbolEnum, + C: 'c' as SpeedCategorySymbolEnum, + D: 'd' as SpeedCategorySymbolEnum, + E: 'e' as SpeedCategorySymbolEnum, + F: 'f' as SpeedCategorySymbolEnum, + G: 'g' as SpeedCategorySymbolEnum, + J: 'j' as SpeedCategorySymbolEnum, + K: 'k' as SpeedCategorySymbolEnum, + L: 'l' as SpeedCategorySymbolEnum, + M: 'm' as SpeedCategorySymbolEnum, + N: 'n' as SpeedCategorySymbolEnum, + P: 'p' as SpeedCategorySymbolEnum, + Q: 'q' as SpeedCategorySymbolEnum + }; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/axleWeightProperties.ts b/src/app/api/vehicle/model/axleWeightProperties.ts index ac8064379d..16f32cfe2d 100644 --- a/src/app/api/vehicle/model/axleWeightProperties.ts +++ b/src/app/api/vehicle/model/axleWeightProperties.ts @@ -9,25 +9,25 @@ * Do not edit the class manually. */ -export interface AxleWeightProperties { - /** - * Used only for PSV - */ - kerbWeight?: number; - /** - * Used only for PSV - */ - ladenWeight?: number; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - gbWeight?: number; - /** - * Used only for HGV and TRL - */ - eecWeight?: number; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - designWeight?: number; -} +export interface AxleWeightProperties { + /** + * Used only for PSV + */ + kerbWeight?: number; + /** + * Used only for PSV + */ + ladenWeight?: number; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + gbWeight?: number; + /** + * Used only for HGV and TRL + */ + eecWeight?: number; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + designWeight?: number; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/axles.ts b/src/app/api/vehicle/model/axles.ts index ad9f2b858d..fc4ba71a07 100644 --- a/src/app/api/vehicle/model/axles.ts +++ b/src/app/api/vehicle/model/axles.ts @@ -10,4 +10,5 @@ */ import { Weights } from './weights'; -export interface Axles extends Array {} +export interface Axles extends Array { +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/brakeForceWheelsNotLocked.ts b/src/app/api/vehicle/model/brakeForceWheelsNotLocked.ts index dc798eae8b..9b9a7f2a80 100644 --- a/src/app/api/vehicle/model/brakeForceWheelsNotLocked.ts +++ b/src/app/api/vehicle/model/brakeForceWheelsNotLocked.ts @@ -9,17 +9,17 @@ * Do not edit the class manually. */ -export interface BrakeForceWheelsNotLocked { - /** - * Used only for PSV - */ - serviceBrakeForceA?: number; - /** - * Used only for PSV - */ - secondaryBrakeForceA?: number; - /** - * Used only for PSV - */ - parkingBrakeForceA?: number; -} +export interface BrakeForceWheelsNotLocked { + /** + * Used only for PSV + */ + serviceBrakeForceA?: number; + /** + * Used only for PSV + */ + secondaryBrakeForceA?: number; + /** + * Used only for PSV + */ + parkingBrakeForceA?: number; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/brakeForceWheelsUpToHalfLocked.ts b/src/app/api/vehicle/model/brakeForceWheelsUpToHalfLocked.ts index a5aa6b8ad7..03b7a04818 100644 --- a/src/app/api/vehicle/model/brakeForceWheelsUpToHalfLocked.ts +++ b/src/app/api/vehicle/model/brakeForceWheelsUpToHalfLocked.ts @@ -9,17 +9,17 @@ * Do not edit the class manually. */ -export interface BrakeForceWheelsUpToHalfLocked { - /** - * Used only for PSV - */ - serviceBrakeForceB?: number; - /** - * Used only for PSV - */ - secondaryBrakeForceB?: number; - /** - * Used only for PSV - */ - parkingBrakeForceB?: number; -} +export interface BrakeForceWheelsUpToHalfLocked { + /** + * Used only for PSV + */ + serviceBrakeForceB?: number; + /** + * Used only for PSV + */ + secondaryBrakeForceB?: number; + /** + * Used only for PSV + */ + parkingBrakeForceB?: number; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/brakes.ts b/src/app/api/vehicle/model/brakes.ts index 4983aafa5e..59315a8f2e 100644 --- a/src/app/api/vehicle/model/brakes.ts +++ b/src/app/api/vehicle/model/brakes.ts @@ -11,67 +11,67 @@ import { BrakeForceWheelsNotLocked } from './brakeForceWheelsNotLocked'; import { BrakeForceWheelsUpToHalfLocked } from './brakeForceWheelsUpToHalfLocked'; -export interface Brakes { - /** - * Used only for PSV - */ - brakeCodeOriginal?: string; - /** - * Used only for PSV - */ - brakeCode?: string; - /** - * Used only for PSV - */ - dataTrBrakeOne?: string; - /** - * Used only for PSV - */ - dataTrBrakeTwo?: string; - /** - * Used only for PSV - */ - dataTrBrakeThree?: string; - /** - * Used only for PSV - */ - retarderBrakeOne?: Brakes.RetarderBrakeOneEnum; - /** - * Used only for PSV - */ - retarderBrakeTwo?: Brakes.RetarderBrakeTwoEnum; - /** - * Used for PSV, HGV and TRL - */ - dtpNumber?: string; - brakeForceWheelsNotLocked?: BrakeForceWheelsNotLocked; - brakeForceWheelsUpToHalfLocked?: BrakeForceWheelsUpToHalfLocked; - /** - * Used only for TRL - */ - loadSensingValve?: boolean; - /** - * Used only for TRL - */ - antilockBrakingSystem?: boolean; +export interface Brakes { + /** + * Used only for PSV + */ + brakeCodeOriginal?: string; + /** + * Used only for PSV + */ + brakeCode?: string; + /** + * Used only for PSV + */ + dataTrBrakeOne?: string; + /** + * Used only for PSV + */ + dataTrBrakeTwo?: string; + /** + * Used only for PSV + */ + dataTrBrakeThree?: string; + /** + * Used only for PSV + */ + retarderBrakeOne?: Brakes.RetarderBrakeOneEnum; + /** + * Used only for PSV + */ + retarderBrakeTwo?: Brakes.RetarderBrakeTwoEnum; + /** + * Used for PSV, HGV and TRL + */ + dtpNumber?: string; + brakeForceWheelsNotLocked?: BrakeForceWheelsNotLocked; + brakeForceWheelsUpToHalfLocked?: BrakeForceWheelsUpToHalfLocked; + /** + * Used only for TRL + */ + loadSensingValve?: boolean; + /** + * Used only for TRL + */ + antilockBrakingSystem?: boolean; } export namespace Brakes { - export type RetarderBrakeOneEnum = 'electric' | 'exhaust' | 'friction' | 'hydraulic' | 'other' | 'none'; - export const RetarderBrakeOneEnum = { - Electric: 'electric' as RetarderBrakeOneEnum, - Exhaust: 'exhaust' as RetarderBrakeOneEnum, - Friction: 'friction' as RetarderBrakeOneEnum, - Hydraulic: 'hydraulic' as RetarderBrakeOneEnum, - Other: 'other' as RetarderBrakeOneEnum, - None: 'none' as RetarderBrakeOneEnum, - }; - export type RetarderBrakeTwoEnum = 'electric' | 'exhaust' | 'friction' | 'hydraulic' | 'other' | 'none'; - export const RetarderBrakeTwoEnum = { - Electric: 'electric' as RetarderBrakeTwoEnum, - Exhaust: 'exhaust' as RetarderBrakeTwoEnum, - Friction: 'friction' as RetarderBrakeTwoEnum, - Hydraulic: 'hydraulic' as RetarderBrakeTwoEnum, - Other: 'other' as RetarderBrakeTwoEnum, - None: 'none' as RetarderBrakeTwoEnum, - }; -} + export type RetarderBrakeOneEnum = 'electric' | 'exhaust' | 'friction' | 'hydraulic' | 'other' | 'none'; + export const RetarderBrakeOneEnum = { + Electric: 'electric' as RetarderBrakeOneEnum, + Exhaust: 'exhaust' as RetarderBrakeOneEnum, + Friction: 'friction' as RetarderBrakeOneEnum, + Hydraulic: 'hydraulic' as RetarderBrakeOneEnum, + Other: 'other' as RetarderBrakeOneEnum, + None: 'none' as RetarderBrakeOneEnum + }; + export type RetarderBrakeTwoEnum = 'electric' | 'exhaust' | 'friction' | 'hydraulic' | 'other' | 'none'; + export const RetarderBrakeTwoEnum = { + Electric: 'electric' as RetarderBrakeTwoEnum, + Exhaust: 'exhaust' as RetarderBrakeTwoEnum, + Friction: 'friction' as RetarderBrakeTwoEnum, + Hydraulic: 'hydraulic' as RetarderBrakeTwoEnum, + Other: 'other' as RetarderBrakeTwoEnum, + None: 'none' as RetarderBrakeTwoEnum + }; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/completeTechRecord.ts b/src/app/api/vehicle/model/completeTechRecord.ts index 1c40d4e552..fdf6a86f98 100644 --- a/src/app/api/vehicle/model/completeTechRecord.ts +++ b/src/app/api/vehicle/model/completeTechRecord.ts @@ -12,20 +12,20 @@ import { Metadata } from './metadata'; import { TechRecords } from './techRecords'; import { Vrms } from './vrms'; -export interface CompleteTechRecord { - /** - * It defines the composed primary key, in combination with \"vin\". - */ - systemNumber?: string; - vrms?: Vrms; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - vin?: string; - /** - * Used only for TRL - */ - trailerId?: string; - techRecord?: TechRecords; - metadata?: Metadata; -} +export interface CompleteTechRecord { + /** + * It defines the composed primary key, in combination with \"vin\". + */ + systemNumber?: string; + vrms?: Vrms; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + vin?: string; + /** + * Used only for TRL + */ + trailerId?: string; + techRecord?: TechRecords; + metadata?: Metadata; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/completeTechRecordDB.ts b/src/app/api/vehicle/model/completeTechRecordDB.ts index 870b4261b2..4658f27478 100644 --- a/src/app/api/vehicle/model/completeTechRecordDB.ts +++ b/src/app/api/vehicle/model/completeTechRecordDB.ts @@ -13,21 +13,21 @@ import { TechRecords } from './techRecords'; /** * the Tech objects as they */ -export interface CompleteTechRecordDB { - /** - * It defines the composed primary key, in combination with \"vin\". - */ - systemNumber?: string; - partialVin?: string; - primaryVrm?: string; - secondaryVrms?: Array; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - vin?: string; - /** - * Used only for TRL - */ - trailerId?: string; - techRecord?: TechRecords; -} +export interface CompleteTechRecordDB { + /** + * It defines the composed primary key, in combination with \"vin\". + */ + systemNumber?: string; + partialVin?: string; + primaryVrm?: string; + secondaryVrms?: Array; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + vin?: string; + /** + * Used only for TRL + */ + trailerId?: string; + techRecord?: TechRecords; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/completeTechRecordPUT.ts b/src/app/api/vehicle/model/completeTechRecordPUT.ts index 78a5f022c6..9252c923ba 100644 --- a/src/app/api/vehicle/model/completeTechRecordPUT.ts +++ b/src/app/api/vehicle/model/completeTechRecordPUT.ts @@ -11,19 +11,19 @@ import { TechRecords } from './techRecords'; import { Vrms } from './vrms'; -export interface CompleteTechRecordPUT { - /** - * It defines the composed primary key, in combination with \"vin\". - */ - systemNumber?: string; - vrms?: Vrms; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - vin?: string; - /** - * Used only for TRL - */ - trailerId?: string; - techRecord?: TechRecords; -} +export interface CompleteTechRecordPUT { + /** + * It defines the composed primary key, in combination with \"vin\". + */ + systemNumber?: string; + vrms?: Vrms; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + vin?: string; + /** + * Used only for TRL + */ + trailerId?: string; + techRecord?: TechRecords; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/completeTechRecords.ts b/src/app/api/vehicle/model/completeTechRecords.ts index 2cbc2c536c..4f754e34c0 100644 --- a/src/app/api/vehicle/model/completeTechRecords.ts +++ b/src/app/api/vehicle/model/completeTechRecords.ts @@ -10,4 +10,5 @@ */ import { CompleteTechRecord } from './completeTechRecord'; -export interface CompleteTechRecords extends Array {} +export interface CompleteTechRecords extends Array { +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/dda.ts b/src/app/api/vehicle/model/dda.ts index 498d17b66a..df3e575f26 100644 --- a/src/app/api/vehicle/model/dda.ts +++ b/src/app/api/vehicle/model/dda.ts @@ -12,53 +12,53 @@ /** * Disability Discrimination Act */ -export interface Dda { - /** - * Used only for PSV - */ - certificateIssued?: boolean; - /** - * Used only for PSV - */ - wheelchairCapacity?: number; - /** - * Used only for PSV - */ - wheelchairFittings?: string; - /** - * Used only for PSV - */ - wheelchairLiftPresent?: boolean; - /** - * Used only for PSV - */ - wheelchairLiftInformation?: string; - /** - * Used only for PSV - */ - wheelchairRampPresent?: boolean; - /** - * Used only for PSV - */ - wheelchairRampInformation?: string; - /** - * Used only for PSV - */ - minEmergencyExits?: number; - /** - * Used only for PSV - */ - outswing?: string; - /** - * Used only for PSV - */ - ddaSchedules?: string; - /** - * Used only for PSV - */ - seatbeltsFitted?: number; - /** - * Used only for PSV - */ - ddaNotes?: string; -} +export interface Dda { + /** + * Used only for PSV + */ + certificateIssued?: boolean; + /** + * Used only for PSV + */ + wheelchairCapacity?: number; + /** + * Used only for PSV + */ + wheelchairFittings?: string; + /** + * Used only for PSV + */ + wheelchairLiftPresent?: boolean; + /** + * Used only for PSV + */ + wheelchairLiftInformation?: string; + /** + * Used only for PSV + */ + wheelchairRampPresent?: boolean; + /** + * Used only for PSV + */ + wheelchairRampInformation?: string; + /** + * Used only for PSV + */ + minEmergencyExits?: number; + /** + * Used only for PSV + */ + outswing?: string; + /** + * Used only for PSV + */ + ddaSchedules?: string; + /** + * Used only for PSV + */ + seatbeltsFitted?: number; + /** + * Used only for PSV + */ + ddaNotes?: string; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/lettersOfAuth.ts b/src/app/api/vehicle/model/lettersOfAuth.ts index 5847c16708..52bb09af9e 100644 --- a/src/app/api/vehicle/model/lettersOfAuth.ts +++ b/src/app/api/vehicle/model/lettersOfAuth.ts @@ -12,24 +12,24 @@ /** * Letters of authorisation */ -export interface LettersOfAuth { - /** - * Used only for TRL - */ - letterType?: LettersOfAuth.LetterTypeEnum; - /** - * Used only for TRL - */ - letterDateRequested?: string; - /** - * Used only for TRL - */ - letterContents?: string; +export interface LettersOfAuth { + /** + * Used only for TRL + */ + letterType?: LettersOfAuth.LetterTypeEnum; + /** + * Used only for TRL + */ + letterDateRequested?: string; + /** + * Used only for TRL + */ + letterContents?: string; } export namespace LettersOfAuth { - export type LetterTypeEnum = 'Trailer authorization' | 'Trailer rejection'; - export const LetterTypeEnum = { - Authorization: 'Trailer authorization' as LetterTypeEnum, - Rejection: 'Trailer rejection' as LetterTypeEnum, - }; -} + export type LetterTypeEnum = 'Trailer authorization' | 'Trailer rejection'; + export const LetterTypeEnum = { + Authorization: 'Trailer authorization' as LetterTypeEnum, + Rejection: 'Trailer rejection' as LetterTypeEnum + }; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/manufacturerDetails.ts b/src/app/api/vehicle/model/manufacturerDetails.ts index 401f693735..3e6f9e2050 100644 --- a/src/app/api/vehicle/model/manufacturerDetails.ts +++ b/src/app/api/vehicle/model/manufacturerDetails.ts @@ -12,15 +12,15 @@ /** * Used for TRL only */ -export interface ManufacturerDetails { - name?: string; - address1?: string; - address2?: string; - postTown?: string; - address3?: string; - postCode?: string; - emailAddress?: string; - telephoneNumber?: string; - faxNumber?: string; - manufacturerNotes?: string; -} +export interface ManufacturerDetails { + name?: string; + address1?: string; + address2?: string; + postTown?: string; + address3?: string; + postCode?: string; + emailAddress?: string; + telephoneNumber?: string; + faxNumber?: string; + manufacturerNotes?: string; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/metadata.ts b/src/app/api/vehicle/model/metadata.ts index 9df852c501..4bfc91960f 100644 --- a/src/app/api/vehicle/model/metadata.ts +++ b/src/app/api/vehicle/model/metadata.ts @@ -13,11 +13,11 @@ import { MetadataAdrDetails } from './metadataAdrDetails'; /** * Applicable only to ADR details. Returned only if query param \"metadata\" = \"true\", otherwise not returned */ -export interface Metadata { - /** - * makeFe and chassisMakeFe fields have the same value. Combining them into a field for now so we don't send the same list twice. - */ - makeAndChassisMakeFe?: Array; - bodyMakeFe?: Array; - adrDetails?: MetadataAdrDetails; -} +export interface Metadata { + /** + * makeFe and chassisMakeFe fields have the same value. Combining them into a field for now so we don't send the same list twice. + */ + makeAndChassisMakeFe?: Array; + bodyMakeFe?: Array; + adrDetails?: MetadataAdrDetails; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/metadataAdrDetails.ts b/src/app/api/vehicle/model/metadataAdrDetails.ts index c02f4b7655..aac6b48499 100644 --- a/src/app/api/vehicle/model/metadataAdrDetails.ts +++ b/src/app/api/vehicle/model/metadataAdrDetails.ts @@ -12,35 +12,27 @@ import { MetadataAdrDetailsAdditionalNotes } from './metadataAdrDetailsAdditiona import { MetadataAdrDetailsTank } from './metadataAdrDetailsTank'; import { MetadataAdrDetailsVehicleDetails } from './metadataAdrDetailsVehicleDetails'; -export interface MetadataAdrDetails { - memosApplyFe?: Array; - tank?: MetadataAdrDetailsTank; - additionalNotes?: MetadataAdrDetailsAdditionalNotes; - permittedDangerousGoodsFe?: Array; - vehicleDetails?: MetadataAdrDetailsVehicleDetails; +export interface MetadataAdrDetails { + memosApplyFe?: Array; + tank?: MetadataAdrDetailsTank; + additionalNotes?: MetadataAdrDetailsAdditionalNotes; + permittedDangerousGoodsFe?: Array; + vehicleDetails?: MetadataAdrDetailsVehicleDetails; } export namespace MetadataAdrDetails { - export type MemosApplyFeEnum = '07/09 3mth leak ext'; - export const MemosApplyFeEnum = { - _07093mthLeakExt: '07/09 3mth leak ext' as MemosApplyFeEnum, - }; - export type PermittedDangerousGoodsFeEnum = - | 'FP <61 (FL)' - | 'AT' - | 'Class 5.1 Hydrogen Peroxide (OX)' - | 'MEMU' - | 'Carbon Disulphide' - | 'Hydrogen' - | 'Explosives (type 2)' - | 'Explosives (type 3)'; - export const PermittedDangerousGoodsFeEnum = { - FP61FL: 'FP <61 (FL)' as PermittedDangerousGoodsFeEnum, - AT: 'AT' as PermittedDangerousGoodsFeEnum, - Class51HydrogenPeroxideOX: 'Class 5.1 Hydrogen Peroxide (OX)' as PermittedDangerousGoodsFeEnum, - MEMU: 'MEMU' as PermittedDangerousGoodsFeEnum, - CarbonDisulphide: 'Carbon Disulphide' as PermittedDangerousGoodsFeEnum, - Hydrogen: 'Hydrogen' as PermittedDangerousGoodsFeEnum, - ExplosivesType2: 'Explosives (type 2)' as PermittedDangerousGoodsFeEnum, - ExplosivesType3: 'Explosives (type 3)' as PermittedDangerousGoodsFeEnum, - }; -} + export type MemosApplyFeEnum = '07/09 3mth leak ext'; + export const MemosApplyFeEnum = { + _07093mthLeakExt: '07/09 3mth leak ext' as MemosApplyFeEnum + }; + export type PermittedDangerousGoodsFeEnum = 'FP <61 (FL)' | 'AT' | 'Class 5.1 Hydrogen Peroxide (OX)' | 'MEMU' | 'Carbon Disulphide' | 'Hydrogen' | 'Explosives (type 2)' | 'Explosives (type 3)'; + export const PermittedDangerousGoodsFeEnum = { + FP61FL: 'FP <61 (FL)' as PermittedDangerousGoodsFeEnum, + AT: 'AT' as PermittedDangerousGoodsFeEnum, + Class51HydrogenPeroxideOX: 'Class 5.1 Hydrogen Peroxide (OX)' as PermittedDangerousGoodsFeEnum, + MEMU: 'MEMU' as PermittedDangerousGoodsFeEnum, + CarbonDisulphide: 'Carbon Disulphide' as PermittedDangerousGoodsFeEnum, + Hydrogen: 'Hydrogen' as PermittedDangerousGoodsFeEnum, + ExplosivesType2: 'Explosives (type 2)' as PermittedDangerousGoodsFeEnum, + ExplosivesType3: 'Explosives (type 3)' as PermittedDangerousGoodsFeEnum + }; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/metadataAdrDetailsAdditionalNotes.ts b/src/app/api/vehicle/model/metadataAdrDetailsAdditionalNotes.ts index 35eac3d117..9011d60033 100644 --- a/src/app/api/vehicle/model/metadataAdrDetailsAdditionalNotes.ts +++ b/src/app/api/vehicle/model/metadataAdrDetailsAdditionalNotes.ts @@ -9,22 +9,22 @@ * Do not edit the class manually. */ -export interface MetadataAdrDetailsAdditionalNotes { - guidanceNotesFe?: Array; - numberFe?: Array; +export interface MetadataAdrDetailsAdditionalNotes { + guidanceNotesFe?: Array; + numberFe?: Array; } export namespace MetadataAdrDetailsAdditionalNotes { - export type GuidanceNotesFeEnum = 'New certificate requested'; - export const GuidanceNotesFeEnum = { - NewCertificateRequested: 'New certificate requested' as GuidanceNotesFeEnum, - }; - export type NumberFeEnum = '1' | '1A' | '2' | '3' | 'V1B' | 'T1B'; - export const NumberFeEnum = { - _1: '1' as NumberFeEnum, - _1A: '1A' as NumberFeEnum, - _2: '2' as NumberFeEnum, - _3: '3' as NumberFeEnum, - V1B: 'V1B' as NumberFeEnum, - T1B: 'T1B' as NumberFeEnum, - }; -} + export type GuidanceNotesFeEnum = 'New certificate requested'; + export const GuidanceNotesFeEnum = { + NewCertificateRequested: 'New certificate requested' as GuidanceNotesFeEnum + }; + export type NumberFeEnum = '1' | '1A' | '2' | '3' | 'V1B' | 'T1B'; + export const NumberFeEnum = { + _1: '1' as NumberFeEnum, + _1A: '1A' as NumberFeEnum, + _2: '2' as NumberFeEnum, + _3: '3' as NumberFeEnum, + V1B: 'V1B' as NumberFeEnum, + T1B: 'T1B' as NumberFeEnum + }; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/metadataAdrDetailsTank.ts b/src/app/api/vehicle/model/metadataAdrDetailsTank.ts index 0154955b4e..04da799d47 100644 --- a/src/app/api/vehicle/model/metadataAdrDetailsTank.ts +++ b/src/app/api/vehicle/model/metadataAdrDetailsTank.ts @@ -10,6 +10,6 @@ */ import { MetadataAdrDetailsTankTankStatement } from './metadataAdrDetailsTankTankStatement'; -export interface MetadataAdrDetailsTank { - tankStatement?: MetadataAdrDetailsTankTankStatement; -} +export interface MetadataAdrDetailsTank { + tankStatement?: MetadataAdrDetailsTankTankStatement; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/metadataAdrDetailsTankTankStatement.ts b/src/app/api/vehicle/model/metadataAdrDetailsTankTankStatement.ts index efdb7d4ceb..1942aace09 100644 --- a/src/app/api/vehicle/model/metadataAdrDetailsTankTankStatement.ts +++ b/src/app/api/vehicle/model/metadataAdrDetailsTankTankStatement.ts @@ -9,17 +9,13 @@ * Do not edit the class manually. */ -export interface MetadataAdrDetailsTankTankStatement { - substancesPermittedFe?: Array; +export interface MetadataAdrDetailsTankTankStatement { + substancesPermittedFe?: Array; } export namespace MetadataAdrDetailsTankTankStatement { - export type SubstancesPermittedFeEnum = - | 'Substances permitted under the tank code and any special provisions specified in 9 may be carried' - | 'Substances (Class UN number and if necessary packing group and proper shipping name) may be carried'; - export const SubstancesPermittedFeEnum = { - PermittedUnderTheTankCodeAndAnySpecialProvisionsSpecifiedIn9MayBeCarried: - 'Substances permitted under the tank code and any special provisions specified in 9 may be carried' as SubstancesPermittedFeEnum, - ClassUNNumberAndIfNecessaryPackingGroupAndProperShippingNameMayBeCarried: - 'Substances (Class UN number and if necessary packing group and proper shipping name) may be carried' as SubstancesPermittedFeEnum, - }; -} + export type SubstancesPermittedFeEnum = 'Substances permitted under the tank code and any special provisions specified in 9 may be carried' | 'Substances (Class UN number and if necessary packing group and proper shipping name) may be carried'; + export const SubstancesPermittedFeEnum = { + PermittedUnderTheTankCodeAndAnySpecialProvisionsSpecifiedIn9MayBeCarried: 'Substances permitted under the tank code and any special provisions specified in 9 may be carried' as SubstancesPermittedFeEnum, + ClassUNNumberAndIfNecessaryPackingGroupAndProperShippingNameMayBeCarried: 'Substances (Class UN number and if necessary packing group and proper shipping name) may be carried' as SubstancesPermittedFeEnum + }; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/metadataAdrDetailsVehicleDetails.ts b/src/app/api/vehicle/model/metadataAdrDetailsVehicleDetails.ts index a16b6532a0..f61106d130 100644 --- a/src/app/api/vehicle/model/metadataAdrDetailsVehicleDetails.ts +++ b/src/app/api/vehicle/model/metadataAdrDetailsVehicleDetails.ts @@ -9,53 +9,32 @@ * Do not edit the class manually. */ -export interface MetadataAdrDetailsVehicleDetails { - typeFe?: Array; +export interface MetadataAdrDetailsVehicleDetails { + typeFe?: Array; } export namespace MetadataAdrDetailsVehicleDetails { - export type TypeFeEnum = - | 'Artic tractor' - | 'Rigid box body' - | 'Rigid sheeted load' - | 'Rigid tank' - | 'Rigid skeletal' - | 'Rigid battery' - | 'Full drawbar box body' - | 'Full drawbar sheeted load' - | 'Full drawbar tank' - | 'Full drawbar skeletal' - | 'Full drawbar battery' - | 'Centre axle box body' - | 'Centre axle sheeted load' - | 'Centre axle tank' - | 'Centre axle skeletal' - | 'Centre axle battery' - | 'Semi trailer box body' - | 'Semi trailer sheeted load' - | 'Semi trailer tank' - | 'Semi trailer skeletal' - | 'Semi trailer battery'; - export const TypeFeEnum = { - ArticTractor: 'Artic tractor' as TypeFeEnum, - RigidBoxBody: 'Rigid box body' as TypeFeEnum, - RigidSheetedLoad: 'Rigid sheeted load' as TypeFeEnum, - RigidTank: 'Rigid tank' as TypeFeEnum, - RigidSkeletal: 'Rigid skeletal' as TypeFeEnum, - RigidBattery: 'Rigid battery' as TypeFeEnum, - FullDrawbarBoxBody: 'Full drawbar box body' as TypeFeEnum, - FullDrawbarSheetedLoad: 'Full drawbar sheeted load' as TypeFeEnum, - FullDrawbarTank: 'Full drawbar tank' as TypeFeEnum, - FullDrawbarSkeletal: 'Full drawbar skeletal' as TypeFeEnum, - FullDrawbarBattery: 'Full drawbar battery' as TypeFeEnum, - CentreAxleBoxBody: 'Centre axle box body' as TypeFeEnum, - CentreAxleSheetedLoad: 'Centre axle sheeted load' as TypeFeEnum, - CentreAxleTank: 'Centre axle tank' as TypeFeEnum, - CentreAxleSkeletal: 'Centre axle skeletal' as TypeFeEnum, - CentreAxleBattery: 'Centre axle battery' as TypeFeEnum, - SemiTrailerBoxBody: 'Semi trailer box body' as TypeFeEnum, - SemiTrailerSheetedLoad: 'Semi trailer sheeted load' as TypeFeEnum, - SemiTrailerTank: 'Semi trailer tank' as TypeFeEnum, - SemiTrailerSkeletal: 'Semi trailer skeletal' as TypeFeEnum, - SemiTrailerBattery: 'Semi trailer battery' as TypeFeEnum, - }; -} + export type TypeFeEnum = 'Artic tractor' | 'Rigid box body' | 'Rigid sheeted load' | 'Rigid tank' | 'Rigid skeletal' | 'Rigid battery' | 'Full drawbar box body' | 'Full drawbar sheeted load' | 'Full drawbar tank' | 'Full drawbar skeletal' | 'Full drawbar battery' | 'Centre axle box body' | 'Centre axle sheeted load' | 'Centre axle tank' | 'Centre axle skeletal' | 'Centre axle battery' | 'Semi trailer box body' | 'Semi trailer sheeted load' | 'Semi trailer tank' | 'Semi trailer skeletal' | 'Semi trailer battery'; + export const TypeFeEnum = { + ArticTractor: 'Artic tractor' as TypeFeEnum, + RigidBoxBody: 'Rigid box body' as TypeFeEnum, + RigidSheetedLoad: 'Rigid sheeted load' as TypeFeEnum, + RigidTank: 'Rigid tank' as TypeFeEnum, + RigidSkeletal: 'Rigid skeletal' as TypeFeEnum, + RigidBattery: 'Rigid battery' as TypeFeEnum, + FullDrawbarBoxBody: 'Full drawbar box body' as TypeFeEnum, + FullDrawbarSheetedLoad: 'Full drawbar sheeted load' as TypeFeEnum, + FullDrawbarTank: 'Full drawbar tank' as TypeFeEnum, + FullDrawbarSkeletal: 'Full drawbar skeletal' as TypeFeEnum, + FullDrawbarBattery: 'Full drawbar battery' as TypeFeEnum, + CentreAxleBoxBody: 'Centre axle box body' as TypeFeEnum, + CentreAxleSheetedLoad: 'Centre axle sheeted load' as TypeFeEnum, + CentreAxleTank: 'Centre axle tank' as TypeFeEnum, + CentreAxleSkeletal: 'Centre axle skeletal' as TypeFeEnum, + CentreAxleBattery: 'Centre axle battery' as TypeFeEnum, + SemiTrailerBoxBody: 'Semi trailer box body' as TypeFeEnum, + SemiTrailerSheetedLoad: 'Semi trailer sheeted load' as TypeFeEnum, + SemiTrailerTank: 'Semi trailer tank' as TypeFeEnum, + SemiTrailerSkeletal: 'Semi trailer skeletal' as TypeFeEnum, + SemiTrailerBattery: 'Semi trailer battery' as TypeFeEnum + }; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/microfilm.ts b/src/app/api/vehicle/model/microfilm.ts index 71b84a2b1b..6dd73f446e 100644 --- a/src/app/api/vehicle/model/microfilm.ts +++ b/src/app/api/vehicle/model/microfilm.ts @@ -9,132 +9,77 @@ * Do not edit the class manually. */ -export interface Microfilm { - /** - * Used for all vehicle types - */ - microfilmDocumentType?: Microfilm.MicrofilmDocumentTypeEnum; - /** - * Used for all vehicle types - */ - microfilmRollNumber?: string; - /** - * Used for all vehicle types - */ - microfilmSerialNumber?: string; +export interface Microfilm { + /** + * Used for all vehicle types + */ + microfilmDocumentType?: Microfilm.MicrofilmDocumentTypeEnum; + /** + * Used for all vehicle types + */ + microfilmRollNumber?: string; + /** + * Used for all vehicle types + */ + microfilmSerialNumber?: string; } export namespace Microfilm { - export type MicrofilmDocumentTypeEnum = - | 'PSV Miscellaneous' - | 'AAT - Trailer Annual Test' - | 'AIV - HGV International App' - | 'COIF Modification' - | 'Trailer COC + Int Plate' - | 'RCT - Trailer Test Cert paid' - | 'HGV COC + Int Plate' - | 'PSV Carry/Auth' - | 'OMO Report' - | 'AIT - Trailer International App' - | 'IPV - HGV EEC Plate/Cert' - | 'XCV - HGV Test Cert free' - | 'AAV - HGV Annual Test' - | 'COIF Master' - | 'Tempo 100 Sp Ord' - | 'Deleted' - | 'PSV N/ALT' - | 'XPT - Tr Plating Cert paid' - | 'FFV - HGV First Test' - | 'Repl Vitesse 100' - | 'TCV - HGV Test Cert' - | 'ZZZ - Miscellaneous' - | 'Test Certificate' - | 'XCT - Trailer Test Cert free' - | 'C52 - COC and VTG52A' - | 'Tempo 100 Report' - | 'Main File Amendment' - | 'PSV Doc' - | 'PSV COC' - | 'PSV Repl COC' - | 'TAV - COC' - | 'NPT - Trailer Alteration' - | 'OMO Certificate' - | 'PSV Repl COIF' - | 'PSV Repl COF' - | 'COIF Application' - | 'XPV - HGV Plating Cert Free' - | 'TCT - Trailer Test Cert' - | 'Tempo 100 App' - | 'PSV Decision on N/ALT' - | 'Special Order PSV' - | 'NPV - HGV Alteration' - | 'No Description Found' - | 'Vitesse 100 Sp Ord' - | 'Brake Test Details' - | 'COIF Productional' - | 'RDT - Test Disc Paid' - | 'RCV - HGV Test Cert' - | 'FFT - Trailer First Test' - | 'IPT - Trailer EEC Plate/Cert' - | 'XDT - Test Disc Free' - | 'PRV - HGV Plating Cert paid' - | 'COF Cert' - | 'PRT - Tr Plating Cert paid' - | 'Tempo 100 Permit'; - export const MicrofilmDocumentTypeEnum = { - PSVMiscellaneous: 'PSV Miscellaneous' as MicrofilmDocumentTypeEnum, - AATTrailerAnnualTest: 'AAT - Trailer Annual Test' as MicrofilmDocumentTypeEnum, - AIVHGVInternationalApp: 'AIV - HGV International App' as MicrofilmDocumentTypeEnum, - COIFModification: 'COIF Modification' as MicrofilmDocumentTypeEnum, - TrailerCOCIntPlate: 'Trailer COC + Int Plate' as MicrofilmDocumentTypeEnum, - RCTTrailerTestCertPaid: 'RCT - Trailer Test Cert paid' as MicrofilmDocumentTypeEnum, - HGVCOCIntPlate: 'HGV COC + Int Plate' as MicrofilmDocumentTypeEnum, - PSVCarryAuth: 'PSV Carry/Auth' as MicrofilmDocumentTypeEnum, - OMOReport: 'OMO Report' as MicrofilmDocumentTypeEnum, - AITTrailerInternationalApp: 'AIT - Trailer International App' as MicrofilmDocumentTypeEnum, - IPVHGVEECPlateCert: 'IPV - HGV EEC Plate/Cert' as MicrofilmDocumentTypeEnum, - XCVHGVTestCertFree: 'XCV - HGV Test Cert free' as MicrofilmDocumentTypeEnum, - AAVHGVAnnualTest: 'AAV - HGV Annual Test' as MicrofilmDocumentTypeEnum, - COIFMaster: 'COIF Master' as MicrofilmDocumentTypeEnum, - Tempo100SpOrd: 'Tempo 100 Sp Ord' as MicrofilmDocumentTypeEnum, - Deleted: 'Deleted' as MicrofilmDocumentTypeEnum, - PSVNALT: 'PSV N/ALT' as MicrofilmDocumentTypeEnum, - XPTTrPlatingCertPaid: 'XPT - Tr Plating Cert paid' as MicrofilmDocumentTypeEnum, - FFVHGVFirstTest: 'FFV - HGV First Test' as MicrofilmDocumentTypeEnum, - ReplVitesse100: 'Repl Vitesse 100' as MicrofilmDocumentTypeEnum, - TCVHGVTestCert: 'TCV - HGV Test Cert' as MicrofilmDocumentTypeEnum, - ZZZMiscellaneous: 'ZZZ - Miscellaneous' as MicrofilmDocumentTypeEnum, - TestCertificate: 'Test Certificate' as MicrofilmDocumentTypeEnum, - XCTTrailerTestCertFree: 'XCT - Trailer Test Cert free' as MicrofilmDocumentTypeEnum, - C52COCAndVTG52A: 'C52 - COC and VTG52A' as MicrofilmDocumentTypeEnum, - Tempo100Report: 'Tempo 100 Report' as MicrofilmDocumentTypeEnum, - MainFileAmendment: 'Main File Amendment' as MicrofilmDocumentTypeEnum, - PSVDoc: 'PSV Doc' as MicrofilmDocumentTypeEnum, - PSVCOC: 'PSV COC' as MicrofilmDocumentTypeEnum, - PSVReplCOC: 'PSV Repl COC' as MicrofilmDocumentTypeEnum, - TAVCOC: 'TAV - COC' as MicrofilmDocumentTypeEnum, - NPTTrailerAlteration: 'NPT - Trailer Alteration' as MicrofilmDocumentTypeEnum, - OMOCertificate: 'OMO Certificate' as MicrofilmDocumentTypeEnum, - PSVReplCOIF: 'PSV Repl COIF' as MicrofilmDocumentTypeEnum, - PSVReplCOF: 'PSV Repl COF' as MicrofilmDocumentTypeEnum, - COIFApplication: 'COIF Application' as MicrofilmDocumentTypeEnum, - XPVHGVPlatingCertFree: 'XPV - HGV Plating Cert Free' as MicrofilmDocumentTypeEnum, - TCTTrailerTestCert: 'TCT - Trailer Test Cert' as MicrofilmDocumentTypeEnum, - Tempo100App: 'Tempo 100 App' as MicrofilmDocumentTypeEnum, - PSVDecisionOnNALT: 'PSV Decision on N/ALT' as MicrofilmDocumentTypeEnum, - SpecialOrderPSV: 'Special Order PSV' as MicrofilmDocumentTypeEnum, - NPVHGVAlteration: 'NPV - HGV Alteration' as MicrofilmDocumentTypeEnum, - NoDescriptionFound: 'No Description Found' as MicrofilmDocumentTypeEnum, - Vitesse100SpOrd: 'Vitesse 100 Sp Ord' as MicrofilmDocumentTypeEnum, - BrakeTestDetails: 'Brake Test Details' as MicrofilmDocumentTypeEnum, - COIFProductional: 'COIF Productional' as MicrofilmDocumentTypeEnum, - RDTTestDiscPaid: 'RDT - Test Disc Paid' as MicrofilmDocumentTypeEnum, - RCVHGVTestCert: 'RCV - HGV Test Cert' as MicrofilmDocumentTypeEnum, - FFTTrailerFirstTest: 'FFT - Trailer First Test' as MicrofilmDocumentTypeEnum, - IPTTrailerEECPlateCert: 'IPT - Trailer EEC Plate/Cert' as MicrofilmDocumentTypeEnum, - XDTTestDiscFree: 'XDT - Test Disc Free' as MicrofilmDocumentTypeEnum, - PRVHGVPlatingCertPaid: 'PRV - HGV Plating Cert paid' as MicrofilmDocumentTypeEnum, - COFCert: 'COF Cert' as MicrofilmDocumentTypeEnum, - PRTTrPlatingCertPaid: 'PRT - Tr Plating Cert paid' as MicrofilmDocumentTypeEnum, - Tempo100Permit: 'Tempo 100 Permit' as MicrofilmDocumentTypeEnum, - }; -} + export type MicrofilmDocumentTypeEnum = 'PSV Miscellaneous' | 'AAT - Trailer Annual Test' | 'AIV - HGV International App' | 'COIF Modification' | 'Trailer COC + Int Plate' | 'RCT - Trailer Test Cert paid' | 'HGV COC + Int Plate' | 'PSV Carry/Auth' | 'OMO Report' | 'AIT - Trailer International App' | 'IPV - HGV EEC Plate/Cert' | 'XCV - HGV Test Cert free' | 'AAV - HGV Annual Test' | 'COIF Master' | 'Tempo 100 Sp Ord' | 'Deleted' | 'PSV N/ALT' | 'XPT - Tr Plating Cert paid' | 'FFV - HGV First Test' | 'Repl Vitesse 100' | 'TCV - HGV Test Cert' | 'ZZZ - Miscellaneous' | 'Test Certificate' | 'XCT - Trailer Test Cert free' | 'C52 - COC and VTG52A' | 'Tempo 100 Report' | 'Main File Amendment' | 'PSV Doc' | 'PSV COC' | 'PSV Repl COC' | 'TAV - COC' | 'NPT - Trailer Alteration' | 'OMO Certificate' | 'PSV Repl COIF' | 'PSV Repl COF' | 'COIF Application' | 'XPV - HGV Plating Cert Free' | 'TCT - Trailer Test Cert' | 'Tempo 100 App' | 'PSV Decision on N/ALT' | 'Special Order PSV' | 'NPV - HGV Alteration' | 'No Description Found' | 'Vitesse 100 Sp Ord' | 'Brake Test Details' | 'COIF Productional' | 'RDT - Test Disc Paid' | 'RCV - HGV Test Cert' | 'FFT - Trailer First Test' | 'IPT - Trailer EEC Plate/Cert' | 'XDT - Test Disc Free' | 'PRV - HGV Plating Cert paid' | 'COF Cert' | 'PRT - Tr Plating Cert paid' | 'Tempo 100 Permit'; + export const MicrofilmDocumentTypeEnum = { + PSVMiscellaneous: 'PSV Miscellaneous' as MicrofilmDocumentTypeEnum, + AATTrailerAnnualTest: 'AAT - Trailer Annual Test' as MicrofilmDocumentTypeEnum, + AIVHGVInternationalApp: 'AIV - HGV International App' as MicrofilmDocumentTypeEnum, + COIFModification: 'COIF Modification' as MicrofilmDocumentTypeEnum, + TrailerCOCIntPlate: 'Trailer COC + Int Plate' as MicrofilmDocumentTypeEnum, + RCTTrailerTestCertPaid: 'RCT - Trailer Test Cert paid' as MicrofilmDocumentTypeEnum, + HGVCOCIntPlate: 'HGV COC + Int Plate' as MicrofilmDocumentTypeEnum, + PSVCarryAuth: 'PSV Carry/Auth' as MicrofilmDocumentTypeEnum, + OMOReport: 'OMO Report' as MicrofilmDocumentTypeEnum, + AITTrailerInternationalApp: 'AIT - Trailer International App' as MicrofilmDocumentTypeEnum, + IPVHGVEECPlateCert: 'IPV - HGV EEC Plate/Cert' as MicrofilmDocumentTypeEnum, + XCVHGVTestCertFree: 'XCV - HGV Test Cert free' as MicrofilmDocumentTypeEnum, + AAVHGVAnnualTest: 'AAV - HGV Annual Test' as MicrofilmDocumentTypeEnum, + COIFMaster: 'COIF Master' as MicrofilmDocumentTypeEnum, + Tempo100SpOrd: 'Tempo 100 Sp Ord' as MicrofilmDocumentTypeEnum, + Deleted: 'Deleted' as MicrofilmDocumentTypeEnum, + PSVNALT: 'PSV N/ALT' as MicrofilmDocumentTypeEnum, + XPTTrPlatingCertPaid: 'XPT - Tr Plating Cert paid' as MicrofilmDocumentTypeEnum, + FFVHGVFirstTest: 'FFV - HGV First Test' as MicrofilmDocumentTypeEnum, + ReplVitesse100: 'Repl Vitesse 100' as MicrofilmDocumentTypeEnum, + TCVHGVTestCert: 'TCV - HGV Test Cert' as MicrofilmDocumentTypeEnum, + ZZZMiscellaneous: 'ZZZ - Miscellaneous' as MicrofilmDocumentTypeEnum, + TestCertificate: 'Test Certificate' as MicrofilmDocumentTypeEnum, + XCTTrailerTestCertFree: 'XCT - Trailer Test Cert free' as MicrofilmDocumentTypeEnum, + C52COCAndVTG52A: 'C52 - COC and VTG52A' as MicrofilmDocumentTypeEnum, + Tempo100Report: 'Tempo 100 Report' as MicrofilmDocumentTypeEnum, + MainFileAmendment: 'Main File Amendment' as MicrofilmDocumentTypeEnum, + PSVDoc: 'PSV Doc' as MicrofilmDocumentTypeEnum, + PSVCOC: 'PSV COC' as MicrofilmDocumentTypeEnum, + PSVReplCOC: 'PSV Repl COC' as MicrofilmDocumentTypeEnum, + TAVCOC: 'TAV - COC' as MicrofilmDocumentTypeEnum, + NPTTrailerAlteration: 'NPT - Trailer Alteration' as MicrofilmDocumentTypeEnum, + OMOCertificate: 'OMO Certificate' as MicrofilmDocumentTypeEnum, + PSVReplCOIF: 'PSV Repl COIF' as MicrofilmDocumentTypeEnum, + PSVReplCOF: 'PSV Repl COF' as MicrofilmDocumentTypeEnum, + COIFApplication: 'COIF Application' as MicrofilmDocumentTypeEnum, + XPVHGVPlatingCertFree: 'XPV - HGV Plating Cert Free' as MicrofilmDocumentTypeEnum, + TCTTrailerTestCert: 'TCT - Trailer Test Cert' as MicrofilmDocumentTypeEnum, + Tempo100App: 'Tempo 100 App' as MicrofilmDocumentTypeEnum, + PSVDecisionOnNALT: 'PSV Decision on N/ALT' as MicrofilmDocumentTypeEnum, + SpecialOrderPSV: 'Special Order PSV' as MicrofilmDocumentTypeEnum, + NPVHGVAlteration: 'NPV - HGV Alteration' as MicrofilmDocumentTypeEnum, + NoDescriptionFound: 'No Description Found' as MicrofilmDocumentTypeEnum, + Vitesse100SpOrd: 'Vitesse 100 Sp Ord' as MicrofilmDocumentTypeEnum, + BrakeTestDetails: 'Brake Test Details' as MicrofilmDocumentTypeEnum, + COIFProductional: 'COIF Productional' as MicrofilmDocumentTypeEnum, + RDTTestDiscPaid: 'RDT - Test Disc Paid' as MicrofilmDocumentTypeEnum, + RCVHGVTestCert: 'RCV - HGV Test Cert' as MicrofilmDocumentTypeEnum, + FFTTrailerFirstTest: 'FFT - Trailer First Test' as MicrofilmDocumentTypeEnum, + IPTTrailerEECPlateCert: 'IPT - Trailer EEC Plate/Cert' as MicrofilmDocumentTypeEnum, + XDTTestDiscFree: 'XDT - Test Disc Free' as MicrofilmDocumentTypeEnum, + PRVHGVPlatingCertPaid: 'PRV - HGV Plating Cert paid' as MicrofilmDocumentTypeEnum, + COFCert: 'COF Cert' as MicrofilmDocumentTypeEnum, + PRTTrPlatingCertPaid: 'PRT - Tr Plating Cert paid' as MicrofilmDocumentTypeEnum, + Tempo100Permit: 'Tempo 100 Permit' as MicrofilmDocumentTypeEnum + }; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/plates.ts b/src/app/api/vehicle/model/plates.ts index 5ead075aec..6fbbd8d1d0 100644 --- a/src/app/api/vehicle/model/plates.ts +++ b/src/app/api/vehicle/model/plates.ts @@ -10,4 +10,5 @@ */ import { PlatesInner } from './platesInner'; -export interface Plates extends Array {} +export interface Plates extends Array { +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/platesInner.ts b/src/app/api/vehicle/model/platesInner.ts index 3a0ba29d66..4f4c7f4ffc 100644 --- a/src/app/api/vehicle/model/platesInner.ts +++ b/src/app/api/vehicle/model/platesInner.ts @@ -9,42 +9,36 @@ * Do not edit the class manually. */ -export interface PlatesInner { - /** - * Used for all vehicle types - */ - plateSerialNumber?: string; - /** - * Used for all vehicle types - */ - plateIssueDate?: string; - /** - * Used for all vehicle types - */ - plateReasonForIssue?: PlatesInner.PlateReasonForIssueEnum; - /** - * Used for all vehicle types - */ - plateIssuer?: string; - /** - * Used for all vehicle types - */ - toEmailAddress?: string; +export interface PlatesInner { + /** + * Used for all vehicle types + */ + plateSerialNumber?: string; + /** + * Used for all vehicle types + */ + plateIssueDate?: string; + /** + * Used for all vehicle types + */ + plateReasonForIssue?: PlatesInner.PlateReasonForIssueEnum; + /** + * Used for all vehicle types + */ + plateIssuer?: string; + /** + * Used for all vehicle types + */ + toEmailAddress?: string; } export namespace PlatesInner { - export type PlateReasonForIssueEnum = - | 'Free replacement' - | 'Replacement' - | 'Destroyed' - | 'Provisional' - | 'Original' - | 'Manual'; - export const PlateReasonForIssueEnum = { - FreeReplacement: 'Free replacement' as PlateReasonForIssueEnum, - Replacement: 'Replacement' as PlateReasonForIssueEnum, - Destroyed: 'Destroyed' as PlateReasonForIssueEnum, - Provisional: 'Provisional' as PlateReasonForIssueEnum, - Original: 'Original' as PlateReasonForIssueEnum, - Manual: 'Manual' as PlateReasonForIssueEnum, - }; -} + export type PlateReasonForIssueEnum = 'Free replacement' | 'Replacement' | 'Destroyed' | 'Provisional' | 'Original' | 'Manual'; + export const PlateReasonForIssueEnum = { + FreeReplacement: 'Free replacement' as PlateReasonForIssueEnum, + Replacement: 'Replacement' as PlateReasonForIssueEnum, + Destroyed: 'Destroyed' as PlateReasonForIssueEnum, + Provisional: 'Provisional' as PlateReasonForIssueEnum, + Original: 'Original' as PlateReasonForIssueEnum, + Manual: 'Manual' as PlateReasonForIssueEnum + }; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/purchaserDetails.ts b/src/app/api/vehicle/model/purchaserDetails.ts index 107fc4238d..89b0d419e5 100644 --- a/src/app/api/vehicle/model/purchaserDetails.ts +++ b/src/app/api/vehicle/model/purchaserDetails.ts @@ -12,15 +12,15 @@ /** * Used for TRL only */ -export interface PurchaserDetails { - name?: string; - address1?: string; - address2?: string; - postTown?: string; - address3?: string; - postCode?: string; - emailAddress?: string; - telephoneNumber?: string; - faxNumber?: string; - purchaserNotes?: string; -} +export interface PurchaserDetails { + name?: string; + address1?: string; + address2?: string; + postTown?: string; + address3?: string; + postCode?: string; + emailAddress?: string; + telephoneNumber?: string; + faxNumber?: string; + purchaserNotes?: string; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/techRecord.ts b/src/app/api/vehicle/model/techRecord.ts index 9e7f2d032d..2d2fc48f52 100644 --- a/src/app/api/vehicle/model/techRecord.ts +++ b/src/app/api/vehicle/model/techRecord.ts @@ -24,496 +24,449 @@ import { TechRecordDimensions } from './techRecordDimensions'; import { TechRecordVehicleClass } from './techRecordVehicleClass'; export interface TechRecord { - /** - * Defines the level of completeness for a tech record. If it is set to \"skeleton\" then it means the vehicle does not meet the minimum requirements to be tested. If it is \"testable\" it means the vehicle meets the minimum requirements to be tested but is not complete from a business perspective. If \"complete\" then the vehicle it is complete form a business perspective also. - */ - recordCompleteness?: string; - /** - * Used for all vehicle types - */ - createdAt?: Date; - /** - * Used for all vehicle types - */ - lastUpdatedAt?: Date; - /** - * Used only for HGV and TRL - */ - make?: string; - /** - * Used only for HGV and TRL - */ - model?: string; - /** - * Used for all vehicle types - */ - functionCode?: string; - /** - * Used for HGV and PSV - */ - fuelPropulsionSystem?: TechRecord.FuelPropulsionSystemEnum; - /** - * Used only for HGV - */ - offRoad?: boolean; - /** - * Used for motorcycles to derive the test codes for specialist tests. Used for HGV and PSV. - */ - numberOfWheelsDriven?: number; - /** - * Used for all vehicle types. Optional for car, lgv and motorcycle. - */ - euVehicleCategory?: TechRecord.EuVehicleCategoryEnum; - /** - * Used only for HGV and PSV - */ - emissionsLimit?: number; - /** - * Used for all vehicle types - */ - departmentalVehicleMarker?: boolean; - authIntoService?: AuthIntoService; - lettersOfAuth?: LettersOfAuth; - /** - * Used for all vehicle types - */ - alterationMarker?: boolean; - /** - * Used for all vehicle types - */ - approvalType?: TechRecord.ApprovalTypeEnum; - /** - * Used for all vehicle types - */ - approvalTypeNumber?: string; - /** - * Used for all vehicle types - */ - variantNumber?: string; - /** - * Used for all vehicle types - */ - variantVersionNumber?: string; - /** - * Used only for HGV and TRL - */ - grossEecWeight?: number; - /** - * Used only for HGV - */ - trainEecWeight?: number; - /** - * Used only for HGV - */ - maxTrainEecWeight?: number; - applicantDetails?: ApplicantDetailsProperties; - purchaserDetails?: PurchaserDetails; - manufacturerDetails?: ManufacturerDetails; - microfilm?: Microfilm; - plates?: Plates; - /** - * Used only for PSV - */ - chassisMake?: string; - /** - * Used only for PSV - */ - chassisModel?: string; - /** - * Used only for PSV - */ - bodyMake?: string; - /** - * Used only for PSV - */ - bodyModel?: string; - /** - * Used only for PSV - */ - modelLiteral?: string; - bodyType?: TechRecordBodyType; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - manufactureYear?: number; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - regnDate?: string; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - firstUseDate?: string; - /** - * Used only for PSV - */ - coifDate?: string; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - ntaNumber?: string; - /** - * Used only for PSV - */ - coifSerialNumber?: string; - /** - * Used only for PSV - */ - coifCertifierName?: string; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - conversionRefNo?: string; - /** - * Used only for PSV - */ - seatsLowerDeck?: number; - /** - * Used only for PSV - */ - seatsUpperDeck?: number; - /** - * Used only for PSV - */ - standingCapacity?: number; - /** - * Used only for PSV - */ - speedRestriction?: number; - /** - * Used only for PSV and HGV - */ - speedLimiterMrk?: boolean; - /** - * Used only for PSV and HGV - */ - tachoExemptMrk?: boolean; - /** - * Used only for PSV - */ - dispensations?: string; - /** - * Used for PSV, car, lgv and motorcycle - */ - remarks?: string; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv and motorcycle - */ - reasonForCreation?: string; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - statusCode?: TechRecord.StatusCodeEnum; - /** - * Used only for PSV - */ - unladenWeight?: number; - /** - * Used only for PSV - */ - grossKerbWeight?: number; - /** - * Used only for PSV - */ - grossLadenWeight?: number; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - grossGbWeight?: number; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - grossDesignWeight?: number; - /** - * Used only for HGV - */ - trainGbWeight?: number; - /** - * Used only for HGV and PSV - */ - trainDesignWeight?: number; - /** - * Used only for HGV and PSV. Optional for PSV - */ - maxTrainGbWeight?: number; - /** - * Used only for HGV - */ - maxTrainDesignWeight?: number; - /** - * Used only for TRL - */ - maxLoadOnCoupling?: number; - frameDescription?: TechRecord.FrameDescriptionEnum; - /** - * Used only for HGV and TRL - */ - tyreUseCode?: string; - /** - * Used only for HGV and TRL - */ - roadFriendly?: boolean; - /** - * Used only for HGV - */ - drawbarCouplingFitted?: boolean; - /** - * Used for HGV and PSV - */ - euroStandard?: string; - /** - * Used only for TRL - */ - suspensionType?: string; - /** - * Used only for TRL - */ - couplingType?: string; - dimensions?: TechRecordDimensions; - /** - * Used only for HGV - */ - frontAxleTo5thWheelMin?: number; - /** - * Used only for HGV - */ - frontAxleTo5thWheelMax?: number; - /** - * Used only for HGV. Optional for HGV - */ - frontVehicleTo5thWheelCouplingMin?: number; - /** - * Used only for HGV. Optional for HGV - */ - frontVehicleTo5thWheelCouplingMax?: number; - /** - * Used for all vehicle types. Optional for PSV - */ - frontAxleToRearAxle?: number; - /** - * Used only for TRL - */ - rearAxleToRearTrl?: number; - /** - * Used only for TRL - */ - couplingCenterToRearAxleMin?: number; - /** - * Used only for TRL - */ - couplingCenterToRearAxleMax?: number; - /** - * Used only for TRL - */ - couplingCenterToRearTrlMin?: number; - /** - * Used only for TRL - */ - couplingCenterToRearTrlMax?: number; - /** - * Used only for TRL - */ - centreOfRearmostAxleToRearOfTrl?: number; - /** - * Used only for HGV and TRL - */ - notes?: string; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - noOfAxles?: number; - /** - * Used only for PSV - */ - brakeCode?: string; - adrDetails?: AdrDetails; - /** - * This field gets populated with the Microsoft AD 'name', when a tech record gets created - */ - createdByName?: string; - /** - * This attribute gets populated with the Microsoft AD 'oid', when a tech record gets created - */ - createdById?: string; - /** - * This field gets populated with the Microsoft AD 'name', when a tech record gets updated - */ - lastUpdatedByName?: string; - /** - * This attribute gets populated with the Microsoft AD 'oid', when a tech record gets updated - */ - lastUpdatedById?: string; - /** - * set updateType to adrUpdate on the archived tech record, when a tech record is archived - */ - updateType?: TechRecord.UpdateTypeEnum; - vehicleClass?: TechRecordVehicleClass; - /** - * Used for car and lgv. - */ - vehicleSubclass?: Array; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - vehicleType?: TechRecord.VehicleTypeEnum; - /** - * Used only for PSV - */ - vehicleSize?: TechRecord.VehicleSizeEnum; - /** - * Used only for PSV - */ - numberOfSeatbelts?: string; - /** - * Used only for PSV - */ - seatbeltInstallationApprovalDate?: string; - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - vehicleConfiguration?: TechRecord.VehicleConfigurationEnum; - brakes?: Brakes; - axles?: Axles; - dda?: Dda; + /** + * Defines the level of completeness for a tech record. If it is set to \"skeleton\" then it means the vehicle does not meet the minimum requirements to be tested. If it is \"testable\" it means the vehicle meets the minimum requirements to be tested but is not complete from a business perspective. If \"complete\" then the vehicle it is complete form a business perspective also. + */ + recordCompleteness?: string; + /** + * Used for all vehicle types + */ + createdAt?: Date; + /** + * Used for all vehicle types + */ + lastUpdatedAt?: Date; + /** + * Used only for HGV and TRL + */ + make?: string; + /** + * Used only for HGV and TRL + */ + model?: string; + /** + * Used for all vehicle types + */ + functionCode?: string; + /** + * Used for HGV and PSV + */ + fuelPropulsionSystem?: TechRecord.FuelPropulsionSystemEnum; + /** + * Used only for HGV + */ + offRoad?: boolean; + /** + * Used for motorcycles to derive the test codes for specialist tests. Used for HGV and PSV. + */ + numberOfWheelsDriven?: number; + /** + * Used for all vehicle types. Optional for car, lgv and motorcycle. + */ + euVehicleCategory?: TechRecord.EuVehicleCategoryEnum; + /** + * Used only for HGV and PSV + */ + emissionsLimit?: number; + /** + * Used for all vehicle types + */ + departmentalVehicleMarker?: boolean; + authIntoService?: AuthIntoService; + lettersOfAuth?: LettersOfAuth; + /** + * Used for all vehicle types + */ + alterationMarker?: boolean; + /** + * Used for all vehicle types + */ + approvalType?: TechRecord.ApprovalTypeEnum; + /** + * Used for all vehicle types + */ + approvalTypeNumber?: string; + /** + * Used for all vehicle types + */ + variantNumber?: string; + /** + * Used for all vehicle types + */ + variantVersionNumber?: string; + /** + * Used only for HGV and TRL + */ + grossEecWeight?: number; + /** + * Used only for HGV + */ + trainEecWeight?: number; + /** + * Used only for HGV + */ + maxTrainEecWeight?: number; + applicantDetails?: ApplicantDetailsProperties; + purchaserDetails?: PurchaserDetails; + manufacturerDetails?: ManufacturerDetails; + microfilm?: Microfilm; + plates?: Plates; + /** + * Used only for PSV + */ + chassisMake?: string; + /** + * Used only for PSV + */ + chassisModel?: string; + /** + * Used only for PSV + */ + bodyMake?: string; + /** + * Used only for PSV + */ + bodyModel?: string; + /** + * Used only for PSV + */ + modelLiteral?: string; + bodyType?: TechRecordBodyType; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + manufactureYear?: number; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + regnDate?: string; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + firstUseDate?: string; + /** + * Used only for PSV + */ + coifDate?: string; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + ntaNumber?: string; + /** + * Used only for PSV + */ + coifSerialNumber?: string; + /** + * Used only for PSV + */ + coifCertifierName?: string; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + conversionRefNo?: string; + /** + * Used only for PSV + */ + seatsLowerDeck?: number; + /** + * Used only for PSV + */ + seatsUpperDeck?: number; + /** + * Used only for PSV + */ + standingCapacity?: number; + /** + * Used only for PSV + */ + speedRestriction?: number; + /** + * Used only for PSV and HGV + */ + speedLimiterMrk?: boolean; + /** + * Used only for PSV and HGV + */ + tachoExemptMrk?: boolean; + /** + * Used only for PSV + */ + dispensations?: string; + /** + * Used for PSV, car, lgv and motorcycle + */ + remarks?: string; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv and motorcycle + */ + reasonForCreation?: string; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + statusCode?: TechRecord.StatusCodeEnum; + /** + * Used only for PSV + */ + unladenWeight?: number; + /** + * Used only for PSV + */ + grossKerbWeight?: number; + /** + * Used only for PSV + */ + grossLadenWeight?: number; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + grossGbWeight?: number; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + grossDesignWeight?: number; + /** + * Used only for HGV + */ + trainGbWeight?: number; + /** + * Used only for HGV and PSV + */ + trainDesignWeight?: number; + /** + * Used only for HGV and PSV. Optional for PSV + */ + maxTrainGbWeight?: number; + /** + * Used only for HGV + */ + maxTrainDesignWeight?: number; + /** + * Used only for TRL + */ + maxLoadOnCoupling?: number; + frameDescription?: TechRecord.FrameDescriptionEnum; + /** + * Used only for HGV and TRL + */ + tyreUseCode?: string; + /** + * Used only for HGV and TRL + */ + roadFriendly?: boolean; + /** + * Used only for HGV + */ + drawbarCouplingFitted?: boolean; + /** + * Used for HGV and PSV + */ + euroStandard?: string; + /** + * Used only for TRL + */ + suspensionType?: string; + /** + * Used only for TRL + */ + couplingType?: string; + dimensions?: TechRecordDimensions; + /** + * Used only for HGV + */ + frontAxleTo5thWheelMin?: number; + /** + * Used only for HGV + */ + frontAxleTo5thWheelMax?: number; + /** + * Used only for HGV. Optional for HGV + */ + frontVehicleTo5thWheelCouplingMin?: number; + /** + * Used only for HGV. Optional for HGV + */ + frontVehicleTo5thWheelCouplingMax?: number; + /** + * Used for all vehicle types. Optional for PSV + */ + frontAxleToRearAxle?: number; + /** + * Used only for TRL + */ + rearAxleToRearTrl?: number; + /** + * Used only for TRL + */ + couplingCenterToRearAxleMin?: number; + /** + * Used only for TRL + */ + couplingCenterToRearAxleMax?: number; + /** + * Used only for TRL + */ + couplingCenterToRearTrlMin?: number; + /** + * Used only for TRL + */ + couplingCenterToRearTrlMax?: number; + /** + * Used only for TRL + */ + centreOfRearmostAxleToRearOfTrl?: number; + /** + * Used only for HGV and TRL + */ + notes?: string; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + noOfAxles?: number; + /** + * Used only for PSV + */ + brakeCode?: string; + adrDetails?: AdrDetails; + /** + * This field gets populated with the Microsoft AD 'name', when a tech record gets created + */ + createdByName?: string; + /** + * This attribute gets populated with the Microsoft AD 'oid', when a tech record gets created + */ + createdById?: string; + /** + * This field gets populated with the Microsoft AD 'name', when a tech record gets updated + */ + lastUpdatedByName?: string; + /** + * This attribute gets populated with the Microsoft AD 'oid', when a tech record gets updated + */ + lastUpdatedById?: string; + /** + * set updateType to adrUpdate on the archived tech record, when a tech record is archived + */ + updateType?: TechRecord.UpdateTypeEnum; + vehicleClass?: TechRecordVehicleClass; + /** + * Used for car and lgv. + */ + vehicleSubclass?: Array; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + vehicleType?: TechRecord.VehicleTypeEnum; + /** + * Used only for PSV + */ + vehicleSize?: TechRecord.VehicleSizeEnum; + /** + * Used only for PSV + */ + numberOfSeatbelts?: string; + /** + * Used only for PSV + */ + seatbeltInstallationApprovalDate?: string; + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + vehicleConfiguration?: TechRecord.VehicleConfigurationEnum; + brakes?: Brakes; + axles?: Axles; + dda?: Dda; } export namespace TechRecord { - export type FuelPropulsionSystemEnum = - | 'DieselPetrol' - | 'Diesel' - | 'Petrol' - | 'Hybrid' - | 'Electric' - | 'CNG' - | 'Fuel cell' - | 'LNG' - | 'Other'; - export const FuelPropulsionSystemEnum = { - DieselPetrol: 'DieselPetrol' as FuelPropulsionSystemEnum, - Diesel: 'Diesel' as FuelPropulsionSystemEnum, - Petrol: 'Petrol' as FuelPropulsionSystemEnum, - Hybrid: 'Hybrid' as FuelPropulsionSystemEnum, - Electric: 'Electric' as FuelPropulsionSystemEnum, - CNG: 'CNG' as FuelPropulsionSystemEnum, - FuelCell: 'Fuel cell' as FuelPropulsionSystemEnum, - LNG: 'LNG' as FuelPropulsionSystemEnum, - Other: 'Other' as FuelPropulsionSystemEnum, - }; - export type EuVehicleCategoryEnum = - | 'm1' - | 'm2' - | 'm3' - | 'n1' - | 'n2' - | 'n3' - | 'o1' - | 'o2' - | 'o3' - | 'o4' - | 'l1e-a' - | 'l1e' - | 'l2e' - | 'l3e' - | 'l4e' - | 'l5e' - | 'l6e' - | 'l7e'; - export const EuVehicleCategoryEnum = { - M1: 'm1' as EuVehicleCategoryEnum, - M2: 'm2' as EuVehicleCategoryEnum, - M3: 'm3' as EuVehicleCategoryEnum, - N1: 'n1' as EuVehicleCategoryEnum, - N2: 'n2' as EuVehicleCategoryEnum, - N3: 'n3' as EuVehicleCategoryEnum, - O1: 'o1' as EuVehicleCategoryEnum, - O2: 'o2' as EuVehicleCategoryEnum, - O3: 'o3' as EuVehicleCategoryEnum, - O4: 'o4' as EuVehicleCategoryEnum, - L1eA: 'l1e-a' as EuVehicleCategoryEnum, - L1e: 'l1e' as EuVehicleCategoryEnum, - L2e: 'l2e' as EuVehicleCategoryEnum, - L3e: 'l3e' as EuVehicleCategoryEnum, - L4e: 'l4e' as EuVehicleCategoryEnum, - L5e: 'l5e' as EuVehicleCategoryEnum, - L6e: 'l6e' as EuVehicleCategoryEnum, - L7e: 'l7e' as EuVehicleCategoryEnum, - }; - export type ApprovalTypeEnum = 'NTA' | 'ECTA' | 'IVA' | 'NSSTA' | 'ECSSTA'; - export const ApprovalTypeEnum = { - NTA: 'NTA' as ApprovalTypeEnum, - ECTA: 'ECTA' as ApprovalTypeEnum, - IVA: 'IVA' as ApprovalTypeEnum, - NSSTA: 'NSSTA' as ApprovalTypeEnum, - ECSSTA: 'ECSSTA' as ApprovalTypeEnum, - }; - export type StatusCodeEnum = 'archived' | 'current' | 'provisional'; - export const StatusCodeEnum = { - Archived: 'archived' as StatusCodeEnum, - Current: 'current' as StatusCodeEnum, - Provisional: 'provisional' as StatusCodeEnum, - }; - export type FrameDescriptionEnum = - | 'Channel section' - | 'Space frame' - | 'I section' - | 'Tubular' - | 'Frame section' - | 'Other' - | 'integral' - | 'Box section' - | 'U section'; - export const FrameDescriptionEnum = { - ChannelSection: 'Channel section' as FrameDescriptionEnum, - SpaceFrame: 'Space frame' as FrameDescriptionEnum, - ISection: 'I section' as FrameDescriptionEnum, - Tubular: 'Tubular' as FrameDescriptionEnum, - FrameSection: 'Frame section' as FrameDescriptionEnum, - Other: 'Other' as FrameDescriptionEnum, - Integral: 'integral' as FrameDescriptionEnum, - BoxSection: 'Box section' as FrameDescriptionEnum, - USection: 'U section' as FrameDescriptionEnum, - }; - export type UpdateTypeEnum = 'adrUpdate' | 'techRecordUpdate'; - export const UpdateTypeEnum = { - AdrUpdate: 'adrUpdate' as UpdateTypeEnum, - TechRecordUpdate: 'techRecordUpdate' as UpdateTypeEnum, - }; - export type VehicleTypeEnum = 'psv' | 'hgv' | 'trl' | 'car' | 'lgv' | 'motorcycle'; - export const VehicleTypeEnum = { - Psv: 'psv' as VehicleTypeEnum, - Hgv: 'hgv' as VehicleTypeEnum, - Trl: 'trl' as VehicleTypeEnum, - Car: 'car' as VehicleTypeEnum, - Lgv: 'lgv' as VehicleTypeEnum, - Motorcycle: 'motorcycle' as VehicleTypeEnum, - }; - export type VehicleSizeEnum = 'small' | 'large'; - export const VehicleSizeEnum = { - Small: 'small' as VehicleSizeEnum, - Large: 'large' as VehicleSizeEnum, - }; - export type VehicleConfigurationEnum = - | 'rigid' - | 'articulated' - | 'centre axle drawbar' - | 'semi-car transporter' - | 'semi-trailer' - | 'low loader' - | 'other' - | 'drawbar' - | 'four-in-line' - | 'dolly' - | 'full drawbar'; - export const VehicleConfigurationEnum = { - Rigid: 'rigid' as VehicleConfigurationEnum, - Articulated: 'articulated' as VehicleConfigurationEnum, - CentreAxleDrawbar: 'centre axle drawbar' as VehicleConfigurationEnum, - SemiCarTransporter: 'semi-car transporter' as VehicleConfigurationEnum, - SemiTrailer: 'semi-trailer' as VehicleConfigurationEnum, - LowLoader: 'low loader' as VehicleConfigurationEnum, - Other: 'other' as VehicleConfigurationEnum, - Drawbar: 'drawbar' as VehicleConfigurationEnum, - FourInLine: 'four-in-line' as VehicleConfigurationEnum, - Dolly: 'dolly' as VehicleConfigurationEnum, - FullDrawbar: 'full drawbar' as VehicleConfigurationEnum, - }; + export type FuelPropulsionSystemEnum = 'DieselPetrol' | 'Diesel' | 'Petrol' | 'Hybrid' | 'Electric' | 'CNG' | 'Fuel cell' | 'LNG' | 'Other'; + export const FuelPropulsionSystemEnum = { + DieselPetrol: "DieselPetrol" as FuelPropulsionSystemEnum, + Diesel: 'Diesel' as FuelPropulsionSystemEnum, + Petrol: 'Petrol' as FuelPropulsionSystemEnum, + Hybrid: 'Hybrid' as FuelPropulsionSystemEnum, + Electric: 'Electric' as FuelPropulsionSystemEnum, + CNG: 'CNG' as FuelPropulsionSystemEnum, + FuelCell: 'Fuel cell' as FuelPropulsionSystemEnum, + LNG: 'LNG' as FuelPropulsionSystemEnum, + Other: 'Other' as FuelPropulsionSystemEnum + }; + export type EuVehicleCategoryEnum = 'm1' | 'm2' | 'm3' | 'n1' | 'n2' | 'n3' | 'o1' | 'o2' | 'o3' | 'o4' | 'l1e-a' | 'l1e' | 'l2e' | 'l3e' | 'l4e' | 'l5e' | 'l6e' | 'l7e'; + export const EuVehicleCategoryEnum = { + M1: 'm1' as EuVehicleCategoryEnum, + M2: 'm2' as EuVehicleCategoryEnum, + M3: 'm3' as EuVehicleCategoryEnum, + N1: 'n1' as EuVehicleCategoryEnum, + N2: 'n2' as EuVehicleCategoryEnum, + N3: 'n3' as EuVehicleCategoryEnum, + O1: 'o1' as EuVehicleCategoryEnum, + O2: 'o2' as EuVehicleCategoryEnum, + O3: 'o3' as EuVehicleCategoryEnum, + O4: 'o4' as EuVehicleCategoryEnum, + L1eA: 'l1e-a' as EuVehicleCategoryEnum, + L1e: 'l1e' as EuVehicleCategoryEnum, + L2e: 'l2e' as EuVehicleCategoryEnum, + L3e: 'l3e' as EuVehicleCategoryEnum, + L4e: 'l4e' as EuVehicleCategoryEnum, + L5e: 'l5e' as EuVehicleCategoryEnum, + L6e: 'l6e' as EuVehicleCategoryEnum, + L7e: 'l7e' as EuVehicleCategoryEnum + }; + export type ApprovalTypeEnum = 'NTA' | 'ECTA' | 'IVA' | 'NSSTA' | 'ECSSTA'; + export const ApprovalTypeEnum = { + NTA: 'NTA' as ApprovalTypeEnum, + ECTA: 'ECTA' as ApprovalTypeEnum, + IVA: 'IVA' as ApprovalTypeEnum, + NSSTA: 'NSSTA' as ApprovalTypeEnum, + ECSSTA: 'ECSSTA' as ApprovalTypeEnum + }; + export type StatusCodeEnum = 'archived' | 'current' | 'provisional'; + export const StatusCodeEnum = { + Archived: 'archived' as StatusCodeEnum, + Current: 'current' as StatusCodeEnum, + Provisional: 'provisional' as StatusCodeEnum + }; + export type FrameDescriptionEnum = 'Channel section' | 'Space frame' | 'I section' | 'Tubular' | 'Frame section' | 'Other' | 'integral' | 'Box section' | 'U section'; + export const FrameDescriptionEnum = { + ChannelSection: 'Channel section' as FrameDescriptionEnum, + SpaceFrame: 'Space frame' as FrameDescriptionEnum, + ISection: 'I section' as FrameDescriptionEnum, + Tubular: 'Tubular' as FrameDescriptionEnum, + FrameSection: 'Frame section' as FrameDescriptionEnum, + Other: 'Other' as FrameDescriptionEnum, + Integral: 'integral' as FrameDescriptionEnum, + BoxSection: 'Box section' as FrameDescriptionEnum, + USection: 'U section' as FrameDescriptionEnum + }; + export type UpdateTypeEnum = 'adrUpdate' | 'techRecordUpdate'; + export const UpdateTypeEnum = { + AdrUpdate: 'adrUpdate' as UpdateTypeEnum, + TechRecordUpdate: 'techRecordUpdate' as UpdateTypeEnum + }; + export type VehicleTypeEnum = 'psv' | 'hgv' | 'trl' | 'car' | 'lgv' | 'motorcycle'; + export const VehicleTypeEnum = { + Psv: 'psv' as VehicleTypeEnum, + Hgv: 'hgv' as VehicleTypeEnum, + Trl: 'trl' as VehicleTypeEnum, + Car: 'car' as VehicleTypeEnum, + Lgv: 'lgv' as VehicleTypeEnum, + Motorcycle: 'motorcycle' as VehicleTypeEnum + }; + export type VehicleSizeEnum = 'small' | 'large'; + export const VehicleSizeEnum = { + Small: 'small' as VehicleSizeEnum, + Large: 'large' as VehicleSizeEnum + }; + export type VehicleConfigurationEnum = 'rigid' | 'articulated' | 'centre axle drawbar' | 'semi-car transporter' | 'semi-trailer' | 'low loader' | 'other' | 'drawbar' | 'four-in-line' | 'dolly' | 'full drawbar'; + export const VehicleConfigurationEnum = { + Rigid: 'rigid' as VehicleConfigurationEnum, + Articulated: 'articulated' as VehicleConfigurationEnum, + CentreAxleDrawbar: 'centre axle drawbar' as VehicleConfigurationEnum, + SemiCarTransporter: 'semi-car transporter' as VehicleConfigurationEnum, + SemiTrailer: 'semi-trailer' as VehicleConfigurationEnum, + LowLoader: 'low loader' as VehicleConfigurationEnum, + Other: 'other' as VehicleConfigurationEnum, + Drawbar: 'drawbar' as VehicleConfigurationEnum, + FourInLine: 'four-in-line' as VehicleConfigurationEnum, + Dolly: 'dolly' as VehicleConfigurationEnum, + FullDrawbar: 'full drawbar' as VehicleConfigurationEnum + }; } diff --git a/src/app/api/vehicle/model/techRecordArchiveAndProvisionalPayload.ts b/src/app/api/vehicle/model/techRecordArchiveAndProvisionalPayload.ts index 9a73fbe0f5..9e4492a955 100644 --- a/src/app/api/vehicle/model/techRecordArchiveAndProvisionalPayload.ts +++ b/src/app/api/vehicle/model/techRecordArchiveAndProvisionalPayload.ts @@ -11,7 +11,7 @@ import { TechRecord } from './techRecord'; import { TechRecordArchiveAndProvisionalPayloadMsUserDetails } from './techRecordArchiveAndProvisionalPayloadMsUserDetails'; -export interface TechRecordArchiveAndProvisionalPayload { - msUserDetails?: TechRecordArchiveAndProvisionalPayloadMsUserDetails; - techRecord?: TechRecord; -} +export interface TechRecordArchiveAndProvisionalPayload { + msUserDetails?: TechRecordArchiveAndProvisionalPayloadMsUserDetails; + techRecord?: TechRecord; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/techRecordArchiveAndProvisionalPayloadMsUserDetails.ts b/src/app/api/vehicle/model/techRecordArchiveAndProvisionalPayloadMsUserDetails.ts index 0d9a727802..f176a9f39c 100644 --- a/src/app/api/vehicle/model/techRecordArchiveAndProvisionalPayloadMsUserDetails.ts +++ b/src/app/api/vehicle/model/techRecordArchiveAndProvisionalPayloadMsUserDetails.ts @@ -9,7 +9,7 @@ * Do not edit the class manually. */ -export interface TechRecordArchiveAndProvisionalPayloadMsUserDetails { - msUser?: string; - msOid?: string; -} +export interface TechRecordArchiveAndProvisionalPayloadMsUserDetails { + msUser?: string; + msOid?: string; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/techRecordBodyType.ts b/src/app/api/vehicle/model/techRecordBodyType.ts index 38976eaf9e..54b7f2fb14 100644 --- a/src/app/api/vehicle/model/techRecordBodyType.ts +++ b/src/app/api/vehicle/model/techRecordBodyType.ts @@ -12,95 +12,56 @@ /** * Used for all vehicles types - PSV, HGV and TRL. x = other, d = double decker. Used only for HGV and TRL. p = petrol/oil tanker, o = other tanker, s = skip loader, f = flat, c = refrigerated, b = box, e = curtainsider, k = skeletal, t = tipper, y = car transporter, i = livestock carrier. Used only for HGV. r = refuse, m = concrete mixer, a = fast trac tractor, u = artic unit. Used only for PSV. s = single decker, a = articulated, m = mini bus. Used only for TRL. l = low loader. */ -export interface TechRecordBodyType { - code?: TechRecordBodyType.CodeEnum; - description?: TechRecordBodyType.DescriptionEnum; +export interface TechRecordBodyType { + code?: TechRecordBodyType.CodeEnum; + description?: TechRecordBodyType.DescriptionEnum; } export namespace TechRecordBodyType { - export type CodeEnum = - | 'a' - | 's' - | 'd' - | 'o' - | 'x' - | 'p' - | 'k' - | 't' - | 'b' - | 'f' - | 'r' - | 'c' - | 'e' - | 'y' - | 'm' - | 'i' - | 'u' - | 'l'; - export const CodeEnum = { - A: 'a' as CodeEnum, - S: 's' as CodeEnum, - D: 'd' as CodeEnum, - O: 'o' as CodeEnum, - M: 'm' as CodeEnum, - X: 'x' as CodeEnum, - P: 'p' as CodeEnum, - K: 'k' as CodeEnum, - T: 't' as CodeEnum, - B: 'b' as CodeEnum, - F: 'f' as CodeEnum, - R: 'r' as CodeEnum, - C: 'c' as CodeEnum, - E: 'e' as CodeEnum, - Y: 'y' as CodeEnum, - M_15: 'm' as CodeEnum, - I: 'i' as CodeEnum, - A_17: 'a' as CodeEnum, - U: 'u' as CodeEnum, - L: 'l' as CodeEnum, - }; - export type DescriptionEnum = - | 'articulated' - | 'single decker' - | 'double decker' - | 'other' - | 'other tanker' - | 'petrol/oil tanker' - | 'skeletal' - | 'tipper' - | 'box' - | 'flat' - | 'refuse' - | 'skip loader' - | 'refrigerated' - | 'curtainsider' - | 'car transporter' - | 'concrete mixer' - | 'mini bus' - | 'livestock carrier' - | 'fast trac tractor' - | 'artic unit' - | 'low loader'; - export const DescriptionEnum = { - Articulated: 'articulated' as DescriptionEnum, - SingleDecker: 'single decker' as DescriptionEnum, - DoubleDecker: 'double decker' as DescriptionEnum, - Other: 'other' as DescriptionEnum, - OtherTanker: 'other tanker' as DescriptionEnum, - PetroloilTanker: 'petrol/oil tanker' as DescriptionEnum, - Skeletal: 'skeletal' as DescriptionEnum, - Tipper: 'tipper' as DescriptionEnum, - Box: 'box' as DescriptionEnum, - Flat: 'flat' as DescriptionEnum, - Refuse: 'refuse' as DescriptionEnum, - SkipLoader: 'skip loader' as DescriptionEnum, - Refrigerated: 'refrigerated' as DescriptionEnum, - Curtainsider: 'curtainsider' as DescriptionEnum, - CarTransporter: 'car transporter' as DescriptionEnum, - ConcreteMixer: 'concrete mixer' as DescriptionEnum, - MiniBus: 'mini bus' as DescriptionEnum, - LivestockCarrier: 'livestock carrier' as DescriptionEnum, - FastTracTractor: 'fast trac tractor' as DescriptionEnum, - ArticUnit: 'artic unit' as DescriptionEnum, - LowLoader: 'low loader' as DescriptionEnum, - }; -} + export type CodeEnum = 'a' | 's' | 'd' | 'o' | 'x' | 'p' | 'k' | 't' | 'b' | 'f' | 'r' | 'c' | 'e' | 'y' | 'm' | 'i' | 'u' | 'l'; + export const CodeEnum = { + A: 'a' as CodeEnum, + S: 's' as CodeEnum, + D: 'd' as CodeEnum, + O: 'o' as CodeEnum, + M: 'm' as CodeEnum, + X: 'x' as CodeEnum, + P: 'p' as CodeEnum, + K: 'k' as CodeEnum, + T: 't' as CodeEnum, + B: 'b' as CodeEnum, + F: 'f' as CodeEnum, + R: 'r' as CodeEnum, + C: 'c' as CodeEnum, + E: 'e' as CodeEnum, + Y: 'y' as CodeEnum, + M_15: 'm' as CodeEnum, + I: 'i' as CodeEnum, + A_17: 'a' as CodeEnum, + U: 'u' as CodeEnum, + L: 'l' as CodeEnum + }; + export type DescriptionEnum = 'articulated' | 'single decker' | 'double decker' | 'other' | 'other tanker' | 'petrol/oil tanker' | 'skeletal' | 'tipper' | 'box' | 'flat' | 'refuse' | 'skip loader' | 'refrigerated' | 'curtainsider' | 'car transporter' | 'concrete mixer' | 'mini bus' | 'livestock carrier' | 'fast trac tractor' | 'artic unit' | 'low loader'; + export const DescriptionEnum = { + Articulated: 'articulated' as DescriptionEnum, + SingleDecker: 'single decker' as DescriptionEnum, + DoubleDecker: 'double decker' as DescriptionEnum, + Other: 'other' as DescriptionEnum, + OtherTanker: 'other tanker' as DescriptionEnum, + PetroloilTanker: 'petrol/oil tanker' as DescriptionEnum, + Skeletal: 'skeletal' as DescriptionEnum, + Tipper: 'tipper' as DescriptionEnum, + Box: 'box' as DescriptionEnum, + Flat: 'flat' as DescriptionEnum, + Refuse: 'refuse' as DescriptionEnum, + SkipLoader: 'skip loader' as DescriptionEnum, + Refrigerated: 'refrigerated' as DescriptionEnum, + Curtainsider: 'curtainsider' as DescriptionEnum, + CarTransporter: 'car transporter' as DescriptionEnum, + ConcreteMixer: 'concrete mixer' as DescriptionEnum, + MiniBus: 'mini bus' as DescriptionEnum, + LivestockCarrier: 'livestock carrier' as DescriptionEnum, + FastTracTractor: 'fast trac tractor' as DescriptionEnum, + ArticUnit: 'artic unit' as DescriptionEnum, + LowLoader: 'low loader' as DescriptionEnum + }; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/techRecordDimensions.ts b/src/app/api/vehicle/model/techRecordDimensions.ts index a45a94e78e..ee3ee86de0 100644 --- a/src/app/api/vehicle/model/techRecordDimensions.ts +++ b/src/app/api/vehicle/model/techRecordDimensions.ts @@ -10,21 +10,21 @@ */ import { TechRecordDimensionsAxleSpacing } from './techRecordDimensionsAxleSpacing'; -export interface TechRecordDimensions { - /** - * Used for all vehicle types. Optional for PSV - */ - length?: number; - /** - * Used only for PSV - */ - height?: number; - /** - * Used for all vehicle types. Optional for PSV - */ - width?: number; - /** - * Used only for HGV and TRL - */ - axleSpacing?: Array; -} +export interface TechRecordDimensions { + /** + * Used for all vehicle types. Optional for PSV + */ + length?: number; + /** + * Used only for PSV + */ + height?: number; + /** + * Used for all vehicle types. Optional for PSV + */ + width?: number; + /** + * Used only for HGV and TRL + */ + axleSpacing?: Array; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/techRecordDimensionsAxleSpacing.ts b/src/app/api/vehicle/model/techRecordDimensionsAxleSpacing.ts index c1872a51f6..7e2e900aee 100644 --- a/src/app/api/vehicle/model/techRecordDimensionsAxleSpacing.ts +++ b/src/app/api/vehicle/model/techRecordDimensionsAxleSpacing.ts @@ -9,10 +9,10 @@ * Do not edit the class manually. */ -export interface TechRecordDimensionsAxleSpacing { - axles?: string; - /** - * Optional for HGV - */ - value?: number; -} +export interface TechRecordDimensionsAxleSpacing { + axles?: string; + /** + * Optional for HGV + */ + value?: number; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/techRecordPOST.ts b/src/app/api/vehicle/model/techRecordPOST.ts index ea06a4e05e..554c971b4a 100644 --- a/src/app/api/vehicle/model/techRecordPOST.ts +++ b/src/app/api/vehicle/model/techRecordPOST.ts @@ -11,23 +11,23 @@ import { TechRecordArchiveAndProvisionalPayloadMsUserDetails } from './techRecordArchiveAndProvisionalPayloadMsUserDetails'; import { TechRecords } from './techRecords'; -export interface TechRecordPOST { - msUserDetails?: TechRecordArchiveAndProvisionalPayloadMsUserDetails; - /** - * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle - */ - vin?: string; - /** - * Mandatory for PSV, HGV, car, lgv, motorcycle. Optional for TRL - */ - primaryVrm?: string; - /** - * Mandatory for PSV and HGV. Optional for TRL - */ - secondaryVrms?: Array; - /** - * Used only for TRL. Optional for HGV and PSV - */ - trailerId?: string; - techRecord?: TechRecords; -} +export interface TechRecordPOST { + msUserDetails?: TechRecordArchiveAndProvisionalPayloadMsUserDetails; + /** + * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle + */ + vin?: string; + /** + * Mandatory for PSV, HGV, car, lgv, motorcycle. Optional for TRL + */ + primaryVrm?: string; + /** + * Mandatory for PSV and HGV. Optional for TRL + */ + secondaryVrms?: Array; + /** + * Used only for TRL. Optional for HGV and PSV + */ + trailerId?: string; + techRecord?: TechRecords; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/techRecordPUT.ts b/src/app/api/vehicle/model/techRecordPUT.ts index d4300dc4f2..0e070ef150 100644 --- a/src/app/api/vehicle/model/techRecordPUT.ts +++ b/src/app/api/vehicle/model/techRecordPUT.ts @@ -11,19 +11,19 @@ import { TechRecordArchiveAndProvisionalPayloadMsUserDetails } from './techRecordArchiveAndProvisionalPayloadMsUserDetails'; import { TechRecords } from './techRecords'; -export interface TechRecordPUT { - msUserDetails?: TechRecordArchiveAndProvisionalPayloadMsUserDetails; - /** - * Mandatory for PSV, HGV, car, lgv, motorcycle. Optional for TRL - */ - primaryVrm?: string; - /** - * Mandatory for PSV and HGV. Optional for TRL - */ - secondaryVrms?: Array; - /** - * Used only for TRL. Optional for HGV and PSV - */ - trailerId?: string; - techRecord?: TechRecords; -} +export interface TechRecordPUT { + msUserDetails?: TechRecordArchiveAndProvisionalPayloadMsUserDetails; + /** + * Mandatory for PSV, HGV, car, lgv, motorcycle. Optional for TRL + */ + primaryVrm?: string; + /** + * Mandatory for PSV and HGV. Optional for TRL + */ + secondaryVrms?: Array; + /** + * Used only for TRL. Optional for HGV and PSV + */ + trailerId?: string; + techRecord?: TechRecords; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/techRecordVehicleClass.ts b/src/app/api/vehicle/model/techRecordVehicleClass.ts index 52a0c14f85..222584bb61 100644 --- a/src/app/api/vehicle/model/techRecordVehicleClass.ts +++ b/src/app/api/vehicle/model/techRecordVehicleClass.ts @@ -12,48 +12,37 @@ /** * Used for all vehicle types - PSV, HGV, TRL, car, lgv, motorcycle. Optional for CAR and LGV */ -export interface TechRecordVehicleClass { - code?: TechRecordVehicleClass.CodeEnum; - description?: TechRecordVehicleClass.DescriptionEnum; +export interface TechRecordVehicleClass { + code?: TechRecordVehicleClass.CodeEnum; + description?: TechRecordVehicleClass.DescriptionEnum; } export namespace TechRecordVehicleClass { - export type CodeEnum = '2' | 'n' | 's' | '1' | 't' | 'l' | '3' | 'v' | '4' | '7' | '5'; - export const CodeEnum = { - _2: '2' as CodeEnum, - N: 'n' as CodeEnum, - S: 's' as CodeEnum, - _1: '1' as CodeEnum, - T: 't' as CodeEnum, - L: 'l' as CodeEnum, - _3: '3' as CodeEnum, - V: 'v' as CodeEnum, - _4: '4' as CodeEnum, - _7: '7' as CodeEnum, - _5: '5' as CodeEnum, - }; - export type DescriptionEnum = - | 'motorbikes over 200cc or with a sidecar' - | 'not applicable' - | 'small psv (ie: less than or equal to 22 seats)' - | 'motorbikes up to 200cc' - | 'trailer' - | 'large psv(ie: greater than 23 seats)' - | '3 wheelers' - | 'heavy goods vehicle' - | 'MOT class 4' - | 'MOT class 7' - | 'MOT class 5'; - export const DescriptionEnum = { - MotorbikesOver200ccOrWithASidecar: 'motorbikes over 200cc or with a sidecar' as DescriptionEnum, - NotApplicable: 'not applicable' as DescriptionEnum, - SmallPsvIeLessThanOrEqualTo22Seats: 'small psv (ie: less than or equal to 22 seats)' as DescriptionEnum, - MotorbikesUpTo200cc: 'motorbikes up to 200cc' as DescriptionEnum, - Trailer: 'trailer' as DescriptionEnum, - LargePsvIeGreaterThan23Seats: 'large psv(ie: greater than 23 seats)' as DescriptionEnum, - _3Wheelers: '3 wheelers' as DescriptionEnum, - HeavyGoodsVehicle: 'heavy goods vehicle' as DescriptionEnum, - MOTClass4: 'MOT class 4' as DescriptionEnum, - MOTClass7: 'MOT class 7' as DescriptionEnum, - MOTClass5: 'MOT class 5' as DescriptionEnum, - }; -} + export type CodeEnum = '2' | 'n' | 's' | '1' | 't' | 'l' | '3' | 'v' | '4' | '7' | '5'; + export const CodeEnum = { + _2: '2' as CodeEnum, + N: 'n' as CodeEnum, + S: 's' as CodeEnum, + _1: '1' as CodeEnum, + T: 't' as CodeEnum, + L: 'l' as CodeEnum, + _3: '3' as CodeEnum, + V: 'v' as CodeEnum, + _4: '4' as CodeEnum, + _7: '7' as CodeEnum, + _5: '5' as CodeEnum + }; + export type DescriptionEnum = 'motorbikes over 200cc or with a sidecar' | 'not applicable' | 'small psv (ie: less than or equal to 22 seats)' | 'motorbikes up to 200cc' | 'trailer' | 'large psv(ie: greater than 23 seats)' | '3 wheelers' | 'heavy goods vehicle' | 'MOT class 4' | 'MOT class 7' | 'MOT class 5'; + export const DescriptionEnum = { + MotorbikesOver200ccOrWithASidecar: 'motorbikes over 200cc or with a sidecar' as DescriptionEnum, + NotApplicable: 'not applicable' as DescriptionEnum, + SmallPsvIeLessThanOrEqualTo22Seats: 'small psv (ie: less than or equal to 22 seats)' as DescriptionEnum, + MotorbikesUpTo200cc: 'motorbikes up to 200cc' as DescriptionEnum, + Trailer: 'trailer' as DescriptionEnum, + LargePsvIeGreaterThan23Seats: 'large psv(ie: greater than 23 seats)' as DescriptionEnum, + _3Wheelers: '3 wheelers' as DescriptionEnum, + HeavyGoodsVehicle: 'heavy goods vehicle' as DescriptionEnum, + MOTClass4: 'MOT class 4' as DescriptionEnum, + MOTClass7: 'MOT class 7' as DescriptionEnum, + MOTClass5: 'MOT class 5' as DescriptionEnum, + }; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/techRecords.ts b/src/app/api/vehicle/model/techRecords.ts index 8e5898fe8b..08d9cebcdb 100644 --- a/src/app/api/vehicle/model/techRecords.ts +++ b/src/app/api/vehicle/model/techRecords.ts @@ -10,4 +10,5 @@ */ import { TechRecord } from './techRecord'; -export interface TechRecords extends Array {} +export interface TechRecords extends Array { +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/vrm.ts b/src/app/api/vehicle/model/vrm.ts index 69bb5cce13..e3c79d95ba 100644 --- a/src/app/api/vehicle/model/vrm.ts +++ b/src/app/api/vehicle/model/vrm.ts @@ -12,7 +12,7 @@ /** * Used only for PSV and HGV */ -export interface Vrm { - vrm?: string; - isPrimary?: boolean; -} +export interface Vrm { + vrm?: string; + isPrimary?: boolean; +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/vrms.ts b/src/app/api/vehicle/model/vrms.ts index 80800601b0..d614ec759f 100644 --- a/src/app/api/vehicle/model/vrms.ts +++ b/src/app/api/vehicle/model/vrms.ts @@ -10,4 +10,5 @@ */ import { Vrm } from './vrm'; -export interface Vrms extends Array {} +export interface Vrms extends Array { +} \ No newline at end of file diff --git a/src/app/api/vehicle/model/weights.ts b/src/app/api/vehicle/model/weights.ts index 0b72e5a0f1..75fb0334f5 100644 --- a/src/app/api/vehicle/model/weights.ts +++ b/src/app/api/vehicle/model/weights.ts @@ -12,16 +12,16 @@ import { AxleBrakeProperties } from './axleBrakeProperties'; import { AxleTyreProperties } from './axleTyreProperties'; import { AxleWeightProperties } from './axleWeightProperties'; -export interface Weights { - /** - * Used for all vehicle types - PSV, HGV and TRL - */ - axleNumber?: number; - /** - * Used for all vehicle types - PSV, HGV and TRL. Optional for HGV - */ - parkingBrakeMrk?: boolean; - weights?: AxleWeightProperties; - tyres?: AxleTyreProperties; - brakes?: AxleBrakeProperties; -} +export interface Weights { + /** + * Used for all vehicle types - PSV, HGV and TRL + */ + axleNumber?: number; + /** + * Used for all vehicle types - PSV, HGV and TRL. Optional for HGV + */ + parkingBrakeMrk?: boolean; + weights?: AxleWeightProperties; + tyres?: AxleTyreProperties; + brakes?: AxleBrakeProperties; +} \ No newline at end of file diff --git a/src/app/api/vehicle/variables.ts b/src/app/api/vehicle/variables.ts index 9bae45f800..6fe58549f3 100644 --- a/src/app/api/vehicle/variables.ts +++ b/src/app/api/vehicle/variables.ts @@ -2,8 +2,8 @@ import { InjectionToken } from '@angular/core'; export const BASE_PATH = new InjectionToken('basePath'); export const COLLECTION_FORMATS = { - csv: ',', - tsv: ' ', - ssv: ' ', - pipes: '|', -}; + 'csv': ',', + 'tsv': ' ', + 'ssv': ' ', + 'pipes': '|' +} From 5966ece9a3b6a6cb5e0ccc5f0ea3f5b37111fb1e Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Wed, 14 Aug 2024 14:46:45 +0100 Subject: [PATCH 17/21] chore(linting-1): enable no implicit any let --- biome.json | 1 - .../forms/components/date/focus-next.directive.ts | 2 +- .../pipes/test-type-name/test-type-name.pipe.ts | 2 +- .../effects/operators/reference-data.operators.ts | 14 +++++++++----- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/biome.json b/biome.json index 5d3c7446d3..8bb8634ca8 100644 --- a/biome.json +++ b/biome.json @@ -21,7 +21,6 @@ "noDoubleEquals": "off", "noDuplicateTestHooks": "off", "noExplicitAny": "off", - "noImplicitAnyLet": "off", "useValidTypeof": "off" } } diff --git a/src/app/forms/components/date/focus-next.directive.ts b/src/app/forms/components/date/focus-next.directive.ts index c299e84651..c39eb7f9cd 100644 --- a/src/app/forms/components/date/focus-next.directive.ts +++ b/src/app/forms/components/date/focus-next.directive.ts @@ -22,7 +22,7 @@ export class FocusNextDirective { } private getNextElement(currentSegment: string, value: string): string | undefined { - let nextEl; + let nextEl: string; if (value.length === 2) { switch (currentSegment) { diff --git a/src/app/shared/pipes/test-type-name/test-type-name.pipe.ts b/src/app/shared/pipes/test-type-name/test-type-name.pipe.ts index aca802585b..051f455d6b 100644 --- a/src/app/shared/pipes/test-type-name/test-type-name.pipe.ts +++ b/src/app/shared/pipes/test-type-name/test-type-name.pipe.ts @@ -17,7 +17,7 @@ export class TestTypeNamePipe implements PipeTransform { ); } - let result; + let result: TestType | undefined; testTypes.some(idMatch); return result; } diff --git a/src/app/store/reference-data/effects/operators/reference-data.operators.ts b/src/app/store/reference-data/effects/operators/reference-data.operators.ts index bb6b35415a..a5785d685f 100644 --- a/src/app/store/reference-data/effects/operators/reference-data.operators.ts +++ b/src/app/store/reference-data/effects/operators/reference-data.operators.ts @@ -45,7 +45,6 @@ export function sortReferenceData(resourceType: ReferenceDataResourceType) { }); } -// eslint-disable-next-line no-underscore-dangle function _sort(type: ReferenceDataResourceType, data: ReferenceDataItem[]) { const dataToSort = [...(data as ReferenceData[])]; switch (type) { @@ -57,12 +56,17 @@ function _sort(type: ReferenceDataResourceType, data: ReferenceDataItem[]) { } type ReferenceData = ReferenceDataItem & Record; + +type SortKeyValue = string | number; + function sorter(sortkey: keyof ReferenceData | undefined = 'description') { - // eslint-disable-next-line no-nested-ternary, @typescript-eslint/no-explicit-any - const compare = (a: any, b: any) => (typeof a === 'string' ? (a <= b ? (a < b ? -1 : 0) : 1) : a - b); + const compare = (a: SortKeyValue, b: SortKeyValue): number => + typeof a === 'string' && typeof b === 'string' ? (a <= b ? (a < b ? -1 : 0) : 1) : (a as number) - (b as number); + return (a: ReferenceData, b: ReferenceData) => { - let l; - let r; + let l: SortKeyValue = ''; + let r: SortKeyValue = ''; + if (sortkey && Object.prototype.hasOwnProperty.call(a, sortkey)) { l = a[`${sortkey}`]; r = b[`${sortkey}`]; From 96f5ab15d3f79dc085f133acd408a5ca12c0f7b4 Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Wed, 14 Aug 2024 16:17:54 +0100 Subject: [PATCH 18/21] chore(linting-1): enable no duplicate test hooks --- biome.json | 1 - .../components/breadcrumbs/breadcrumbs.component.spec.ts | 2 -- src/app/core/components/footer/footer.component.spec.ts | 2 -- .../global-error/global-error.component.spec.ts | 2 -- .../global-warning/global-warning.component.spec.ts | 3 --- src/app/core/components/header/header.component.spec.ts | 2 -- .../page-not-found/page-not-found.component.spec.ts | 2 -- .../phase-banner/phase-banner.component.spec.ts | 2 -- .../server-error/server-error.component.spec.ts | 2 -- .../components/home-button/home-button.component.spec.ts | 2 -- src/app/features/home/home.component.spec.ts | 2 -- .../reference-data-add.component.spec.ts | 2 -- .../reference-data-amend-history.component.spec.ts | 2 -- .../reference-data-amend.component.spec.ts | 2 -- .../reference-data-delete.component.spec.ts | 3 +-- .../reference-data-deleted-list.component.spec.ts | 2 -- .../reference-data-list.component.spec.ts | 2 -- .../reference-data-select-type.component.spec.ts | 2 -- src/app/features/search/search.component.spec.ts | 2 -- .../single-search-result.component.spec.ts | 2 -- .../adr-generate-certificate.component.spec.ts | 3 +-- .../edit-tech-record-button.component.spec.ts | 2 -- .../tech-record-amend-reason.component.spec.ts | 2 -- .../tech-record-amend-vin.component.spec.ts | 2 -- .../tech-record-amend-vrm-reason.component.spec.ts | 2 -- .../tech-record-amend-vrm.component.spec.ts | 3 +-- .../tech-record-change-status.component.spec.ts | 2 -- .../tech-record-change-type.component.spec.ts | 2 -- .../tech-record-change-visibility.component.spec.ts | 2 -- .../tech-record-generate-letter.component.spec.ts | 2 -- .../tech-record-generate-plate.component.spec.ts | 2 -- .../tech-record-history.component.spec.ts | 3 +-- .../tech-record-search-tyres.component.spec.ts | 2 -- .../tech-record-summary.component.spec.ts | 2 -- .../tech-record-title/tech-record-title.component.spec.ts | 2 -- .../tech-record-unarchive.component.spec.ts | 2 -- .../test-record-summary.component.spec.ts | 2 -- .../vehicle-technical-record.component.spec.ts | 2 -- .../batch-vehicle-details.component.spec.ts | 2 -- .../batch-vehicle-results.component.spec.ts | 2 -- .../batch-vehicle-template.component.spec.ts | 2 -- .../hydrate-new-vehicle-record.component.spec.ts | 2 -- .../create/create-tech-record.component.spec.ts | 2 -- .../features/tech-record/tech-record.component.spec.ts | 2 -- .../test-amendment-history.component.spec.ts | 2 -- .../amend/views/amend-test/amend-test.component.spec.ts | 2 -- .../amended-test-record.component.spec.ts | 2 -- .../confirm-cancellation.component.spec.ts | 2 -- .../test-amend-reason/test-amend-reason.component.spec.ts | 2 -- .../amend/views/test-record/test-record.component.spec.ts | 2 -- .../test-result-summary.component.spec.ts | 2 -- .../test-router-outlet.component.spec.ts | 2 -- .../test-type-select-wrapper.component.spec.ts | 2 -- .../base-test-record/base-test-record.component.spec.ts | 2 -- .../test-type-select/test-type-select.component.spec.ts | 2 -- .../vehicle-header/vehicle-header.component.spec.ts | 2 -- .../create-test-record.component.spec.ts | 2 -- .../create-test-type/create-test-type.component.spec.ts | 2 -- .../test-router-outlet.component.spec.ts | 2 -- .../approval-type/approval-type.component.spec.ts | 2 -- .../autocomplete/autocomplete.component.spec.ts | 2 -- .../base-control/base-control.component.spec.ts | 6 +----- .../checkbox-group/checkbox-group.component.spec.ts | 2 -- .../forms/components/checkbox/checkbox.component.spec.ts | 2 -- .../contingency-adr-generate-cert.component.spec.ts | 3 +-- src/app/forms/components/date/date.component.spec.ts | 2 -- .../forms/components/date/focus-next.directive.spec.ts | 2 -- .../defect-select/defect-select.component.spec.ts | 2 -- .../dynamic-form-field.component.spec.ts | 4 +--- .../dynamic-form-group.component.spec.ts | 2 -- .../field-error-message.component.spec.ts | 2 -- .../number-input/number-input.component.spec.ts | 2 -- .../components/radio-group/radio-group.component.spec.ts | 2 -- .../components/read-only/read-only.component.spec.ts | 2 -- .../required-standard-select.component.spec.ts | 2 -- src/app/forms/components/select/select.component.spec.ts | 2 -- .../suggestive-input/suggestive-input.component.spec.ts | 2 -- .../switchable-input/switchable-input.component.spec.ts | 2 -- .../components/text-area/text-area.component.spec.ts | 2 -- .../components/text-input/text-input.component.spec.ts | 2 -- .../view-combination/view-combination.component.spec.ts | 2 -- .../view-list-item/view-list-item.component.spec.ts | 2 -- .../abandon-dialog/abandon-dialog.component.spec.ts | 2 -- .../adr-certificate-history.component.spec.ts | 4 ++-- ...-details-subsequent-inspections-edit.component.spec.ts | 2 -- src/app/forms/custom-sections/body/body.component.spec.ts | 2 -- .../custom-defect/custom-defect.component.spec.ts | 2 -- .../custom-defects/custom-defects.component.spec.ts | 2 -- .../forms/custom-sections/defect/defect.component.spec.ts | 2 -- .../custom-sections/defects/defects.component.spec.ts | 2 -- .../dimensions/dimensions.component.spec.ts | 3 +-- .../custom-sections/letters/letters.component.spec.ts | 2 -- .../forms/custom-sections/plates/plates.component.spec.ts | 2 -- .../psv-brakes/psv-brakes.component.spec.ts | 2 -- .../required-standard/required-standard.component.spec.ts | 2 -- .../required-standards.component.spec.ts | 2 -- .../trl-brakes/trl-brakes.component.spec.ts | 2 -- .../forms/custom-sections/tyres/tyres.component.spec.ts | 8 -------- .../custom-sections/weights/weights.component.spec.ts | 2 -- .../error-handling/error-handling.interceptor.spec.ts | 2 -- .../defects-taxonomy/defects-taxonomy.resolver.spec.ts | 2 -- .../required-standards.resolver.spec.ts | 2 -- .../tech-record-view/tech-record-view.resolver.spec.ts | 2 -- .../resolvers/test-result/test-result.resolver.spec.ts | 2 -- .../test-stations/test-stations.resolver.spec.ts | 2 -- .../test-type-taxonomy.resolver.spec.ts | 2 -- .../accordion-control/accordion-control.component.spec.ts | 2 -- .../components/accordion/accordion.component.spec.ts | 4 +--- src/app/shared/components/banner/banner.component.spec.ts | 2 -- .../components/base-dialog/base-dialog.component.spec.ts | 2 -- .../button-group/button-group.component.spec.ts | 2 -- src/app/shared/components/button/button.component.spec.ts | 2 -- .../collapsible-text/collapsible-text.component.spec.ts | 2 -- src/app/shared/components/icon/icon.component.spec.ts | 2 -- .../input-spinner/input-spinner.component.spec.ts | 2 -- .../number-plate/number-plate.component.spec.ts | 2 -- .../components/pagination/pagination.component.spec.ts | 6 +----- .../router-outlet/router-outlet.component.spec.ts | 2 -- src/app/shared/components/tag/tag.component.spec.ts | 2 -- .../test-certificate/test-certificate.component.spec.ts | 2 -- .../prevent-double-click.directive.spec.ts | 4 +--- src/app/store/defects/effects/defects.effects.spec.ts | 2 -- .../reference-data/effects/reference-data.effects.spec.ts | 2 -- .../effects/required-standards.effects.spec.ts | 2 -- .../effects/tech-record-search.effect.spec.ts | 2 -- .../effects/technical-record-service.effects.spec.ts | 2 -- .../test-records/effects/test-records.effects.spec.ts | 2 -- .../test-stations/effects/test-stations.effects.spec.ts | 2 -- .../store/test-types/effects/test-types.effects.spec.ts | 2 -- 129 files changed, 13 insertions(+), 273 deletions(-) diff --git a/biome.json b/biome.json index 8bb8634ca8..6225cbf794 100644 --- a/biome.json +++ b/biome.json @@ -19,7 +19,6 @@ }, "suspicious": { "noDoubleEquals": "off", - "noDuplicateTestHooks": "off", "noExplicitAny": "off", "useValidTypeof": "off" } diff --git a/src/app/core/components/breadcrumbs/breadcrumbs.component.spec.ts b/src/app/core/components/breadcrumbs/breadcrumbs.component.spec.ts index 9e23418c03..ac71fe4e9f 100644 --- a/src/app/core/components/breadcrumbs/breadcrumbs.component.spec.ts +++ b/src/app/core/components/breadcrumbs/breadcrumbs.component.spec.ts @@ -19,9 +19,7 @@ describe('BreadcrumbsComponent', () => { imports: [RouterTestingModule], providers: [RouterService, provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(BreadcrumbsComponent); component = fixture.componentInstance; store = TestBed.inject(MockStore); diff --git a/src/app/core/components/footer/footer.component.spec.ts b/src/app/core/components/footer/footer.component.spec.ts index 6c48f38b17..7c622bb3ab 100644 --- a/src/app/core/components/footer/footer.component.spec.ts +++ b/src/app/core/components/footer/footer.component.spec.ts @@ -10,9 +10,7 @@ describe('FooterComponent', () => { await TestBed.configureTestingModule({ declarations: [FooterComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(FooterComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/core/components/global-error/global-error.component.spec.ts b/src/app/core/components/global-error/global-error.component.spec.ts index fb2ebddc04..4e178f3c37 100644 --- a/src/app/core/components/global-error/global-error.component.spec.ts +++ b/src/app/core/components/global-error/global-error.component.spec.ts @@ -23,9 +23,7 @@ describe('GlobalErrorComponent', () => { imports: [], providers: [GlobalErrorService, provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(MockComponent); component = fixture.debugElement.query(By.directive(GlobalErrorComponent)).componentInstance; fixture.detectChanges(); diff --git a/src/app/core/components/global-warning/global-warning.component.spec.ts b/src/app/core/components/global-warning/global-warning.component.spec.ts index 65bc2ae2d8..004f359304 100644 --- a/src/app/core/components/global-warning/global-warning.component.spec.ts +++ b/src/app/core/components/global-warning/global-warning.component.spec.ts @@ -20,12 +20,9 @@ describe('GlobalWarningComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [GlobalWarningComponent, MockComponent], - imports: [], providers: [GlobalWarningService, provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(MockComponent); component = fixture.debugElement.query(By.directive(GlobalWarningComponent)).componentInstance; fixture.detectChanges(); diff --git a/src/app/core/components/header/header.component.spec.ts b/src/app/core/components/header/header.component.spec.ts index 36543cc334..5f141f7644 100644 --- a/src/app/core/components/header/header.component.spec.ts +++ b/src/app/core/components/header/header.component.spec.ts @@ -13,9 +13,7 @@ describe('HeaderComponent', () => { await TestBed.configureTestingModule({ declarations: [HeaderComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HeaderComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/core/components/page-not-found/page-not-found.component.spec.ts b/src/app/core/components/page-not-found/page-not-found.component.spec.ts index c1d2ff83e5..b04de391a6 100644 --- a/src/app/core/components/page-not-found/page-not-found.component.spec.ts +++ b/src/app/core/components/page-not-found/page-not-found.component.spec.ts @@ -9,9 +9,7 @@ describe('PageNotFoundComponent', () => { await TestBed.configureTestingModule({ declarations: [PageNotFoundComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(PageNotFoundComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/core/components/phase-banner/phase-banner.component.spec.ts b/src/app/core/components/phase-banner/phase-banner.component.spec.ts index 779d4b39f0..6f52f8618f 100644 --- a/src/app/core/components/phase-banner/phase-banner.component.spec.ts +++ b/src/app/core/components/phase-banner/phase-banner.component.spec.ts @@ -10,9 +10,7 @@ describe('PhaseBannerComponent', () => { await TestBed.configureTestingModule({ declarations: [PhaseBannerComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(PhaseBannerComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/core/components/server-error/server-error.component.spec.ts b/src/app/core/components/server-error/server-error.component.spec.ts index 10a1576600..82286b60ff 100644 --- a/src/app/core/components/server-error/server-error.component.spec.ts +++ b/src/app/core/components/server-error/server-error.component.spec.ts @@ -9,9 +9,7 @@ describe('ServerErrorComponent', () => { await TestBed.configureTestingModule({ declarations: [ServerErrorComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(ServerErrorComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/home/components/home-button/home-button.component.spec.ts b/src/app/features/home/components/home-button/home-button.component.spec.ts index e7d4916c58..58dc904987 100644 --- a/src/app/features/home/components/home-button/home-button.component.spec.ts +++ b/src/app/features/home/components/home-button/home-button.component.spec.ts @@ -11,9 +11,7 @@ describe('HomeButtonComponent', () => { declarations: [HomeButtonComponent], imports: [RouterTestingModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HomeButtonComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/home/home.component.spec.ts b/src/app/features/home/home.component.spec.ts index 3d3e56ae45..f8b0287bc1 100644 --- a/src/app/features/home/home.component.spec.ts +++ b/src/app/features/home/home.component.spec.ts @@ -31,9 +31,7 @@ describe('HomeComponent', () => { }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HomeComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/reference-data/reference-data-add/reference-data-add.component.spec.ts b/src/app/features/reference-data/reference-data-add/reference-data-add.component.spec.ts index 5ef1ceacce..276b04704f 100644 --- a/src/app/features/reference-data/reference-data-add/reference-data-add.component.spec.ts +++ b/src/app/features/reference-data/reference-data-add/reference-data-add.component.spec.ts @@ -36,9 +36,7 @@ describe('ReferenceDataCreateComponent', () => { { provide: ReferenceDataService, useValue: mockRefDataService }, ], }).compileComponents(); - }); - beforeEach(() => { store = TestBed.inject(MockStore); fixture = TestBed.createComponent(ReferenceDataCreateComponent); component = fixture.componentInstance; diff --git a/src/app/features/reference-data/reference-data-amend-history/reference-data-amend-history.component.spec.ts b/src/app/features/reference-data/reference-data-amend-history/reference-data-amend-history.component.spec.ts index 2b271cda86..31857196b0 100644 --- a/src/app/features/reference-data/reference-data-amend-history/reference-data-amend-history.component.spec.ts +++ b/src/app/features/reference-data/reference-data-amend-history/reference-data-amend-history.component.spec.ts @@ -21,9 +21,7 @@ describe('ReferenceDataAmendHistoryComponent', () => { { provide: UserService, useValue: {} }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(ReferenceDataAmendHistoryComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/reference-data/reference-data-amend/reference-data-amend.component.spec.ts b/src/app/features/reference-data/reference-data-amend/reference-data-amend.component.spec.ts index 7f50174b69..e7d45eb384 100644 --- a/src/app/features/reference-data/reference-data-amend/reference-data-amend.component.spec.ts +++ b/src/app/features/reference-data/reference-data-amend/reference-data-amend.component.spec.ts @@ -34,9 +34,7 @@ describe('ReferenceDataAmendComponent', () => { { provide: ReferenceDataService, useValue: mockRefDataService }, ], }).compileComponents(); - }); - beforeEach(() => { store = TestBed.inject(MockStore); fixture = TestBed.createComponent(ReferenceDataAmendComponent); component = fixture.componentInstance; diff --git a/src/app/features/reference-data/reference-data-delete/reference-data-delete.component.spec.ts b/src/app/features/reference-data/reference-data-delete/reference-data-delete.component.spec.ts index de0205b757..4a8ac4f413 100644 --- a/src/app/features/reference-data/reference-data-delete/reference-data-delete.component.spec.ts +++ b/src/app/features/reference-data/reference-data-delete/reference-data-delete.component.spec.ts @@ -29,9 +29,7 @@ describe('ReferenceDataAddComponent', () => { { provide: UserService, useValue: {} }, ], }).compileComponents(); - }); - beforeEach(() => { store = TestBed.inject(MockStore); fixture = TestBed.createComponent(ReferenceDataDeleteComponent); component = fixture.componentInstance; @@ -44,6 +42,7 @@ describe('ReferenceDataAddComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + describe('navigateBack', () => { it('should clear all errors', () => { jest.spyOn(router, 'navigate').mockImplementation(); diff --git a/src/app/features/reference-data/reference-data-deleted-list/reference-data-deleted-list.component.spec.ts b/src/app/features/reference-data/reference-data-deleted-list/reference-data-deleted-list.component.spec.ts index 8ea4c02b9e..d5b0701df9 100644 --- a/src/app/features/reference-data/reference-data-deleted-list/reference-data-deleted-list.component.spec.ts +++ b/src/app/features/reference-data/reference-data-deleted-list/reference-data-deleted-list.component.spec.ts @@ -31,9 +31,7 @@ describe('DataTypeListComponent', () => { }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(ReferenceDataDeletedListComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/reference-data/reference-data-list/reference-data-list.component.spec.ts b/src/app/features/reference-data/reference-data-list/reference-data-list.component.spec.ts index ca02ef1826..860df181e0 100644 --- a/src/app/features/reference-data/reference-data-list/reference-data-list.component.spec.ts +++ b/src/app/features/reference-data/reference-data-list/reference-data-list.component.spec.ts @@ -34,9 +34,7 @@ describe('DataTypeListComponent', () => { { provide: UserService, useValue: { roles$: of([Roles.ReferenceDataView]) } }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(ReferenceDataListComponent); component = fixture.componentInstance; route = TestBed.inject(ActivatedRoute); diff --git a/src/app/features/reference-data/reference-data-select-type/reference-data-select-type.component.spec.ts b/src/app/features/reference-data/reference-data-select-type/reference-data-select-type.component.spec.ts index b118e4e9e1..ef917d4c39 100644 --- a/src/app/features/reference-data/reference-data-select-type/reference-data-select-type.component.spec.ts +++ b/src/app/features/reference-data/reference-data-select-type/reference-data-select-type.component.spec.ts @@ -32,9 +32,7 @@ describe('ReferenceDataComponent', () => { { provide: UserService, useValue: { roles$: of([Roles.ReferenceDataView]) } }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(ReferenceDataSelectTypeComponent); component = fixture.componentInstance; router = TestBed.inject(Router); diff --git a/src/app/features/search/search.component.spec.ts b/src/app/features/search/search.component.spec.ts index 6949a51442..df2e7e7292 100644 --- a/src/app/features/search/search.component.spec.ts +++ b/src/app/features/search/search.component.spec.ts @@ -28,9 +28,7 @@ describe('SearchComponent', () => { imports: [HttpClientTestingModule, RouterTestingModule], providers: [GlobalErrorService, TechnicalRecordService, provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { store = TestBed.inject(MockStore); store.overrideSelector(globalErrorState, expectedErrors); fixture = TestBed.createComponent(SearchComponent); diff --git a/src/app/features/search/single-search-result/single-search-result.component.spec.ts b/src/app/features/search/single-search-result/single-search-result.component.spec.ts index 8218f51eff..e3bcb15c05 100644 --- a/src/app/features/search/single-search-result/single-search-result.component.spec.ts +++ b/src/app/features/search/single-search-result/single-search-result.component.spec.ts @@ -31,9 +31,7 @@ describe('SingleSearchResultComponent', () => { }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(SingleSearchResultComponent); component = fixture.componentInstance; component.searchResult = { diff --git a/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.spec.ts b/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.spec.ts index 85982abf07..9a42771af8 100644 --- a/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.spec.ts +++ b/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.spec.ts @@ -52,8 +52,7 @@ describe('AdrGenerateCertificateComponent', () => { ], imports: [RouterTestingModule, SharedModule, ReactiveFormsModule, DynamicFormsModule, HttpClientTestingModule], }).compileComponents(); - }); - beforeEach(() => { + fixture = TestBed.createComponent(AdrGenerateCertificateComponent); errorService = TestBed.inject(GlobalErrorService); route = TestBed.inject(ActivatedRoute); diff --git a/src/app/features/tech-record/components/edit-tech-record-button/edit-tech-record-button.component.spec.ts b/src/app/features/tech-record/components/edit-tech-record-button/edit-tech-record-button.component.spec.ts index 1dd1330d5e..4cfcbf93a4 100644 --- a/src/app/features/tech-record/components/edit-tech-record-button/edit-tech-record-button.component.spec.ts +++ b/src/app/features/tech-record/components/edit-tech-record-button/edit-tech-record-button.component.spec.ts @@ -63,9 +63,7 @@ describe('EditTechRecordButtonComponent', () => { ], imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule, SharedModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(EditTechRecordButtonComponent); router = TestBed.inject(Router); store = TestBed.inject(MockStore); diff --git a/src/app/features/tech-record/components/tech-record-amend-reason/tech-record-amend-reason.component.spec.ts b/src/app/features/tech-record/components/tech-record-amend-reason/tech-record-amend-reason.component.spec.ts index 6e219d412d..1e5dc5b42c 100644 --- a/src/app/features/tech-record/components/tech-record-amend-reason/tech-record-amend-reason.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-amend-reason/tech-record-amend-reason.component.spec.ts @@ -28,9 +28,7 @@ describe('TechRecordAmendReasonComponent', () => { route = TestBed.inject(ActivatedRoute); router = TestBed.inject(Router); - }); - beforeEach(() => { fixture = TestBed.createComponent(TechRecordAmendReasonComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/tech-record/components/tech-record-amend-vin/tech-record-amend-vin.component.spec.ts b/src/app/features/tech-record/components/tech-record-amend-vin/tech-record-amend-vin.component.spec.ts index c07c9b74bc..52e09b675a 100644 --- a/src/app/features/tech-record/components/tech-record-amend-vin/tech-record-amend-vin.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-amend-vin/tech-record-amend-vin.component.spec.ts @@ -55,9 +55,7 @@ describe('TechRecordChangeVinComponent', () => { ], imports: [RouterTestingModule, SharedModule, ReactiveFormsModule, DynamicFormsModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(AmendVinComponent); errorService = TestBed.inject(GlobalErrorService); route = TestBed.inject(ActivatedRoute); diff --git a/src/app/features/tech-record/components/tech-record-amend-vrm-reason/tech-record-amend-vrm-reason.component.spec.ts b/src/app/features/tech-record/components/tech-record-amend-vrm-reason/tech-record-amend-vrm-reason.component.spec.ts index 10719b606a..239a207102 100644 --- a/src/app/features/tech-record/components/tech-record-amend-vrm-reason/tech-record-amend-vrm-reason.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-amend-vrm-reason/tech-record-amend-vrm-reason.component.spec.ts @@ -39,9 +39,7 @@ describe('TechRecordChangeVrmComponent', () => { ], imports: [RouterTestingModule, SharedModule, ReactiveFormsModule, DynamicFormsModule, HttpClientTestingModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(AmendVrmReasonComponent); errorService = TestBed.inject(GlobalErrorService); router = TestBed.inject(Router); diff --git a/src/app/features/tech-record/components/tech-record-amend-vrm/tech-record-amend-vrm.component.spec.ts b/src/app/features/tech-record/components/tech-record-amend-vrm/tech-record-amend-vrm.component.spec.ts index 0f25609fce..cb4d8972c2 100644 --- a/src/app/features/tech-record/components/tech-record-amend-vrm/tech-record-amend-vrm.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-amend-vrm/tech-record-amend-vrm.component.spec.ts @@ -64,8 +64,7 @@ describe('TechRecordChangeVrmComponent', () => { ], imports: [RouterTestingModule, SharedModule, ReactiveFormsModule], }).compileComponents(); - }); - beforeEach(() => { + fixture = TestBed.createComponent(AmendVrmComponent); errorService = TestBed.inject(GlobalErrorService); route = TestBed.inject(ActivatedRoute); diff --git a/src/app/features/tech-record/components/tech-record-change-status/tech-record-change-status.component.spec.ts b/src/app/features/tech-record/components/tech-record-change-status/tech-record-change-status.component.spec.ts index ef212aac05..328a682f75 100644 --- a/src/app/features/tech-record/components/tech-record-change-status/tech-record-change-status.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-change-status/tech-record-change-status.component.spec.ts @@ -45,9 +45,7 @@ describe('TechRecordChangeStatusComponent', () => { }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TechRecordChangeStatusComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/tech-record/components/tech-record-change-type/tech-record-change-type.component.spec.ts b/src/app/features/tech-record/components/tech-record-change-type/tech-record-change-type.component.spec.ts index c3294cb4b5..c6323efe8d 100644 --- a/src/app/features/tech-record/components/tech-record-change-type/tech-record-change-type.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-change-type/tech-record-change-type.component.spec.ts @@ -61,9 +61,7 @@ describe('TechRecordChangeTypeComponent', () => { FixNavigationTriggeredOutsideAngularZoneNgModule, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(ChangeVehicleTypeComponent); errorService = TestBed.inject(GlobalErrorService); route = TestBed.inject(ActivatedRoute); diff --git a/src/app/features/tech-record/components/tech-record-change-visibility/tech-record-change-visibility.component.spec.ts b/src/app/features/tech-record/components/tech-record-change-visibility/tech-record-change-visibility.component.spec.ts index 316e40c076..86ea514e87 100644 --- a/src/app/features/tech-record/components/tech-record-change-visibility/tech-record-change-visibility.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-change-visibility/tech-record-change-visibility.component.spec.ts @@ -44,9 +44,7 @@ describe('TechRecordHoldComponent', () => { }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TechRecordChangeVisibilityComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/tech-record/components/tech-record-generate-letter/tech-record-generate-letter.component.spec.ts b/src/app/features/tech-record/components/tech-record-generate-letter/tech-record-generate-letter.component.spec.ts index a93992cbfc..a29d8215b9 100644 --- a/src/app/features/tech-record/components/tech-record-generate-letter/tech-record-generate-letter.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-generate-letter/tech-record-generate-letter.component.spec.ts @@ -67,9 +67,7 @@ describe('TechRecordGenerateLetterComponent', () => { FixNavigationTriggeredOutsideAngularZoneNgModule, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(GenerateLetterComponent); errorService = TestBed.inject(GlobalErrorService); route = TestBed.inject(ActivatedRoute); diff --git a/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.spec.ts b/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.spec.ts index f1de33b1b0..3bc35d08d8 100644 --- a/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.spec.ts @@ -51,9 +51,7 @@ describe('TechRecordGeneratePlateComponent', () => { ], imports: [RouterTestingModule, SharedModule, ReactiveFormsModule, DynamicFormsModule, HttpClientTestingModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(GeneratePlateComponent); errorService = TestBed.inject(GlobalErrorService); route = TestBed.inject(ActivatedRoute); diff --git a/src/app/features/tech-record/components/tech-record-history/tech-record-history.component.spec.ts b/src/app/features/tech-record/components/tech-record-history/tech-record-history.component.spec.ts index e2ce5f0833..55f1881a0b 100644 --- a/src/app/features/tech-record/components/tech-record-history/tech-record-history.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-history/tech-record-history.component.spec.ts @@ -18,14 +18,13 @@ describe('TechRecordHistoryComponent', () => { imports: [HttpClientTestingModule, RouterTestingModule, SharedModule], providers: [TechnicalRecordService, provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TechRecordHistoryComponent); component = fixture.componentInstance; component.currentTechRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel; fixture.detectChanges(); }); + it('should create', () => { expect(component).toBeTruthy(); }); diff --git a/src/app/features/tech-record/components/tech-record-search-tyres/tech-record-search-tyres.component.spec.ts b/src/app/features/tech-record/components/tech-record-search-tyres/tech-record-search-tyres.component.spec.ts index f3a8ec16db..f7b1beaad4 100644 --- a/src/app/features/tech-record/components/tech-record-search-tyres/tech-record-search-tyres.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-search-tyres/tech-record-search-tyres.component.spec.ts @@ -69,9 +69,7 @@ describe('TechRecordSearchTyresComponent', () => { { provide: GlobalErrorService, useValue: mockGlobalErrorService }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TechRecordSearchTyresComponent); router = TestBed.inject(Router); route = TestBed.inject(ActivatedRoute); diff --git a/src/app/features/tech-record/components/tech-record-summary/tech-record-summary.component.spec.ts b/src/app/features/tech-record/components/tech-record-summary/tech-record-summary.component.spec.ts index 247eecb5c4..573193e65f 100644 --- a/src/app/features/tech-record/components/tech-record-summary/tech-record-summary.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-summary/tech-record-summary.component.spec.ts @@ -55,9 +55,7 @@ describe('TechRecordSummaryComponent', () => { }, }) .compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TechRecordSummaryComponent); store = TestBed.inject(MockStore); techRecordService = TestBed.inject(TechnicalRecordService); diff --git a/src/app/features/tech-record/components/tech-record-title/tech-record-title.component.spec.ts b/src/app/features/tech-record/components/tech-record-title/tech-record-title.component.spec.ts index 144aee7562..d0f063e7c8 100644 --- a/src/app/features/tech-record/components/tech-record-title/tech-record-title.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-title/tech-record-title.component.spec.ts @@ -39,9 +39,7 @@ describe('TechRecordTitleComponent', () => { TechnicalRecordService, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TechRecordTitleComponent); store = TestBed.inject(MockStore); component = fixture.componentInstance; diff --git a/src/app/features/tech-record/components/tech-record-unarchive/tech-record-unarchive.component.spec.ts b/src/app/features/tech-record/components/tech-record-unarchive/tech-record-unarchive.component.spec.ts index 9cce85b866..bce7bb897c 100644 --- a/src/app/features/tech-record/components/tech-record-unarchive/tech-record-unarchive.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-unarchive/tech-record-unarchive.component.spec.ts @@ -45,9 +45,7 @@ describe('TechRecordUnarchiveComponent', () => { }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TechRecordUnarchiveComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/tech-record/components/test-record-summary/test-record-summary.component.spec.ts b/src/app/features/tech-record/components/test-record-summary/test-record-summary.component.spec.ts index ac1b4359b5..c8dac0fdf1 100644 --- a/src/app/features/tech-record/components/test-record-summary/test-record-summary.component.spec.ts +++ b/src/app/features/tech-record/components/test-record-summary/test-record-summary.component.spec.ts @@ -17,9 +17,7 @@ describe('TestRecordSummaryComponent', () => { declarations: [TestRecordSummaryComponent], imports: [RouterTestingModule, SharedModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TestRecordSummaryComponent); component = fixture.componentInstance; }); diff --git a/src/app/features/tech-record/components/vehicle-technical-record/vehicle-technical-record.component.spec.ts b/src/app/features/tech-record/components/vehicle-technical-record/vehicle-technical-record.component.spec.ts index 2d4ae4b74b..821f58cead 100644 --- a/src/app/features/tech-record/components/vehicle-technical-record/vehicle-technical-record.component.spec.ts +++ b/src/app/features/tech-record/components/vehicle-technical-record/vehicle-technical-record.component.spec.ts @@ -89,9 +89,7 @@ describe('VehicleTechnicalRecordComponent', () => { }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(VehicleTechnicalRecordComponent); component = fixture.componentInstance; component.techRecord = { systemNumber: 'foo', createdTimestamp: 'bar', vin: 'testVin' } as V3TechRecordModel; diff --git a/src/app/features/tech-record/create-batch/components/batch-vehicle-details/batch-vehicle-details.component.spec.ts b/src/app/features/tech-record/create-batch/components/batch-vehicle-details/batch-vehicle-details.component.spec.ts index 593c04fd5e..bca80321cb 100644 --- a/src/app/features/tech-record/create-batch/components/batch-vehicle-details/batch-vehicle-details.component.spec.ts +++ b/src/app/features/tech-record/create-batch/components/batch-vehicle-details/batch-vehicle-details.component.spec.ts @@ -29,9 +29,7 @@ describe('BatchVehicleDetailsComponent', () => { provideMockStore({ initialState: initialAppState }), ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(BatchVehicleDetailsComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/tech-record/create-batch/components/batch-vehicle-results/batch-vehicle-results.component.spec.ts b/src/app/features/tech-record/create-batch/components/batch-vehicle-results/batch-vehicle-results.component.spec.ts index e0a32f5ab3..249238b288 100644 --- a/src/app/features/tech-record/create-batch/components/batch-vehicle-results/batch-vehicle-results.component.spec.ts +++ b/src/app/features/tech-record/create-batch/components/batch-vehicle-results/batch-vehicle-results.component.spec.ts @@ -17,9 +17,7 @@ describe('BatchVehicleResultsComponent', () => { declarations: [BatchVehicleResultsComponent], providers: [provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(BatchVehicleResultsComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/tech-record/create-batch/components/batch-vehicle-template/batch-vehicle-template.component.spec.ts b/src/app/features/tech-record/create-batch/components/batch-vehicle-template/batch-vehicle-template.component.spec.ts index c2b59435e8..d107fd751e 100644 --- a/src/app/features/tech-record/create-batch/components/batch-vehicle-template/batch-vehicle-template.component.spec.ts +++ b/src/app/features/tech-record/create-batch/components/batch-vehicle-template/batch-vehicle-template.component.spec.ts @@ -65,9 +65,7 @@ describe('BatchVehicleTemplateComponent', () => { { provide: BatchTechnicalRecordService, useValue: mockBatchTechRecordService }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(BatchVehicleTemplateComponent); store = TestBed.inject(MockStore); router = TestBed.inject(Router); diff --git a/src/app/features/tech-record/create/components/hydrate-new-vehicle-record/hydrate-new-vehicle-record.component.spec.ts b/src/app/features/tech-record/create/components/hydrate-new-vehicle-record/hydrate-new-vehicle-record.component.spec.ts index 1eae33542b..8022d3f056 100644 --- a/src/app/features/tech-record/create/components/hydrate-new-vehicle-record/hydrate-new-vehicle-record.component.spec.ts +++ b/src/app/features/tech-record/create/components/hydrate-new-vehicle-record/hydrate-new-vehicle-record.component.spec.ts @@ -38,9 +38,7 @@ describe('HydrateNewVehicleRecordComponent', () => { ], imports: [HttpClientTestingModule, RouterTestingModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HydrateNewVehicleRecordComponent); route = TestBed.inject(ActivatedRoute); errorService = TestBed.inject(GlobalErrorService); diff --git a/src/app/features/tech-record/create/create-tech-record.component.spec.ts b/src/app/features/tech-record/create/create-tech-record.component.spec.ts index 3d7af5f5f1..f8bf7d4282 100644 --- a/src/app/features/tech-record/create/create-tech-record.component.spec.ts +++ b/src/app/features/tech-record/create/create-tech-record.component.spec.ts @@ -32,9 +32,7 @@ describe('CreateNewVehicleRecordComponent', () => { { provide: ActivatedRoute, useValue: { params: of([{ id: 1 }]) } }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(CreateTechRecordComponent); errorService = TestBed.inject(GlobalErrorService); route = TestBed.inject(ActivatedRoute); diff --git a/src/app/features/tech-record/tech-record.component.spec.ts b/src/app/features/tech-record/tech-record.component.spec.ts index ed7b0aa8bf..6045e8e616 100644 --- a/src/app/features/tech-record/tech-record.component.spec.ts +++ b/src/app/features/tech-record/tech-record.component.spec.ts @@ -20,9 +20,7 @@ describe('TechRecordComponent', () => { declarations: [TechRecordComponent], providers: [provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { store = TestBed.inject(MockStore); store.overrideSelector(selectRouteNestedParams, { vin: '123456' }); diff --git a/src/app/features/test-records/amend/components/test-amendment-history/test-amendment-history.component.spec.ts b/src/app/features/test-records/amend/components/test-amendment-history/test-amendment-history.component.spec.ts index 860d107029..f32a8cd239 100644 --- a/src/app/features/test-records/amend/components/test-amendment-history/test-amendment-history.component.spec.ts +++ b/src/app/features/test-records/amend/components/test-amendment-history/test-amendment-history.component.spec.ts @@ -23,9 +23,7 @@ describe('TestAmendmentHistoryComponent', () => { imports: [RouterTestingModule], providers: [provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TestAmendmentHistoryComponent); component = fixture.componentInstance; store = TestBed.inject(MockStore); diff --git a/src/app/features/test-records/amend/views/amend-test/amend-test.component.spec.ts b/src/app/features/test-records/amend/views/amend-test/amend-test.component.spec.ts index fe9413a5fd..ce1ce01051 100644 --- a/src/app/features/test-records/amend/views/amend-test/amend-test.component.spec.ts +++ b/src/app/features/test-records/amend/views/amend-test/amend-test.component.spec.ts @@ -11,9 +11,7 @@ describe('AmendTestComponent', () => { declarations: [AmendTestComponent], imports: [RouterTestingModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(AmendTestComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/test-records/amend/views/amended-test-record/amended-test-record.component.spec.ts b/src/app/features/test-records/amend/views/amended-test-record/amended-test-record.component.spec.ts index 016ac13173..f6bccd6daf 100644 --- a/src/app/features/test-records/amend/views/amended-test-record/amended-test-record.component.spec.ts +++ b/src/app/features/test-records/amend/views/amended-test-record/amended-test-record.component.spec.ts @@ -37,9 +37,7 @@ describe('AmendedTestRecordComponent', () => { }, ], }).compileComponents(); - }); - beforeEach(() => { store = TestBed.inject(MockStore); store.overrideSelector(selectedAmendedTestResultState, mockTestResult()); store.overrideSelector(selectAmendedDefectData, mockDefectList()); diff --git a/src/app/features/test-records/amend/views/confirm-cancellation/confirm-cancellation.component.spec.ts b/src/app/features/test-records/amend/views/confirm-cancellation/confirm-cancellation.component.spec.ts index 06e655e7ad..d47dbe6552 100644 --- a/src/app/features/test-records/amend/views/confirm-cancellation/confirm-cancellation.component.spec.ts +++ b/src/app/features/test-records/amend/views/confirm-cancellation/confirm-cancellation.component.spec.ts @@ -32,9 +32,7 @@ describe('ConfirmCancellationComponent', () => { }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(ConfirmCancellationComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/test-records/amend/views/test-amend-reason/test-amend-reason.component.spec.ts b/src/app/features/test-records/amend/views/test-amend-reason/test-amend-reason.component.spec.ts index edf4e17d4c..2505ddc73d 100644 --- a/src/app/features/test-records/amend/views/test-amend-reason/test-amend-reason.component.spec.ts +++ b/src/app/features/test-records/amend/views/test-amend-reason/test-amend-reason.component.spec.ts @@ -19,9 +19,7 @@ describe('TestAmendReasonComponent', () => { router = TestBed.inject(Router); route = TestBed.inject(ActivatedRoute); - }); - beforeEach(() => { fixture = TestBed.createComponent(TestAmendReasonComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/test-records/amend/views/test-record/test-record.component.spec.ts b/src/app/features/test-records/amend/views/test-record/test-record.component.spec.ts index 421664d132..444eb68fd5 100644 --- a/src/app/features/test-records/amend/views/test-record/test-record.component.spec.ts +++ b/src/app/features/test-records/amend/views/test-record/test-record.component.spec.ts @@ -57,9 +57,7 @@ describe('TestRecordComponent', () => { TechnicalRecordService, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TestRecordComponent); component = fixture.componentInstance; el = fixture.debugElement; diff --git a/src/app/features/test-records/amend/views/test-result-summary/test-result-summary.component.spec.ts b/src/app/features/test-records/amend/views/test-result-summary/test-result-summary.component.spec.ts index bc78d8f21b..6b48aa807e 100644 --- a/src/app/features/test-records/amend/views/test-result-summary/test-result-summary.component.spec.ts +++ b/src/app/features/test-records/amend/views/test-result-summary/test-result-summary.component.spec.ts @@ -27,9 +27,7 @@ describe('TestResultSummaryComponent', () => { RouterService, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TestResultSummaryComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/test-records/amend/views/test-router-outlet/test-router-outlet.component.spec.ts b/src/app/features/test-records/amend/views/test-router-outlet/test-router-outlet.component.spec.ts index d1d8bd0c1c..d426813ccb 100644 --- a/src/app/features/test-records/amend/views/test-router-outlet/test-router-outlet.component.spec.ts +++ b/src/app/features/test-records/amend/views/test-router-outlet/test-router-outlet.component.spec.ts @@ -11,9 +11,7 @@ describe('TestRouterOutletComponent', () => { declarations: [TestRouterOutletComponent], imports: [RouterTestingModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TestRouterOutletComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/test-records/amend/views/test-type-select-wrapper/test-type-select-wrapper.component.spec.ts b/src/app/features/test-records/amend/views/test-type-select-wrapper/test-type-select-wrapper.component.spec.ts index 600dc57755..00e9e28f54 100644 --- a/src/app/features/test-records/amend/views/test-type-select-wrapper/test-type-select-wrapper.component.spec.ts +++ b/src/app/features/test-records/amend/views/test-type-select-wrapper/test-type-select-wrapper.component.spec.ts @@ -25,9 +25,7 @@ describe('TestTypeSelectWrapperComponent', () => { { provide: TestTypesService, useValue: { selectAllTestTypes$: of([]), testTypeIdChanged: () => {} } }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TestTypeSelectWrapperComponent); component = fixture.componentInstance; router = TestBed.inject(Router); diff --git a/src/app/features/test-records/components/base-test-record/base-test-record.component.spec.ts b/src/app/features/test-records/components/base-test-record/base-test-record.component.spec.ts index f4b6bd5bff..6716086e44 100644 --- a/src/app/features/test-records/components/base-test-record/base-test-record.component.spec.ts +++ b/src/app/features/test-records/components/base-test-record/base-test-record.component.spec.ts @@ -52,9 +52,7 @@ describe('BaseTestRecordComponent', () => { }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(BaseTestRecordComponent); component = fixture.componentInstance; component.testResult = { vin: 'ABC002', testTypes: [{ testResult: resultOfTestEnum.fail }] } as TestResultModel; diff --git a/src/app/features/test-records/components/test-type-select/test-type-select.component.spec.ts b/src/app/features/test-records/components/test-type-select/test-type-select.component.spec.ts index 240dea8a36..46aebfeefc 100644 --- a/src/app/features/test-records/components/test-type-select/test-type-select.component.spec.ts +++ b/src/app/features/test-records/components/test-type-select/test-type-select.component.spec.ts @@ -23,9 +23,7 @@ describe('TestTypeSelectComponent', () => { { provide: TestTypesService, useValue: { selectAllTestTypes$: of([]), testTypeIdChanged: () => {} } }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TestTypeSelectComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/test-records/components/vehicle-header/vehicle-header.component.spec.ts b/src/app/features/test-records/components/vehicle-header/vehicle-header.component.spec.ts index 6332718574..903b27d0cf 100644 --- a/src/app/features/test-records/components/vehicle-header/vehicle-header.component.spec.ts +++ b/src/app/features/test-records/components/vehicle-header/vehicle-header.component.spec.ts @@ -32,9 +32,7 @@ describe('VehicleHeaderComponent', () => { { provide: TechnicalRecordService, useValue: mockTechnicalRecordService }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(VehicleHeaderComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/features/test-records/create/views/create-test-record/create-test-record.component.spec.ts b/src/app/features/test-records/create/views/create-test-record/create-test-record.component.spec.ts index 027368c626..a32301571f 100644 --- a/src/app/features/test-records/create/views/create-test-record/create-test-record.component.spec.ts +++ b/src/app/features/test-records/create/views/create-test-record/create-test-record.component.spec.ts @@ -86,9 +86,7 @@ describe('CreateTestRecordComponent', () => { DynamicFormService, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(CreateTestRecordComponent); component = fixture.componentInstance; router = TestBed.inject(Router); diff --git a/src/app/features/test-records/create/views/create-test-type/create-test-type.component.spec.ts b/src/app/features/test-records/create/views/create-test-type/create-test-type.component.spec.ts index 6c41251730..6f050ba9cb 100644 --- a/src/app/features/test-records/create/views/create-test-type/create-test-type.component.spec.ts +++ b/src/app/features/test-records/create/views/create-test-type/create-test-type.component.spec.ts @@ -31,9 +31,7 @@ describe('CreateTestTypeComponent', () => { { provide: TestTypesService, useValue: { selectAllTestTypes$: of([]), testTypeIdChanged: () => {} } }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(CreateTestTypeComponent); techRecordService = TestBed.inject(TechnicalRecordService); component = fixture.componentInstance; diff --git a/src/app/features/test-records/create/views/test-router-outlet/test-router-outlet.component.spec.ts b/src/app/features/test-records/create/views/test-router-outlet/test-router-outlet.component.spec.ts index d1d8bd0c1c..d426813ccb 100644 --- a/src/app/features/test-records/create/views/test-router-outlet/test-router-outlet.component.spec.ts +++ b/src/app/features/test-records/create/views/test-router-outlet/test-router-outlet.component.spec.ts @@ -11,9 +11,7 @@ describe('TestRouterOutletComponent', () => { declarations: [TestRouterOutletComponent], imports: [RouterTestingModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TestRouterOutletComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/forms/components/approval-type/approval-type.component.spec.ts b/src/app/forms/components/approval-type/approval-type.component.spec.ts index b3671be132..b396c639c7 100644 --- a/src/app/forms/components/approval-type/approval-type.component.spec.ts +++ b/src/app/forms/components/approval-type/approval-type.component.spec.ts @@ -48,9 +48,7 @@ describe('ApprovalTypeComponent', () => { imports: [FormsModule, ReactiveFormsModule], providers: [GlobalErrorService, provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HostComponent); component = fixture.componentInstance; }); diff --git a/src/app/forms/components/autocomplete/autocomplete.component.spec.ts b/src/app/forms/components/autocomplete/autocomplete.component.spec.ts index 4cd953f538..c64134b3e1 100644 --- a/src/app/forms/components/autocomplete/autocomplete.component.spec.ts +++ b/src/app/forms/components/autocomplete/autocomplete.component.spec.ts @@ -39,9 +39,7 @@ describe('AutocompleteComponent', () => { declarations: [AutocompleteComponent, HostComponent, FieldErrorMessageComponent], imports: [FormsModule, ReactiveFormsModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HostComponent); component = fixture.componentInstance; autocompleteComponent = fixture.debugElement.query(By.directive(AutocompleteComponent)).componentInstance; diff --git a/src/app/forms/components/base-control/base-control.component.spec.ts b/src/app/forms/components/base-control/base-control.component.spec.ts index ff05f29a77..76e49c10f1 100644 --- a/src/app/forms/components/base-control/base-control.component.spec.ts +++ b/src/app/forms/components/base-control/base-control.component.spec.ts @@ -25,9 +25,7 @@ describe('BaseControlComponent', () => { }) .overrideComponent(BaseControlComponent, { add: { providers: [NG_CONTROL_PROVIDER] } }) .compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(BaseControlComponent); component = fixture.componentInstance; fixture.detectChanges(); @@ -120,14 +118,12 @@ describe('BaseControlComponent', () => { declarations: [BaseControlComponent], imports: [FormsModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(BaseControlComponent); component = fixture.componentInstance; }); - it('shoud throw no control binding error', () => { + it('should throw no control binding error', () => { expect(component).toBeTruthy(); expect(() => fixture.detectChanges()).toThrow(Error); }); diff --git a/src/app/forms/components/checkbox-group/checkbox-group.component.spec.ts b/src/app/forms/components/checkbox-group/checkbox-group.component.spec.ts index 19b676e853..3f4790268e 100644 --- a/src/app/forms/components/checkbox-group/checkbox-group.component.spec.ts +++ b/src/app/forms/components/checkbox-group/checkbox-group.component.spec.ts @@ -36,9 +36,7 @@ describe('CheckboxGroupComponent', () => { declarations: [HostComponent, CheckboxGroupComponent, BaseControlComponent, FieldErrorMessageComponent], imports: [FormsModule, ReactiveFormsModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HostComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/forms/components/checkbox/checkbox.component.spec.ts b/src/app/forms/components/checkbox/checkbox.component.spec.ts index 4ff559b985..de5f050072 100644 --- a/src/app/forms/components/checkbox/checkbox.component.spec.ts +++ b/src/app/forms/components/checkbox/checkbox.component.spec.ts @@ -25,9 +25,7 @@ describe('CheckboxComponent', () => { await TestBed.configureTestingModule({ declarations: [CheckboxComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HostComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/forms/components/contingency-adr-generate-cert/contingency-adr-generate-cert.component.spec.ts b/src/app/forms/components/contingency-adr-generate-cert/contingency-adr-generate-cert.component.spec.ts index 99e8db312e..8cd30a4bdf 100644 --- a/src/app/forms/components/contingency-adr-generate-cert/contingency-adr-generate-cert.component.spec.ts +++ b/src/app/forms/components/contingency-adr-generate-cert/contingency-adr-generate-cert.component.spec.ts @@ -62,8 +62,7 @@ describe('AdrGenerateCertTestComponent', () => { imports: [HttpClientTestingModule], schemas: [CUSTOM_ELEMENTS_SCHEMA], }).compileComponents(); - }); - beforeEach(() => { + fixture = TestBed.createComponent(ContingencyAdrGenerateCertComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/forms/components/date/date.component.spec.ts b/src/app/forms/components/date/date.component.spec.ts index fdc68ba2d5..acd8c2dda0 100644 --- a/src/app/forms/components/date/date.component.spec.ts +++ b/src/app/forms/components/date/date.component.spec.ts @@ -41,9 +41,7 @@ describe('DateComponent', () => { imports: [FormsModule, ReactiveFormsModule], providers: [GlobalErrorService, provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HostComponent); component = fixture.componentInstance; }); diff --git a/src/app/forms/components/date/focus-next.directive.spec.ts b/src/app/forms/components/date/focus-next.directive.spec.ts index f66abf041a..840d7c5a73 100644 --- a/src/app/forms/components/date/focus-next.directive.spec.ts +++ b/src/app/forms/components/date/focus-next.directive.spec.ts @@ -28,9 +28,7 @@ describe('FocusNextDirective', () => { await TestBed.configureTestingModule({ declarations: [TestComponent, FocusNextDirective], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TestComponent); component = fixture.componentInstance; de = fixture.debugElement; diff --git a/src/app/forms/components/defect-select/defect-select.component.spec.ts b/src/app/forms/components/defect-select/defect-select.component.spec.ts index abd44145d2..9c75ffba51 100644 --- a/src/app/forms/components/defect-select/defect-select.component.spec.ts +++ b/src/app/forms/components/defect-select/defect-select.component.spec.ts @@ -44,9 +44,7 @@ describe('DefectSelectComponent', () => { declarations: [DefectSelectComponent], providers: [provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(DefectSelectComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/forms/components/dynamic-form-field/dynamic-form-field.component.spec.ts b/src/app/forms/components/dynamic-form-field/dynamic-form-field.component.spec.ts index 6d2aea4656..b62c239ea7 100644 --- a/src/app/forms/components/dynamic-form-field/dynamic-form-field.component.spec.ts +++ b/src/app/forms/components/dynamic-form-field/dynamic-form-field.component.spec.ts @@ -27,10 +27,8 @@ describe('DynamicFormFieldComponent', () => { { provide: UserService, useValue: {} }, ], }).compileComponents(); - service = TestBed.inject(ReferenceDataService); - }); - beforeEach(() => { + service = TestBed.inject(ReferenceDataService); fixture = TestBed.createComponent(DynamicFormFieldComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/forms/components/dynamic-form-group/dynamic-form-group.component.spec.ts b/src/app/forms/components/dynamic-form-group/dynamic-form-group.component.spec.ts index a13d9dc031..7718819a0b 100644 --- a/src/app/forms/components/dynamic-form-group/dynamic-form-group.component.spec.ts +++ b/src/app/forms/components/dynamic-form-group/dynamic-form-group.component.spec.ts @@ -27,9 +27,7 @@ describe('DynamicFormGroupComponent', () => { { provide: UserService, useValue: {} }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(DynamicFormGroupComponent); component = fixture.componentInstance; // Don't detect changes on the first load as it will prevent change detection diff --git a/src/app/forms/components/field-error-message/field-error-message.component.spec.ts b/src/app/forms/components/field-error-message/field-error-message.component.spec.ts index d5aa120cbc..6880d01487 100644 --- a/src/app/forms/components/field-error-message/field-error-message.component.spec.ts +++ b/src/app/forms/components/field-error-message/field-error-message.component.spec.ts @@ -10,9 +10,7 @@ describe('FieldErrorMessageComponent', () => { await TestBed.configureTestingModule({ declarations: [FieldErrorMessageComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(FieldErrorMessageComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/forms/components/number-input/number-input.component.spec.ts b/src/app/forms/components/number-input/number-input.component.spec.ts index e75b95bb90..cddd3630ca 100644 --- a/src/app/forms/components/number-input/number-input.component.spec.ts +++ b/src/app/forms/components/number-input/number-input.component.spec.ts @@ -35,9 +35,7 @@ describe('NumberInputComponent', () => { ], imports: [FormsModule, ReactiveFormsModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HostComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/forms/components/radio-group/radio-group.component.spec.ts b/src/app/forms/components/radio-group/radio-group.component.spec.ts index bda7a4d031..393adc16e5 100644 --- a/src/app/forms/components/radio-group/radio-group.component.spec.ts +++ b/src/app/forms/components/radio-group/radio-group.component.spec.ts @@ -38,9 +38,7 @@ describe('RadioGroupComponent', () => { imports: [FormsModule, ReactiveFormsModule], providers: [ReferenceDataService, provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HostComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/forms/components/read-only/read-only.component.spec.ts b/src/app/forms/components/read-only/read-only.component.spec.ts index ec72b6c376..062527fda6 100644 --- a/src/app/forms/components/read-only/read-only.component.spec.ts +++ b/src/app/forms/components/read-only/read-only.component.spec.ts @@ -28,9 +28,7 @@ describe('ReadOnlyComponent', () => { declarations: [BaseControlComponent, HostComponent, ReadOnlyComponent], imports: [FormsModule, ReactiveFormsModule, SharedModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HostComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/forms/components/required-standard-select/required-standard-select.component.spec.ts b/src/app/forms/components/required-standard-select/required-standard-select.component.spec.ts index acd4a5827d..e04511592f 100644 --- a/src/app/forms/components/required-standard-select/required-standard-select.component.spec.ts +++ b/src/app/forms/components/required-standard-select/required-standard-select.component.spec.ts @@ -22,9 +22,7 @@ describe('RequiredStandardSelectComponent', () => { declarations: [RequiredStandardSelectComponent], providers: [provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(RequiredStandardSelectComponent); router = TestBed.inject(Router); component = fixture.componentInstance; diff --git a/src/app/forms/components/select/select.component.spec.ts b/src/app/forms/components/select/select.component.spec.ts index 5d599a2047..8a6587c0ab 100644 --- a/src/app/forms/components/select/select.component.spec.ts +++ b/src/app/forms/components/select/select.component.spec.ts @@ -37,9 +37,7 @@ describe('SelectComponent', () => { declarations: [BaseControlComponent, FieldErrorMessageComponent, HostComponent, SelectComponent], imports: [FormsModule, ReactiveFormsModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HostComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/forms/components/suggestive-input/suggestive-input.component.spec.ts b/src/app/forms/components/suggestive-input/suggestive-input.component.spec.ts index ad37755123..9c76309f1b 100644 --- a/src/app/forms/components/suggestive-input/suggestive-input.component.spec.ts +++ b/src/app/forms/components/suggestive-input/suggestive-input.component.spec.ts @@ -35,9 +35,7 @@ describe('SuggestiveInputComponent', () => { declarations: [HostComponent, SuggestiveInputComponent, FieldErrorMessageComponent], imports: [FormsModule, ReactiveFormsModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HostComponent); component = fixture.componentInstance; suggestiveInput = fixture.debugElement.query(By.directive(SuggestiveInputComponent)).componentInstance; diff --git a/src/app/forms/components/switchable-input/switchable-input.component.spec.ts b/src/app/forms/components/switchable-input/switchable-input.component.spec.ts index ee1328e759..aff4f13eef 100644 --- a/src/app/forms/components/switchable-input/switchable-input.component.spec.ts +++ b/src/app/forms/components/switchable-input/switchable-input.component.spec.ts @@ -34,9 +34,7 @@ describe('SwitchableInputComponent', () => { ], imports: [FormsModule, ReactiveFormsModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(SwitchableInputComponent); component = fixture.componentInstance; component.type = FormNodeEditTypes.TEXT; diff --git a/src/app/forms/components/text-area/text-area.component.spec.ts b/src/app/forms/components/text-area/text-area.component.spec.ts index 6bca85037f..0d08c6d89e 100644 --- a/src/app/forms/components/text-area/text-area.component.spec.ts +++ b/src/app/forms/components/text-area/text-area.component.spec.ts @@ -25,9 +25,7 @@ describe('TextAreaComponent', () => { await TestBed.configureTestingModule({ declarations: [TextAreaComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HostComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/forms/components/text-input/text-input.component.spec.ts b/src/app/forms/components/text-input/text-input.component.spec.ts index 8294e04e9f..e9978e12bb 100644 --- a/src/app/forms/components/text-input/text-input.component.spec.ts +++ b/src/app/forms/components/text-input/text-input.component.spec.ts @@ -25,9 +25,7 @@ describe('TextInputComponent', () => { await TestBed.configureTestingModule({ declarations: [TextInputComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HostComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/forms/components/view-combination/view-combination.component.spec.ts b/src/app/forms/components/view-combination/view-combination.component.spec.ts index 9c0238efad..ed76c261c3 100644 --- a/src/app/forms/components/view-combination/view-combination.component.spec.ts +++ b/src/app/forms/components/view-combination/view-combination.component.spec.ts @@ -31,9 +31,7 @@ describe('ViewCombinationComponent', () => { declarations: [ViewCombinationComponent], imports: [SharedModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(ViewCombinationComponent); component = fixture.componentInstance; component.formNode = formNode; diff --git a/src/app/forms/components/view-list-item/view-list-item.component.spec.ts b/src/app/forms/components/view-list-item/view-list-item.component.spec.ts index f60934808b..18a1ede032 100644 --- a/src/app/forms/components/view-list-item/view-list-item.component.spec.ts +++ b/src/app/forms/components/view-list-item/view-list-item.component.spec.ts @@ -25,9 +25,7 @@ describe('ListItemOutputComponent', () => { await TestBed.configureTestingModule({ declarations: [ViewListItemComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(HostComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/forms/custom-sections/abandon-dialog/abandon-dialog.component.spec.ts b/src/app/forms/custom-sections/abandon-dialog/abandon-dialog.component.spec.ts index 266da1ad8d..dde815e528 100644 --- a/src/app/forms/custom-sections/abandon-dialog/abandon-dialog.component.spec.ts +++ b/src/app/forms/custom-sections/abandon-dialog/abandon-dialog.component.spec.ts @@ -23,9 +23,7 @@ describe('AbandonDialogComponent', () => { imports: [DynamicFormsModule, SharedModule, RouterTestingModule, HttpClientTestingModule], providers: [provideMockStore({ initialState: initialAppState }), DynamicFormService], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(AbandonDialogComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/forms/custom-sections/adr-certificate-history/adr-certificate-history.component.spec.ts b/src/app/forms/custom-sections/adr-certificate-history/adr-certificate-history.component.spec.ts index 58ad199b41..1b6e7ad8be 100644 --- a/src/app/forms/custom-sections/adr-certificate-history/adr-certificate-history.component.spec.ts +++ b/src/app/forms/custom-sections/adr-certificate-history/adr-certificate-history.component.spec.ts @@ -26,8 +26,7 @@ describe('TechRecordAdrCertificateHistoryComponent', () => { imports: [RouterTestingModule, HttpClientTestingModule], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - }); - beforeEach(() => { + fixture = TestBed.createComponent(AdrCertificateHistoryComponent); component = fixture.componentInstance; fixture.detectChanges(); @@ -37,6 +36,7 @@ describe('TechRecordAdrCertificateHistoryComponent', () => { router = TestBed.inject(Router); viewportScroller = TestBed.inject(ViewportScroller); }); + it('should create', () => { expect(component).toBeTruthy(); }); diff --git a/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component.spec.ts b/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component.spec.ts index b5788ad7d0..a975359caf 100644 --- a/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component.spec.ts +++ b/src/app/forms/custom-sections/adr-tank-details-subsequent-inspections-edit/adr-tank-details-subsequent-inspections-edit.component.spec.ts @@ -95,9 +95,7 @@ describe('AdrTankDetailsSubsequentInspectionsEditComponent', () => { fixture = TestBed.createComponent(AdrTankDetailsSubsequentInspectionsEditComponent); component = fixture.componentInstance; fixture.detectChanges(); - }); - beforeEach(() => { component.formArray.patchValue([]); }); diff --git a/src/app/forms/custom-sections/body/body.component.spec.ts b/src/app/forms/custom-sections/body/body.component.spec.ts index ebd9fcd41f..ce4d97ffe7 100644 --- a/src/app/forms/custom-sections/body/body.component.spec.ts +++ b/src/app/forms/custom-sections/body/body.component.spec.ts @@ -46,9 +46,7 @@ describe('BodyComponent', () => { multiOptionsService = TestBed.inject(MultiOptionsService); dynamicFormService = TestBed.inject(DynamicFormService); referenceDataService = TestBed.inject(ReferenceDataService); - }); - beforeEach(() => { fixture = TestBed.createComponent(BodyComponent); component = fixture.componentInstance; component.techRecord = { diff --git a/src/app/forms/custom-sections/custom-defect/custom-defect.component.spec.ts b/src/app/forms/custom-sections/custom-defect/custom-defect.component.spec.ts index 919dbbe633..0b02c724a3 100644 --- a/src/app/forms/custom-sections/custom-defect/custom-defect.component.spec.ts +++ b/src/app/forms/custom-sections/custom-defect/custom-defect.component.spec.ts @@ -13,9 +13,7 @@ describe('CustomDefectComponent', () => { declarations: [], imports: [SharedModule, DynamicFormsModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(CustomDefectComponent); component = fixture.componentInstance; }); diff --git a/src/app/forms/custom-sections/custom-defects/custom-defects.component.spec.ts b/src/app/forms/custom-sections/custom-defects/custom-defects.component.spec.ts index 9c8e35ab47..6dd0f29336 100644 --- a/src/app/forms/custom-sections/custom-defects/custom-defects.component.spec.ts +++ b/src/app/forms/custom-sections/custom-defects/custom-defects.component.spec.ts @@ -21,9 +21,7 @@ describe('CustomDefectsComponent', () => { declarations: [CustomDefectsComponent, CustomDefectComponent], providers: [DynamicFormService, provideMockStore({})], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(CustomDefectsComponent); component = fixture.componentInstance; el = fixture.debugElement; diff --git a/src/app/forms/custom-sections/defect/defect.component.spec.ts b/src/app/forms/custom-sections/defect/defect.component.spec.ts index 7278bddcae..63383afad5 100644 --- a/src/app/forms/custom-sections/defect/defect.component.spec.ts +++ b/src/app/forms/custom-sections/defect/defect.component.spec.ts @@ -72,9 +72,7 @@ describe('DefectComponent', () => { router = TestBed.inject(Router); store = TestBed.inject(MockStore); - }); - beforeEach(() => { fixture = TestBed.createComponent(DefectComponent); component = fixture.componentInstance; }); diff --git a/src/app/forms/custom-sections/defects/defects.component.spec.ts b/src/app/forms/custom-sections/defects/defects.component.spec.ts index 57ecf9db38..45b86f99cf 100644 --- a/src/app/forms/custom-sections/defects/defects.component.spec.ts +++ b/src/app/forms/custom-sections/defects/defects.component.spec.ts @@ -32,9 +32,7 @@ describe('DefectsComponent', () => { ], providers: [DynamicFormService, provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(DefectsComponent); component = fixture.componentInstance; el = fixture.debugElement; diff --git a/src/app/forms/custom-sections/dimensions/dimensions.component.spec.ts b/src/app/forms/custom-sections/dimensions/dimensions.component.spec.ts index 3d0817b91b..002fc46777 100644 --- a/src/app/forms/custom-sections/dimensions/dimensions.component.spec.ts +++ b/src/app/forms/custom-sections/dimensions/dimensions.component.spec.ts @@ -19,13 +19,12 @@ describe('DimensionsComponent', () => { imports: [DynamicFormsModule, FormsModule, ReactiveFormsModule, HttpClientTestingModule, RouterTestingModule], providers: [provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(DimensionsComponent); component = fixture.componentInstance; component.techRecord = mockVehicleTechnicalRecord('psv') as TechRecordType<'hgv'>; }); + it('should create', () => { expect(component).toBeTruthy(); }); diff --git a/src/app/forms/custom-sections/letters/letters.component.spec.ts b/src/app/forms/custom-sections/letters/letters.component.spec.ts index 564d15b5ab..80e7ecccd3 100644 --- a/src/app/forms/custom-sections/letters/letters.component.spec.ts +++ b/src/app/forms/custom-sections/letters/letters.component.spec.ts @@ -70,9 +70,7 @@ describe('LettersComponent', () => { }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(LettersComponent); component = fixture.componentInstance; component.techRecord = { diff --git a/src/app/forms/custom-sections/plates/plates.component.spec.ts b/src/app/forms/custom-sections/plates/plates.component.spec.ts index ff51aa45a5..79f9ce80b3 100644 --- a/src/app/forms/custom-sections/plates/plates.component.spec.ts +++ b/src/app/forms/custom-sections/plates/plates.component.spec.ts @@ -60,9 +60,7 @@ describe('PlatesComponent', () => { GlobalErrorService, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(PlatesComponent); component = fixture.componentInstance; router = TestBed.inject(Router); diff --git a/src/app/forms/custom-sections/psv-brakes/psv-brakes.component.spec.ts b/src/app/forms/custom-sections/psv-brakes/psv-brakes.component.spec.ts index 9be07a56a1..3724742f9e 100644 --- a/src/app/forms/custom-sections/psv-brakes/psv-brakes.component.spec.ts +++ b/src/app/forms/custom-sections/psv-brakes/psv-brakes.component.spec.ts @@ -30,9 +30,7 @@ describe('PsvBrakesComponent', () => { { provide: UserService, useValue: {} }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(PsvBrakesComponent); component = fixture.componentInstance; diff --git a/src/app/forms/custom-sections/required-standard/required-standard.component.spec.ts b/src/app/forms/custom-sections/required-standard/required-standard.component.spec.ts index d8b0e9ed9b..1a55399d78 100644 --- a/src/app/forms/custom-sections/required-standard/required-standard.component.spec.ts +++ b/src/app/forms/custom-sections/required-standard/required-standard.component.spec.ts @@ -29,9 +29,7 @@ describe('RequiredStandardComponent', () => { declarations: [RequiredStandardComponent], providers: [DynamicFormService, provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(RequiredStandardComponent); router = TestBed.inject(Router); store = TestBed.inject(MockStore); diff --git a/src/app/forms/custom-sections/required-standards/required-standards.component.spec.ts b/src/app/forms/custom-sections/required-standards/required-standards.component.spec.ts index 74a5ec5554..4b8e340b83 100644 --- a/src/app/forms/custom-sections/required-standards/required-standards.component.spec.ts +++ b/src/app/forms/custom-sections/required-standards/required-standards.component.spec.ts @@ -26,9 +26,7 @@ describe('RequiredStandardsComponent', () => { declarations: [RequiredStandardsComponent, ButtonComponent, TruncatePipe, TagComponent], providers: [DynamicFormService, provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(RequiredStandardsComponent); router = TestBed.inject(Router); component = fixture.componentInstance; diff --git a/src/app/forms/custom-sections/trl-brakes/trl-brakes.component.spec.ts b/src/app/forms/custom-sections/trl-brakes/trl-brakes.component.spec.ts index 9c28fbe1ee..0f303251d3 100644 --- a/src/app/forms/custom-sections/trl-brakes/trl-brakes.component.spec.ts +++ b/src/app/forms/custom-sections/trl-brakes/trl-brakes.component.spec.ts @@ -22,9 +22,7 @@ describe('BrakesComponent', () => { imports: [DynamicFormsModule, HttpClientTestingModule, RouterTestingModule], providers: [provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TrlBrakesComponent); component = fixture.componentInstance; component.vehicleTechRecord = mockVehicleTechnicalRecord('trl') as TechRecordType<'trl'>; diff --git a/src/app/forms/custom-sections/tyres/tyres.component.spec.ts b/src/app/forms/custom-sections/tyres/tyres.component.spec.ts index de9c189164..e76639f330 100644 --- a/src/app/forms/custom-sections/tyres/tyres.component.spec.ts +++ b/src/app/forms/custom-sections/tyres/tyres.component.spec.ts @@ -38,9 +38,7 @@ describe('TyresComponent', () => { { provide: TechnicalRecordService, useValue: mockTechRecordService }, ], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TyresComponent); component = fixture.componentInstance; component.vehicleTechRecord = mockVehicleTechnicalRecord('psv'); @@ -65,35 +63,29 @@ describe('TyresComponent', () => { { axleNumber: 2, parkingBrakeMrk: true, - tyres_tyreSize: '295/80-22.5', tyres_speedCategorySymbol: 'p', tyres_fitmentCode: 'double', tyres_dataTrAxles: 0, tyres_plyRating: 'A', tyres_tyreCode: 456, - weights_kerbWeight: 1, weights_ladenWeight: 2, weights_gbWeight: 3, - // weights_eecWeight: 4, weights_designWeight: 5, }, { axleNumber: 3, parkingBrakeMrk: true, - tyres_tyreSize: '295/80-22.5', tyres_speedCategorySymbol: 'p', tyres_fitmentCode: 'double', tyres_dataTrAxles: 0, tyres_plyRating: 'A', tyres_tyreCode: 456, - weights_kerbWeight: 1, weights_ladenWeight: 2, weights_gbWeight: 3, - // weights_eecWeight: 4, weights_designWeight: 5, }, ]; diff --git a/src/app/forms/custom-sections/weights/weights.component.spec.ts b/src/app/forms/custom-sections/weights/weights.component.spec.ts index 57061faf3d..cfe7bec784 100644 --- a/src/app/forms/custom-sections/weights/weights.component.spec.ts +++ b/src/app/forms/custom-sections/weights/weights.component.spec.ts @@ -21,9 +21,7 @@ describe('WeightsComponent', () => { declarations: [NumberInputComponent, WeightsComponent], providers: [provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(WeightsComponent); store = TestBed.inject(MockStore); component = fixture.componentInstance; diff --git a/src/app/interceptors/error-handling/error-handling.interceptor.spec.ts b/src/app/interceptors/error-handling/error-handling.interceptor.spec.ts index 0177df4752..7973e2eb93 100644 --- a/src/app/interceptors/error-handling/error-handling.interceptor.spec.ts +++ b/src/app/interceptors/error-handling/error-handling.interceptor.spec.ts @@ -42,9 +42,7 @@ describe('ErrorInterceptor', () => { }, ], }); - }); - beforeEach(() => { router = TestBed.inject(Router); http = TestBed.inject(HttpClient); httpController = TestBed.inject(HttpTestingController); diff --git a/src/app/resolvers/defects-taxonomy/defects-taxonomy.resolver.spec.ts b/src/app/resolvers/defects-taxonomy/defects-taxonomy.resolver.spec.ts index 62156ad95a..9a928e90fe 100644 --- a/src/app/resolvers/defects-taxonomy/defects-taxonomy.resolver.spec.ts +++ b/src/app/resolvers/defects-taxonomy/defects-taxonomy.resolver.spec.ts @@ -22,9 +22,7 @@ describe('DefectsTaxonomyResolver', () => { resolver = (...resolverParameters) => TestBed.runInInjectionContext(() => defectsTaxonomyResolver(...resolverParameters)); store = TestBed.inject(MockStore); - }); - beforeEach(() => { testScheduler = new TestScheduler((actual, expected) => { expect(actual).toEqual(expected); }); diff --git a/src/app/resolvers/required-standards/required-standards.resolver.spec.ts b/src/app/resolvers/required-standards/required-standards.resolver.spec.ts index 4f807c3f08..dba9776e90 100644 --- a/src/app/resolvers/required-standards/required-standards.resolver.spec.ts +++ b/src/app/resolvers/required-standards/required-standards.resolver.spec.ts @@ -28,9 +28,7 @@ describe('RequiredStandardsResolver', () => { resolver = (...resolverParameters) => TestBed.runInInjectionContext(() => requiredStandardsResolver(...resolverParameters)); store = TestBed.inject(MockStore); - }); - beforeEach(() => { testScheduler = new TestScheduler((actual, expected) => { expect(actual).toEqual(expected); }); diff --git a/src/app/resolvers/tech-record-view/tech-record-view.resolver.spec.ts b/src/app/resolvers/tech-record-view/tech-record-view.resolver.spec.ts index a9156c8125..62bf0c069d 100644 --- a/src/app/resolvers/tech-record-view/tech-record-view.resolver.spec.ts +++ b/src/app/resolvers/tech-record-view/tech-record-view.resolver.spec.ts @@ -29,9 +29,7 @@ describe('TechRecordViewResolver', () => { store = TestBed.inject(MockStore); resolver = (...resolverParameters) => TestBed.runInInjectionContext(() => techRecordViewResolver(...resolverParameters)); - }); - beforeEach(() => { testScheduler = new TestScheduler((actual, expected) => { expect(actual).toEqual(expected); }); diff --git a/src/app/resolvers/test-result/test-result.resolver.spec.ts b/src/app/resolvers/test-result/test-result.resolver.spec.ts index 1c101820c2..af6ef9c55d 100644 --- a/src/app/resolvers/test-result/test-result.resolver.spec.ts +++ b/src/app/resolvers/test-result/test-result.resolver.spec.ts @@ -34,9 +34,7 @@ describe('TestResultResolver', () => { resolver = (...resolverParameters) => TestBed.runInInjectionContext(() => testResultResolver(...resolverParameters)); store = TestBed.inject(MockStore); - }); - beforeEach(() => { testScheduler = new TestScheduler((actual, expected) => { expect(actual).toEqual(expected); }); diff --git a/src/app/resolvers/test-stations/test-stations.resolver.spec.ts b/src/app/resolvers/test-stations/test-stations.resolver.spec.ts index f76288356f..fca2c7a1ab 100644 --- a/src/app/resolvers/test-stations/test-stations.resolver.spec.ts +++ b/src/app/resolvers/test-stations/test-stations.resolver.spec.ts @@ -22,9 +22,7 @@ describe('TestTypeTaxonomyResolver', () => { store = TestBed.inject(MockStore); resolver = (...resolverParameters) => TestBed.runInInjectionContext(() => testStationsResolver(...resolverParameters)); - }); - beforeEach(() => { testScheduler = new TestScheduler((actual, expected) => { expect(actual).toEqual(expected); }); diff --git a/src/app/resolvers/test-type-taxonomy/test-type-taxonomy.resolver.spec.ts b/src/app/resolvers/test-type-taxonomy/test-type-taxonomy.resolver.spec.ts index 82c4e4208a..4a3a74987b 100644 --- a/src/app/resolvers/test-type-taxonomy/test-type-taxonomy.resolver.spec.ts +++ b/src/app/resolvers/test-type-taxonomy/test-type-taxonomy.resolver.spec.ts @@ -26,9 +26,7 @@ describe('TestTypeTaxonomyResolver', () => { resolver = (...resolverParameters) => TestBed.runInInjectionContext(() => testTypeTaxonomyResolver(...resolverParameters)); store = TestBed.inject(MockStore); - }); - beforeEach(() => { testScheduler = new TestScheduler((actual, expected) => { expect(actual).toEqual(expected); }); diff --git a/src/app/shared/components/accordion-control/accordion-control.component.spec.ts b/src/app/shared/components/accordion-control/accordion-control.component.spec.ts index 981a1f2c20..5c06c1a404 100644 --- a/src/app/shared/components/accordion-control/accordion-control.component.spec.ts +++ b/src/app/shared/components/accordion-control/accordion-control.component.spec.ts @@ -23,9 +23,7 @@ describe('AccordionControlComponent', () => { declarations: [AccordionControlComponent, HostComponent, AccordionComponent], providers: [provideMockStore({ initialState: initialAppState })], }).compileComponents(); - }); - beforeEach(async () => { fixture = TestBed.createComponent(HostComponent); component = fixture.debugElement.query(By.directive(AccordionControlComponent)).componentInstance; fixture.detectChanges(); diff --git a/src/app/shared/components/accordion/accordion.component.spec.ts b/src/app/shared/components/accordion/accordion.component.spec.ts index 2acf7335c9..df2abea996 100644 --- a/src/app/shared/components/accordion/accordion.component.spec.ts +++ b/src/app/shared/components/accordion/accordion.component.spec.ts @@ -21,10 +21,8 @@ describe('AccordionComponent', () => { declarations: [AccordionComponent, HostComponent], providers: [provideMockStore({ initialState: initialAppState })], }).compileComponents(); - store = TestBed.inject(MockStore); - }); - beforeEach(() => { + store = TestBed.inject(MockStore); fixture = TestBed.createComponent(HostComponent); component = fixture.debugElement.query(By.directive(AccordionComponent)).componentInstance; fixture.detectChanges(); diff --git a/src/app/shared/components/banner/banner.component.spec.ts b/src/app/shared/components/banner/banner.component.spec.ts index 865c11ae07..59f4c611c6 100644 --- a/src/app/shared/components/banner/banner.component.spec.ts +++ b/src/app/shared/components/banner/banner.component.spec.ts @@ -10,9 +10,7 @@ describe('BannerComponent', () => { await TestBed.configureTestingModule({ declarations: [BannerComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(BannerComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/shared/components/base-dialog/base-dialog.component.spec.ts b/src/app/shared/components/base-dialog/base-dialog.component.spec.ts index ac5a25b311..7be6d8b970 100644 --- a/src/app/shared/components/base-dialog/base-dialog.component.spec.ts +++ b/src/app/shared/components/base-dialog/base-dialog.component.spec.ts @@ -10,9 +10,7 @@ describe('BaseDialogComponent', () => { await TestBed.configureTestingModule({ declarations: [BaseDialogComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(BaseDialogComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/shared/components/button-group/button-group.component.spec.ts b/src/app/shared/components/button-group/button-group.component.spec.ts index 81fe8fd84d..0bd7f7b2f6 100644 --- a/src/app/shared/components/button-group/button-group.component.spec.ts +++ b/src/app/shared/components/button-group/button-group.component.spec.ts @@ -9,9 +9,7 @@ describe('ButtonGroupComponent', () => { await TestBed.configureTestingModule({ declarations: [ButtonGroupComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(ButtonGroupComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/shared/components/button/button.component.spec.ts b/src/app/shared/components/button/button.component.spec.ts index 413d986027..8a02a153ef 100644 --- a/src/app/shared/components/button/button.component.spec.ts +++ b/src/app/shared/components/button/button.component.spec.ts @@ -11,9 +11,7 @@ describe('ButtonComponent', () => { declarations: [ButtonComponent], imports: [RouterTestingModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(ButtonComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/shared/components/collapsible-text/collapsible-text.component.spec.ts b/src/app/shared/components/collapsible-text/collapsible-text.component.spec.ts index 5a58540798..437a35785f 100644 --- a/src/app/shared/components/collapsible-text/collapsible-text.component.spec.ts +++ b/src/app/shared/components/collapsible-text/collapsible-text.component.spec.ts @@ -9,9 +9,7 @@ describe('CollapsibleTextComponent', () => { await TestBed.configureTestingModule({ declarations: [CollapsibleTextComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(CollapsibleTextComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/shared/components/icon/icon.component.spec.ts b/src/app/shared/components/icon/icon.component.spec.ts index 2a0824d9d1..9e82ba8222 100644 --- a/src/app/shared/components/icon/icon.component.spec.ts +++ b/src/app/shared/components/icon/icon.component.spec.ts @@ -9,9 +9,7 @@ describe('IconComponent', () => { await TestBed.configureTestingModule({ declarations: [IconComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(IconComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/shared/components/input-spinner/input-spinner.component.spec.ts b/src/app/shared/components/input-spinner/input-spinner.component.spec.ts index ae3c9efa91..5a270fbc0c 100644 --- a/src/app/shared/components/input-spinner/input-spinner.component.spec.ts +++ b/src/app/shared/components/input-spinner/input-spinner.component.spec.ts @@ -10,9 +10,7 @@ describe('InputSpinnerComponent', () => { await TestBed.configureTestingModule({ declarations: [InputSpinnerComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(InputSpinnerComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/shared/components/number-plate/number-plate.component.spec.ts b/src/app/shared/components/number-plate/number-plate.component.spec.ts index 4d63f16945..748948d782 100644 --- a/src/app/shared/components/number-plate/number-plate.component.spec.ts +++ b/src/app/shared/components/number-plate/number-plate.component.spec.ts @@ -10,9 +10,7 @@ describe('NumberPlateComponent', () => { await TestBed.configureTestingModule({ declarations: [NumberPlateComponent, DefaultNullOrEmpty], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(NumberPlateComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/shared/components/pagination/pagination.component.spec.ts b/src/app/shared/components/pagination/pagination.component.spec.ts index 87097a9dd4..2cb2309fa4 100644 --- a/src/app/shared/components/pagination/pagination.component.spec.ts +++ b/src/app/shared/components/pagination/pagination.component.spec.ts @@ -35,18 +35,14 @@ describe('PaginationComponent', () => { declarations: [HostComponent, PaginationComponent], imports: [RouterTestingModule.withRoutes([{ path: '', component: PaginationComponent }])], }).compileComponents(); - })); - beforeEach(() => { fixture = TestBed.createComponent(HostComponent); hostComponent = fixture.componentInstance; component = fixture.debugElement.query(By.directive(PaginationComponent)).componentInstance; el = fixture.debugElement; - router = TestBed.inject(Router); - fixture.detectChanges(); - }); + })); it('should create', () => { expect(component).toBeTruthy(); diff --git a/src/app/shared/components/router-outlet/router-outlet.component.spec.ts b/src/app/shared/components/router-outlet/router-outlet.component.spec.ts index 807d44da2d..3b4a45205c 100644 --- a/src/app/shared/components/router-outlet/router-outlet.component.spec.ts +++ b/src/app/shared/components/router-outlet/router-outlet.component.spec.ts @@ -11,9 +11,7 @@ describe('RouterOutletComponent', () => { declarations: [RouterOutletComponent], imports: [RouterTestingModule], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(RouterOutletComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/shared/components/tag/tag.component.spec.ts b/src/app/shared/components/tag/tag.component.spec.ts index 5536e01837..17919fd616 100644 --- a/src/app/shared/components/tag/tag.component.spec.ts +++ b/src/app/shared/components/tag/tag.component.spec.ts @@ -9,9 +9,7 @@ describe('TagComponent', () => { await TestBed.configureTestingModule({ declarations: [TagComponent], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TagComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/src/app/shared/components/test-certificate/test-certificate.component.spec.ts b/src/app/shared/components/test-certificate/test-certificate.component.spec.ts index 9414691733..a32c4e2374 100644 --- a/src/app/shared/components/test-certificate/test-certificate.component.spec.ts +++ b/src/app/shared/components/test-certificate/test-certificate.component.spec.ts @@ -22,9 +22,7 @@ describe('TestCertificateComponent', () => { imports: [HttpClientTestingModule], providers: [DocumentRetrievalService, provideMockStore({ initialState: initialAppState }), FeatureToggleService], }).compileComponents(); - }); - beforeEach(() => { fixture = TestBed.createComponent(TestCertificateComponent); component = fixture.componentInstance; store = TestBed.inject(MockStore); diff --git a/src/app/shared/directives/prevent-double-click/prevent-double-click.directive.spec.ts b/src/app/shared/directives/prevent-double-click/prevent-double-click.directive.spec.ts index d15bbc3b07..117f0683ac 100644 --- a/src/app/shared/directives/prevent-double-click/prevent-double-click.directive.spec.ts +++ b/src/app/shared/directives/prevent-double-click/prevent-double-click.directive.spec.ts @@ -19,13 +19,11 @@ describe('PreventDoubleClickDirective', () => { await TestBed.configureTestingModule({ declarations: [HostComponent, PreventDoubleClickDirective], }).compileComponents(); - })); - beforeEach(() => { fixture = TestBed.createComponent(HostComponent); component = fixture.componentInstance; fixture.detectChanges(); - }); + })); it('should emit clicked once', () => { const emitSpy = jest.spyOn(component.clicked, 'emit'); diff --git a/src/app/store/defects/effects/defects.effects.spec.ts b/src/app/store/defects/effects/defects.effects.spec.ts index c749d5cdc1..00800d2308 100644 --- a/src/app/store/defects/effects/defects.effects.spec.ts +++ b/src/app/store/defects/effects/defects.effects.spec.ts @@ -47,9 +47,7 @@ describe('DefectsEffects', () => { effects = TestBed.inject(DefectsEffects); service = TestBed.inject(DefectsService); - }); - beforeEach(() => { testScheduler = new TestScheduler((actual, expected) => { expect(actual).toEqual(expected); }); diff --git a/src/app/store/reference-data/effects/reference-data.effects.spec.ts b/src/app/store/reference-data/effects/reference-data.effects.spec.ts index 4c9c3adf57..88d2fd8f47 100644 --- a/src/app/store/reference-data/effects/reference-data.effects.spec.ts +++ b/src/app/store/reference-data/effects/reference-data.effects.spec.ts @@ -65,9 +65,7 @@ describe('ReferenceDataEffects', () => { effects = TestBed.inject(ReferenceDataEffects); store = TestBed.inject(MockStore); referenceDataService = TestBed.inject(ReferenceDataService); - }); - beforeEach(() => { testScheduler = new TestScheduler((actual, expected) => { expect(actual).toEqual(expected); }); diff --git a/src/app/store/required-standards/effects/required-standards.effects.spec.ts b/src/app/store/required-standards/effects/required-standards.effects.spec.ts index 1bb68f8bc5..20dd8a0374 100644 --- a/src/app/store/required-standards/effects/required-standards.effects.spec.ts +++ b/src/app/store/required-standards/effects/required-standards.effects.spec.ts @@ -46,9 +46,7 @@ describe('RequiredStandardEffects', () => { effects = TestBed.inject(RequiredStandardsEffects); service = TestBed.inject(RequiredStandardsService); - }); - beforeEach(() => { testScheduler = new TestScheduler((actual, expected) => { expect(actual).toEqual(expected); }); diff --git a/src/app/store/tech-record-search/effects/tech-record-search.effect.spec.ts b/src/app/store/tech-record-search/effects/tech-record-search.effect.spec.ts index c1f5eea4c7..6e51cab35c 100644 --- a/src/app/store/tech-record-search/effects/tech-record-search.effect.spec.ts +++ b/src/app/store/tech-record-search/effects/tech-record-search.effect.spec.ts @@ -45,9 +45,7 @@ describe('DefectsEffects', () => { effects = TestBed.inject(TechSearchResultsEffects); service = TestBed.inject(TechnicalRecordHttpService); - }); - beforeEach(() => { testScheduler = new TestScheduler((actual, expected) => { expect(actual).toEqual(expected); }); diff --git a/src/app/store/technical-records/effects/technical-record-service.effects.spec.ts b/src/app/store/technical-records/effects/technical-record-service.effects.spec.ts index 5a320064f9..b2d3df3d26 100644 --- a/src/app/store/technical-records/effects/technical-record-service.effects.spec.ts +++ b/src/app/store/technical-records/effects/technical-record-service.effects.spec.ts @@ -53,9 +53,7 @@ describe('TechnicalRecordServiceEffects', () => { effects = TestBed.inject(TechnicalRecordServiceEffects); techRecordHttpService = TestBed.inject(TechnicalRecordHttpService); technicalRecordService = TestBed.inject(TechnicalRecordService); - }); - beforeEach(() => { testScheduler = new TestScheduler((actual, expected) => expect(actual).toEqual(expected)); }); diff --git a/src/app/store/test-records/effects/test-records.effects.spec.ts b/src/app/store/test-records/effects/test-records.effects.spec.ts index 2700964336..fdd5185e4d 100644 --- a/src/app/store/test-records/effects/test-records.effects.spec.ts +++ b/src/app/store/test-records/effects/test-records.effects.spec.ts @@ -183,9 +183,7 @@ describe('TestResultsEffects', () => { effects = TestBed.inject(TestResultsEffects); testResultsService = TestBed.inject(TestRecordsService); featureToggleService = TestBed.inject(FeatureToggleService); - }); - beforeEach(() => { testScheduler = new TestScheduler((actual, expected) => { expect(actual).toEqual(expected); }); diff --git a/src/app/store/test-stations/effects/test-stations.effects.spec.ts b/src/app/store/test-stations/effects/test-stations.effects.spec.ts index 70c120781c..44899dc5b6 100644 --- a/src/app/store/test-stations/effects/test-stations.effects.spec.ts +++ b/src/app/store/test-stations/effects/test-stations.effects.spec.ts @@ -47,9 +47,7 @@ describe('TestStationsEffects', () => { effects = TestBed.inject(TestStationsEffects); service = TestBed.inject(TestStationsService); - }); - beforeEach(() => { testScheduler = new TestScheduler((actual, expected) => { expect(actual).toEqual(expected); }); diff --git a/src/app/store/test-types/effects/test-types.effects.spec.ts b/src/app/store/test-types/effects/test-types.effects.spec.ts index 2a197a6e11..865f2981f7 100644 --- a/src/app/store/test-types/effects/test-types.effects.spec.ts +++ b/src/app/store/test-types/effects/test-types.effects.spec.ts @@ -41,9 +41,7 @@ describe('TestResultsEffects', () => { effects = TestBed.inject(TestTypeEffects); testTypesService = TestBed.inject(TestTypesService); - }); - beforeEach(() => { testScheduler = new TestScheduler((actual, expected) => { expect(actual).toEqual(expected); }); From 191981fd1058a01bc0bf748eaa72569ec4f2d073 Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Wed, 14 Aug 2024 16:19:32 +0100 Subject: [PATCH 19/21] chore(linting-1): enable use regex literals --- biome.json | 3 +-- src/app/forms/components/date/focus-next.directive.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/biome.json b/biome.json index 6225cbf794..d4c0e30997 100644 --- a/biome.json +++ b/biome.json @@ -11,8 +11,7 @@ "complexity": { "noForEach": "off", "noUselessConstructor": "off", - "useLiteralKeys": "off", - "useRegexLiterals": "off" + "useLiteralKeys": "off" }, "performance": { "noDelete": "off" diff --git a/src/app/forms/components/date/focus-next.directive.ts b/src/app/forms/components/date/focus-next.directive.ts index c39eb7f9cd..1b59974c6f 100644 --- a/src/app/forms/components/date/focus-next.directive.ts +++ b/src/app/forms/components/date/focus-next.directive.ts @@ -22,7 +22,7 @@ export class FocusNextDirective { } private getNextElement(currentSegment: string, value: string): string | undefined { - let nextEl: string; + let nextEl: string | undefined = undefined; if (value.length === 2) { switch (currentSegment) { From 29c5874b69fcc036c962f4a5cb1ed3788aab3fca Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Thu, 15 Aug 2024 17:12:32 +0100 Subject: [PATCH 20/21] fix(build-1): provider hoisting --- ...adr-generate-certificate.component.spec.ts | 4 ++-- .../tech-record-amend-vrm.component.ts | 7 +++--- ...ch-record-generate-plate.component.spec.ts | 4 ++-- src/app/forms/utils/error-message-map.spec.ts | 8 +++---- src/app/services/loading/loading.service.ts | 6 ++--- .../pagination/pagination.component.spec.ts | 4 ++-- .../store/defects/effects/defects.effects.ts | 10 ++++----- .../effects/reference-data.effects.ts | 12 ++++------ .../effects/required-standards.effects.ts | 10 ++++----- .../effects/tech-record-search.effect.ts | 10 ++++----- .../technical-record-service.effects.ts | 18 +++++++-------- .../effects/test-records.effects.ts | 22 +++++++++---------- .../effects/test-stations.effects.ts | 10 ++++----- .../test-types/effects/test-types.effects.ts | 12 +++++----- 14 files changed, 60 insertions(+), 77 deletions(-) diff --git a/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.spec.ts b/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.spec.ts index 9a42771af8..6c4c6c6602 100644 --- a/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.spec.ts +++ b/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.spec.ts @@ -33,8 +33,8 @@ describe('AdrGenerateCertificateComponent', () => { let store: MockStore; let technicalRecordService: TechnicalRecordService; - beforeEach(async () => { - await TestBed.configureTestingModule({ + beforeEach( () => { + TestBed.configureTestingModule({ declarations: [AdrGenerateCertificateComponent], providers: [ GlobalErrorService, diff --git a/src/app/features/tech-record/components/tech-record-amend-vrm/tech-record-amend-vrm.component.ts b/src/app/features/tech-record/components/tech-record-amend-vrm/tech-record-amend-vrm.component.ts index cc2baedfa3..c670543151 100644 --- a/src/app/features/tech-record/components/tech-record-amend-vrm/tech-record-amend-vrm.component.ts +++ b/src/app/features/tech-record/components/tech-record-amend-vrm/tech-record-amend-vrm.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, OnDestroy, OnInit, Output, QueryList, ViewChildren } from '@angular/core'; +import { Component, EventEmitter, OnDestroy, OnInit, Output, QueryList, ViewChildren, inject } from '@angular/core'; import { FormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { GlobalError } from '@core/components/global-error/global-error.interface'; @@ -30,6 +30,8 @@ export class AmendVrmComponent implements OnDestroy, OnInit { formValidity = false; width: FormNodeWidth = FormNodeWidth.L; + private technicalRecordService = inject(TechnicalRecordService); + cherishedTransferForm = new FormGroup({ currentVrm: new CustomFormControl( { @@ -94,8 +96,7 @@ export class AmendVrmComponent implements OnDestroy, OnInit { private globalErrorService: GlobalErrorService, private route: ActivatedRoute, private router: Router, - private store: Store, - private technicalRecordService: TechnicalRecordService + private store: Store ) {} ngOnInit(): void { diff --git a/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.spec.ts b/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.spec.ts index 3bc35d08d8..d09e9312e7 100644 --- a/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.spec.ts @@ -32,8 +32,8 @@ describe('TechRecordGeneratePlateComponent', () => { let store: MockStore; let technicalRecordService: TechnicalRecordService; - beforeEach(async () => { - await TestBed.configureTestingModule({ + beforeEach( () => { + TestBed.configureTestingModule({ declarations: [GeneratePlateComponent], providers: [ GlobalErrorService, diff --git a/src/app/forms/utils/error-message-map.spec.ts b/src/app/forms/utils/error-message-map.spec.ts index 40ff715e81..b4e4939d8d 100644 --- a/src/app/forms/utils/error-message-map.spec.ts +++ b/src/app/forms/utils/error-message-map.spec.ts @@ -61,11 +61,11 @@ describe('ErrorMessageMap', () => { ], ])('should return "%s" for %s with %o', (expected, key, props) => { if (props) { - // eslint-disable-next-line jest/no-conditional-expect - expect(ErrorMessageMap[`${key}`](...props)).toBe(expected); + // @ts-ignore + expect(ErrorMessageMap[`${key}`](...props)).toBe(expected); } else { - // eslint-disable-next-line jest/no-conditional-expect - expect(ErrorMessageMap[`${key}`]()).toBe(expected); + // @ts-ignore + expect(ErrorMessageMap[`${key}`]()).toBe(expected); } }); }); diff --git a/src/app/services/loading/loading.service.ts b/src/app/services/loading/loading.service.ts index a0a573f442..75514811d4 100644 --- a/src/app/services/loading/loading.service.ts +++ b/src/app/services/loading/loading.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, inject } from '@angular/core'; import { Store, select } from '@ngrx/store'; import { defectsLoadingState } from '@store/defects'; import { referenceDataLoadingState } from '@store/reference-data'; @@ -15,6 +15,8 @@ import { Observable, combineLatest, map } from 'rxjs'; providedIn: 'root', }) export class LoadingService { + private store = inject(Store); + globalLoadingState$: Observable = this.store.pipe(select(getSpinner)); testResultLoadingState$: Observable = this.store.pipe(select(testResultLoadingState)); techRecordsLoadingState$: Observable = this.store.pipe(select(technicalRecordsLoadingState)); @@ -25,8 +27,6 @@ export class LoadingService { techRecordSearchLoadingState$: Observable = this.store.pipe(select(selectTechRecordSearchLoadingState)); requiredStandardsLoadingState$: Observable = this.store.pipe(select(requiredStandardsLoadingState)); - constructor(private store: Store) {} - private get reduceLoadingStates$() { return combineLatest([ this.globalLoadingState$, diff --git a/src/app/shared/components/pagination/pagination.component.spec.ts b/src/app/shared/components/pagination/pagination.component.spec.ts index 2cb2309fa4..00208094c4 100644 --- a/src/app/shared/components/pagination/pagination.component.spec.ts +++ b/src/app/shared/components/pagination/pagination.component.spec.ts @@ -30,8 +30,8 @@ describe('PaginationComponent', () => { let el: DebugElement; let router: Router; - beforeEach(waitForAsync(async () => { - await TestBed.configureTestingModule({ + beforeEach(waitForAsync( () => { + TestBed.configureTestingModule({ declarations: [HostComponent, PaginationComponent], imports: [RouterTestingModule.withRoutes([{ path: '', component: PaginationComponent }])], }).compileComponents(); diff --git a/src/app/store/defects/effects/defects.effects.ts b/src/app/store/defects/effects/defects.effects.ts index 3d8488ac58..3593ffcf44 100644 --- a/src/app/store/defects/effects/defects.effects.ts +++ b/src/app/store/defects/effects/defects.effects.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, inject } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { DefectsService } from '@services/defects/defects.service'; import { catchError, map, mergeMap, of } from 'rxjs'; @@ -13,6 +13,9 @@ import { @Injectable() export class DefectsEffects { + private actions$ = inject(Actions); + private defectsService = inject(DefectsService); + fetchDefects$ = createEffect(() => this.actions$.pipe( ofType(fetchDefects), @@ -36,9 +39,4 @@ export class DefectsEffects { ) ) ); - - constructor( - private actions$: Actions, - private defectsService: DefectsService - ) {} } diff --git a/src/app/store/reference-data/effects/reference-data.effects.ts b/src/app/store/reference-data/effects/reference-data.effects.ts index 0ccc4e06cb..5ed331a6ce 100644 --- a/src/app/store/reference-data/effects/reference-data.effects.ts +++ b/src/app/store/reference-data/effects/reference-data.effects.ts @@ -1,11 +1,10 @@ -import { Injectable } from '@angular/core'; +import { Injectable, inject } from '@angular/core'; import { ReferenceDataApiResponse, ReferenceDataApiResponseWithPagination } from '@api/reference-data'; import { ReferenceDataModelBase, ReferenceDataResourceType } from '@models/reference-data.model'; import { VehicleTypes } from '@models/vehicle-tech-record.model'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { Store, select } from '@ngrx/store'; import { ReferenceDataService } from '@services/reference-data/reference-data.service'; -import { UserService } from '@services/user-service/user-service'; import { State } from '@store/.'; import { testResultInEdit } from '@store/test-records'; import { catchError, map, mergeMap, of, switchMap, take } from 'rxjs'; @@ -40,12 +39,9 @@ import { handleNotFound, sortReferenceData } from './operators'; @Injectable() export class ReferenceDataEffects { - constructor( - private actions$: Actions, - private userService: UserService, - private referenceDataService: ReferenceDataService, - private store: Store - ) {} + private actions$ = inject(Actions); + private referenceDataService = inject(ReferenceDataService); + private store = inject>(Store); fetchReferenceDataByType$ = createEffect(() => this.actions$.pipe( diff --git a/src/app/store/required-standards/effects/required-standards.effects.ts b/src/app/store/required-standards/effects/required-standards.effects.ts index 059dc52168..2ce5ec1ee4 100644 --- a/src/app/store/required-standards/effects/required-standards.effects.ts +++ b/src/app/store/required-standards/effects/required-standards.effects.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, inject } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { RequiredStandardsService } from '@services/required-standards/required-standards.service'; import { catchError, map, mergeMap, of } from 'rxjs'; @@ -10,6 +10,9 @@ import { @Injectable() export class RequiredStandardsEffects { + private actions$ = inject(Actions); + private requiredStandardsService = inject(RequiredStandardsService); + getRequiredStandards$ = createEffect(() => this.actions$.pipe( ofType(getRequiredStandards), @@ -21,9 +24,4 @@ export class RequiredStandardsEffects { ) ) ); - - constructor( - private actions$: Actions, - private requiredStandardsService: RequiredStandardsService - ) {} } diff --git a/src/app/store/tech-record-search/effects/tech-record-search.effect.ts b/src/app/store/tech-record-search/effects/tech-record-search.effect.ts index fa4e716447..8fbe11b69e 100644 --- a/src/app/store/tech-record-search/effects/tech-record-search.effect.ts +++ b/src/app/store/tech-record-search/effects/tech-record-search.effect.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, inject } from '@angular/core'; import { SEARCH_TYPES } from '@models/search-types-enum'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { TechnicalRecordHttpService } from '@services/technical-record-http/technical-record-http.service'; @@ -11,6 +11,9 @@ import { @Injectable() export class TechSearchResultsEffects { + private actions$ = inject(Actions); + private techRecordHttpService = inject(TechnicalRecordHttpService); + fetchSearchResults$ = createEffect(() => this.actions$.pipe( ofType(fetchSearchResult), @@ -47,9 +50,4 @@ export class TechSearchResultsEffects { getTechnicalRecords_404: 'Vehicle not found, check the vehicle registration mark, trailer ID or vehicle identification number', }; - - constructor( - private actions$: Actions, - private techRecordHttpService: TechnicalRecordHttpService - ) {} } diff --git a/src/app/store/technical-records/effects/technical-record-service.effects.ts b/src/app/store/technical-records/effects/technical-record-service.effects.ts index f523055916..1bcaabe101 100644 --- a/src/app/store/technical-records/effects/technical-record-service.effects.ts +++ b/src/app/store/technical-records/effects/technical-record-service.effects.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, inject } from '@angular/core'; import { EUVehicleCategory } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/euVehicleCategory.enum.js'; import { VehicleClassDescription } from '@dvsa/cvs-type-definitions/types/v3/tech-record/enums/vehicleClassDescription.enum.js'; import { TechRecordType } from '@dvsa/cvs-type-definitions/types/v3/tech-record/tech-record-verb'; @@ -62,15 +62,13 @@ import { editingTechRecord, selectTechRecord } from '../selectors/technical-reco @Injectable() export class TechnicalRecordServiceEffects { - constructor( - private actions$: Actions, - private techRecordHttpService: TechnicalRecordHttpService, - private technicalRecordService: TechnicalRecordService, - private batchTechRecordService: BatchTechnicalRecordService, - private userService: UserService, - private store: Store, - private dfs: DynamicFormService - ) {} + private actions$ = inject(Actions); + private techRecordHttpService = inject(TechnicalRecordHttpService); + private technicalRecordService = inject(TechnicalRecordService); + private batchTechRecordService = inject(BatchTechnicalRecordService); + private userService = inject(UserService); + private store = inject>(Store); + private dfs = inject(DynamicFormService); getTechnicalRecordHistory$ = createEffect(() => this.actions$.pipe( diff --git a/src/app/store/test-records/effects/test-records.effects.ts b/src/app/store/test-records/effects/test-records.effects.ts index 19adbbcdad..015400b48e 100644 --- a/src/app/store/test-records/effects/test-records.effects.ts +++ b/src/app/store/test-records/effects/test-records.effects.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, inject } from '@angular/core'; import { Router } from '@angular/router'; import { GlobalError } from '@core/components/global-error/global-error.interface'; import { TEST_TYPES } from '@forms/models/testTypeId.enum'; @@ -50,6 +50,15 @@ import { @Injectable() export class TestResultsEffects { + private actions$ = inject(Actions); + private testRecordsService = inject(TestRecordsService); + private techRecordHttpService = inject(TechnicalRecordHttpService); + private store = inject>(Store); + private router = inject(Router); + private userService = inject(UserService); + private dfs = inject(DynamicFormService); + private featureToggleService = inject(FeatureToggleService); + fetchTestResultsBySystemNumber$ = createEffect(() => this.actions$.pipe( ofType(fetchTestResultsBySystemNumber), @@ -345,15 +354,4 @@ export class TestResultsEffects { ), { dispatch: false } ); - - constructor( - private actions$: Actions, - private testRecordsService: TestRecordsService, - private techRecordHttpService: TechnicalRecordHttpService, - private store: Store, - private router: Router, - private userService: UserService, - private dfs: DynamicFormService, - private featureToggleService: FeatureToggleService - ) {} } diff --git a/src/app/store/test-stations/effects/test-stations.effects.ts b/src/app/store/test-stations/effects/test-stations.effects.ts index c6aef9e6dd..9a7fdf4f51 100644 --- a/src/app/store/test-stations/effects/test-stations.effects.ts +++ b/src/app/store/test-stations/effects/test-stations.effects.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, inject } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { TestStationsService } from '@services/test-stations/test-stations.service'; import { catchError, map, mergeMap, of } from 'rxjs'; @@ -13,6 +13,9 @@ import { @Injectable() export class TestStationsEffects { + private actions$ = inject(Actions); + private testStationsService = inject(TestStationsService); + fetchTestStations$ = createEffect(() => this.actions$.pipe( ofType(fetchTestStations), @@ -36,9 +39,4 @@ export class TestStationsEffects { ) ) ); - - constructor( - private actions$: Actions, - private testStationsService: TestStationsService - ) {} } diff --git a/src/app/store/test-types/effects/test-types.effects.ts b/src/app/store/test-types/effects/test-types.effects.ts index e38d6a64f6..833417aa6d 100644 --- a/src/app/store/test-types/effects/test-types.effects.ts +++ b/src/app/store/test-types/effects/test-types.effects.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, inject } from '@angular/core'; import { Roles } from '@models/roles.enum'; import { TypeOfTest } from '@models/test-results/typeOfTest.enum'; import { Actions, createEffect, ofType } from '@ngrx/effects'; @@ -9,6 +9,10 @@ import { fetchTestTypes, fetchTestTypesFailed, fetchTestTypesSuccess } from '../ @Injectable() export class TestTypeEffects { + private actions$ = inject(Actions); + private testTypeService = inject(TestTypesService); + private userService = inject(UserService); + fetchTestTypeTaxonomy$ = createEffect(() => this.actions$.pipe( ofType(fetchTestTypes), @@ -25,10 +29,4 @@ export class TestTypeEffects { }) ) ); - - constructor( - private actions$: Actions, - private testTypeService: TestTypesService, - private userService: UserService - ) {} } From 634158892971f42ed74fc3bc4e6e11f472cf9de7 Mon Sep 17 00:00:00 2001 From: Matthew Bell <33056264+matthew2564@users.noreply.github.com> Date: Thu, 15 Aug 2024 17:18:05 +0100 Subject: [PATCH 21/21] fix(linting-1): lint fix --- .../adr-generate-certificate.component.spec.ts | 4 ++-- .../tech-record-generate-plate.component.spec.ts | 4 ++-- src/app/forms/utils/error-message-map.spec.ts | 4 ++-- .../shared/components/pagination/pagination.component.spec.ts | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.spec.ts b/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.spec.ts index 6c4c6c6602..bf0550b0f5 100644 --- a/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.spec.ts +++ b/src/app/features/tech-record/components/adr-generate-certificate/adr-generate-certificate.component.spec.ts @@ -33,8 +33,8 @@ describe('AdrGenerateCertificateComponent', () => { let store: MockStore; let technicalRecordService: TechnicalRecordService; - beforeEach( () => { - TestBed.configureTestingModule({ + beforeEach(() => { + TestBed.configureTestingModule({ declarations: [AdrGenerateCertificateComponent], providers: [ GlobalErrorService, diff --git a/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.spec.ts b/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.spec.ts index d09e9312e7..0568590a30 100644 --- a/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.spec.ts +++ b/src/app/features/tech-record/components/tech-record-generate-plate/tech-record-generate-plate.component.spec.ts @@ -32,8 +32,8 @@ describe('TechRecordGeneratePlateComponent', () => { let store: MockStore; let technicalRecordService: TechnicalRecordService; - beforeEach( () => { - TestBed.configureTestingModule({ + beforeEach(() => { + TestBed.configureTestingModule({ declarations: [GeneratePlateComponent], providers: [ GlobalErrorService, diff --git a/src/app/forms/utils/error-message-map.spec.ts b/src/app/forms/utils/error-message-map.spec.ts index b4e4939d8d..2be790f88e 100644 --- a/src/app/forms/utils/error-message-map.spec.ts +++ b/src/app/forms/utils/error-message-map.spec.ts @@ -62,10 +62,10 @@ describe('ErrorMessageMap', () => { ])('should return "%s" for %s with %o', (expected, key, props) => { if (props) { // @ts-ignore - expect(ErrorMessageMap[`${key}`](...props)).toBe(expected); + expect(ErrorMessageMap[`${key}`](...props)).toBe(expected); } else { // @ts-ignore - expect(ErrorMessageMap[`${key}`]()).toBe(expected); + expect(ErrorMessageMap[`${key}`]()).toBe(expected); } }); }); diff --git a/src/app/shared/components/pagination/pagination.component.spec.ts b/src/app/shared/components/pagination/pagination.component.spec.ts index 00208094c4..0e67358f0a 100644 --- a/src/app/shared/components/pagination/pagination.component.spec.ts +++ b/src/app/shared/components/pagination/pagination.component.spec.ts @@ -30,8 +30,8 @@ describe('PaginationComponent', () => { let el: DebugElement; let router: Router; - beforeEach(waitForAsync( () => { - TestBed.configureTestingModule({ + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ declarations: [HostComponent, PaginationComponent], imports: [RouterTestingModule.withRoutes([{ path: '', component: PaginationComponent }])], }).compileComponents();